summaryrefslogtreecommitdiff
path: root/chromium/third_party/dawn/src
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-09-29 16:16:15 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-11-09 10:04:06 +0000
commita95a7417ad456115a1ef2da4bb8320531c0821f1 (patch)
treeedcd59279e486d2fd4a8f88a7ed025bcf925c6e6 /chromium/third_party/dawn/src
parent33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (diff)
downloadqtwebengine-chromium-a95a7417ad456115a1ef2da4bb8320531c0821f1.tar.gz
BASELINE: Update Chromium to 106.0.5249.126
Change-Id: Ib0bb21c437a7d1686e21c33f2d329f2ac425b7ab Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438936 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/dawn/src')
-rw-r--r--chromium/third_party/dawn/src/dawn/BUILD.gn20
-rw-r--r--chromium/third_party/dawn/src/dawn/CMakeLists.txt3
-rw-r--r--chromium/third_party/dawn/src/dawn/common/Assert.cpp34
-rw-r--r--chromium/third_party/dawn/src/dawn/common/BUILD.gn15
-rw-r--r--chromium/third_party/dawn/src/dawn/common/CMakeLists.txt2
-rw-r--r--chromium/third_party/dawn/src/dawn/common/Compiler.h11
-rw-r--r--chromium/third_party/dawn/src/dawn/common/Log.cpp10
-rw-r--r--chromium/third_party/dawn/src/dawn/common/Numeric.h1
-rw-r--r--chromium/third_party/dawn/src/dawn/common/Platform.h158
-rw-r--r--chromium/third_party/dawn/src/dawn/glfw/BUILD.gn51
-rw-r--r--chromium/third_party/dawn/src/dawn/glfw/CMakeLists.txt45
-rw-r--r--chromium/third_party/dawn/src/dawn/glfw/README.md5
-rw-r--r--chromium/third_party/dawn/src/dawn/glfw/utils.cpp85
-rw-r--r--chromium/third_party/dawn/src/dawn/glfw/utils_metal.mm (renamed from chromium/third_party/dawn/src/dawn/utils/GLFWUtils_metal.mm)36
-rw-r--r--chromium/third_party/dawn/src/dawn/gpu_info.json219
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Adapter.cpp28
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Adapter.h3
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.cpp396
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.h55
-rw-r--r--chromium/third_party/dawn/src/dawn/native/BUILD.gn31
-rw-r--r--chromium/third_party/dawn/src/dawn/native/BindGroup.cpp20
-rw-r--r--chromium/third_party/dawn/src/dawn/native/BindGroup.h5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Blob.cpp54
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Blob.h20
-rw-r--r--chromium/third_party/dawn/src/dawn/native/BlobCache.cpp10
-rw-r--r--chromium/third_party/dawn/src/dawn/native/BlobCache.h14
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CMakeLists.txt30
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CacheKey.cpp23
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CacheKey.h186
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CacheRequest.cpp (renamed from chromium/third_party/dawn/src/include/dawn/dawn_wsi.h)13
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CacheRequest.h193
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CacheResult.h77
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CachedObject.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CommandEncoder.cpp154
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CommandEncoder.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CommandValidation.cpp1
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CommandValidation.h6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Commands.cpp4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Commands.h13
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.cpp48
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.h8
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ComputePipeline.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/CopyTextureForBrowserHelper.cpp56
-rw-r--r--chromium/third_party/dawn/src/dawn/native/DawnNative.cpp4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Device.cpp32
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Device.h8
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ExternalTexture.cpp5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ExternalTexture.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Features.cpp68
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Features.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Format.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Format.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/IndirectDrawValidationEncoder.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Instance.cpp37
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Instance.h12
-rw-r--r--chromium/third_party/dawn/src/dawn/native/InternalPipelineStore.h3
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Limits.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Pipeline.cpp8
-rw-r--r--chromium/third_party/dawn/src/dawn/native/QueryHelper.cpp29
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Queue.cpp8
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderBundle.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderBundle.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderBundleEncoder.cpp5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.cpp13
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.h3
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.cpp26
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.h5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderPipeline.cpp52
-rw-r--r--chromium/third_party/dawn/src/dawn/native/RenderPipeline.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Serializable.h74
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ShaderModule.cpp230
-rw-r--r--chromium/third_party/dawn/src/dawn/native/ShaderModule.h34
-rw-r--r--chromium/third_party/dawn/src/dawn/native/SpirvValidation.cpp9
-rw-r--r--chromium/third_party/dawn/src/dawn/native/SpirvValidation.h7
-rw-r--r--chromium/third_party/dawn/src/dawn/native/StreamImplTint.cpp117
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Texture.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Texture.h1
-rw-r--r--chromium/third_party/dawn/src/dawn/native/TintUtils.cpp138
-rw-r--r--chromium/third_party/dawn/src/dawn/native/TintUtils.h22
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Toggles.cpp54
-rw-r--r--chromium/third_party/dawn/src/dawn/native/Toggles.h7
-rw-r--r--chromium/third_party/dawn/src/dawn/native/UsageValidationMode.h (renamed from chromium/third_party/dawn/src/include/dawn/dawn_proc.h)15
-rw-r--r--chromium/third_party/dawn/src/dawn/native/VisitableMembers.h65
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/AdapterD3D12.cpp10
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.cpp12
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.h1
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/CacheKeyD3D12.cpp139
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.cpp140
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/CommandRecordingContext.cpp5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/ComputePipelineD3D12.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Backend.cpp4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.cpp53
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.cpp96
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.h5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp28
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.h6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/RenderPipelineD3D12.cpp31
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp87
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h9
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.cpp765
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.h23
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/StreamImplD3D12.cpp122
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.cpp115
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.h26
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.cpp8
-rw-r--r--chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/BackendMTL.mm120
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/CommandBufferMTL.mm14
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/DeviceMTL.mm10
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/MetalBackend.mm4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.h9
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.mm277
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/TextureMTL.mm10
-rw-r--r--chromium/third_party/dawn/src/dawn/native/metal/UtilsMetal.mm22
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.cpp118
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.cpp56
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/BufferGL.cpp24
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/CommandBufferGL.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/ComputePipelineGL.cpp7
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.cpp81
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.h45
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.cpp135
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.h21
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.cpp43
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.h43
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/GLFormat.cpp1
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/NativeSwapChainImplGL.cpp8
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/OpenGLBackend.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.cpp12
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.h10
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/PipelineGL.cpp46
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/QueueGL.cpp4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/RenderPipelineGL.cpp9
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/SamplerGL.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.cpp244
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.h58
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/TextureGL.cpp31
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/UtilsEGL.cpp75
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/UtilsEGL.h (renamed from chromium/third_party/dawn/src/include/dawn/EnumClassBitmasks.h)19
-rw-r--r--chromium/third_party/dawn/src/dawn/native/opengl/UtilsGL.cpp1
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/BlobSource.cpp (renamed from chromium/third_party/dawn/src/include/dawn/dawn_thread_dispatch_proc.h)18
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/BlobSource.h38
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.cpp47
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.h39
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/Sink.h32
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/Source.h34
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/Stream.cpp61
-rw-r--r--chromium/third_party/dawn/src/dawn/native/stream/Stream.h338
-rw-r--r--chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.cpp5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.h5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/AdapterVk.cpp21
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/BindGroupLayoutVk.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.cpp265
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.h100
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.cpp68
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/CommandRecordingContext.h9
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/ComputePipelineVk.cpp13
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.cpp117
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/ExternalHandle.h3
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.h5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/RenderPipelineVk.cpp33
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.cpp197
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.h35
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/StreamImplVk.cpp339
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.cpp173
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.h30
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.cpp26
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.h1
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.cpp5
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.h1
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreService.h6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceFD.cpp12
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceNull.cpp6
-rw-r--r--chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp13
-rw-r--r--chromium/third_party/dawn/src/dawn/native/webgpu_absl_format.cpp8
-rw-r--r--chromium/third_party/dawn/src/dawn/node/README.md2
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/Converter.cpp333
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/Converter.h11
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/GPUAdapter.cpp55
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/GPUBuffer.cpp15
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.cpp64
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/GPUQuerySet.cpp16
-rw-r--r--chromium/third_party/dawn/src/dawn/node/binding/GPUTexture.cpp49
-rw-r--r--chromium/third_party/dawn/src/dawn/node/interop/Core.h6
-rw-r--r--chromium/third_party/dawn/src/dawn/node/tools/src/cmd/run-cts/main.go11
-rw-r--r--chromium/third_party/dawn/src/dawn/node/utils/Debug.h6
-rw-r--r--chromium/third_party/dawn/src/dawn/platform/DawnPlatform.cpp3
-rw-r--r--chromium/third_party/dawn/src/dawn/samples/BUILD.gn2
-rw-r--r--chromium/third_party/dawn/src/dawn/samples/CMakeLists.txt1
-rw-r--r--chromium/third_party/dawn/src/dawn/samples/ManualSwapChainTest.cpp4
-rw-r--r--chromium/third_party/dawn/src/dawn/samples/SampleUtils.cpp8
-rw-r--r--chromium/third_party/dawn/src/dawn/tests/BUILD.gn32
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/BUILD.gn57
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/BackendBinding.cpp29
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/CMakeLists.txt3
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/GLFWUtils.cpp107
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/GLFWUtils.h42
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/Glfw3Fuchsia.cpp99
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/TestUtils.cpp14
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/TestUtils.h20
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/TextureUtils.cpp56
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/TextureUtils.h15
-rw-r--r--chromium/third_party/dawn/src/dawn/utils/WireHelper.h2
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/BUILD.gn5
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/CMakeLists.txt5
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/ObjectHandle.cpp44
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/ObjectHandle.h49
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/SupportedFeatures.cpp3
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/WireClient.cpp5
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Adapter.cpp16
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Adapter.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Buffer.cpp42
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Buffer.h6
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Client.cpp62
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Client.h39
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Device.cpp60
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Device.h5
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Instance.cpp16
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Instance.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/ObjectAllocator.h108
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.cpp32
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.h33
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.cpp72
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.h51
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/QuerySet.cpp17
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/QuerySet.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Queue.cpp15
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Queue.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.cpp5
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.h4
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Texture.cpp43
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/client/Texture.h5
-rw-r--r--chromium/third_party/dawn/src/dawn/wire/server/ServerInlineMemoryTransferService.cpp2
-rw-r--r--chromium/third_party/dawn/src/dawn_native/BUILD.gn24
-rw-r--r--chromium/third_party/dawn/src/dawn_platform/BUILD.gn21
-rw-r--r--chromium/third_party/dawn/src/dawn_wire/BUILD.gn24
-rw-r--r--chromium/third_party/dawn/src/fuzzers/dawn/BUILD.gn22
-rw-r--r--chromium/third_party/dawn/src/include/README.md4
-rw-r--r--chromium/third_party/dawn/src/include/dawn/webgpu.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn/webgpu_cpp.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_native/D3D12Backend.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_native/DawnNative.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_native/MetalBackend.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_native/NullBackend.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_native/OpenGLBackend.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_native/VulkanBackend.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_native/dawn_native_export.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_platform/DawnPlatform.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_wire/Wire.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_wire/WireClient.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_wire/WireServer.h20
-rw-r--r--chromium/third_party/dawn/src/include/dawn_wire/dawn_wire_export.h20
-rw-r--r--chromium/third_party/dawn/src/include/webgpu/webgpu.h20
-rw-r--r--chromium/third_party/dawn/src/include/webgpu/webgpu_cpp.h20
-rw-r--r--chromium/third_party/dawn/src/tint/BUILD.gn889
-rw-r--r--chromium/third_party/dawn/src/tint/CMakeLists.txt98
-rw-r--r--chromium/third_party/dawn/src/tint/ast/alias.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/alias.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/array.cc19
-rw-r--r--chromium/third_party/dawn/src/tint/ast/array.h12
-rw-r--r--chromium/third_party/dawn/src/tint/ast/array_test.cc30
-rw-r--r--chromium/third_party/dawn/src/tint/ast/assignment_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/assignment_statement.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/ast_type.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/atomic.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/atomic.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/attribute.h14
-rw-r--r--chromium/third_party/dawn/src/tint/ast/binary_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/binary_expression.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/binding_attribute.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/binding_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/binding_attribute_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/bitcast_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/bitcast_expression.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/block_statement.cc9
-rw-r--r--chromium/third_party/dawn/src/tint/ast/block_statement.h14
-rw-r--r--chromium/third_party/dawn/src/tint/ast/block_statement_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/ast/bool.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/bool.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/bool_literal_expression.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/bool_literal_expression.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/break_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/break_statement.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin.cc80
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_attribute.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_attribute.h7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_attribute_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.cc31
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.h13
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value.cc104
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value.cc.tmpl22
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value.h (renamed from chromium/third_party/dawn/src/tint/ast/builtin.h)36
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value.h.tmpl26
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc130
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc.tmpl26
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc122
-rw-r--r--chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc.tmpl27
-rw-r--r--chromium/third_party/dawn/src/tint/ast/call_expression.cc20
-rw-r--r--chromium/third_party/dawn/src/tint/ast/call_expression.h18
-rw-r--r--chromium/third_party/dawn/src/tint/ast/call_expression_test.cc44
-rw-r--r--chromium/third_party/dawn/src/tint/ast/call_statement.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/call_statement.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/call_statement_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/case_statement.cc9
-rw-r--r--chromium/third_party/dawn/src/tint/ast/case_statement.h14
-rw-r--r--chromium/third_party/dawn/src/tint/ast/case_statement_test.cc48
-rw-r--r--chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/const.cc53
-rw-r--r--chromium/third_party/dawn/src/tint/ast/const.h69
-rw-r--r--chromium/third_party/dawn/src/tint/ast/continue_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/continue_statement.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/depth_texture.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/depth_texture.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.cc13
-rw-r--r--chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.h33
-rw-r--r--chromium/third_party/dawn/src/tint/ast/discard_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/discard_statement.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/enable.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/enable.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/expression.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/expression.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension.cc55
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension.cc.tmpl22
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension.h55
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension.h.tmpl32
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension_bench.cc74
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension_bench.cc.tmpl26
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension_test.cc74
-rw-r--r--chromium/third_party/dawn/src/tint/ast/extension_test.cc.tmpl27
-rw-r--r--chromium/third_party/dawn/src/tint/ast/external_texture.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/external_texture.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/f16.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/f16.h5
-rw-r--r--chromium/third_party/dawn/src/tint/ast/f32.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/f32.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/fallthrough_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/fallthrough_statement.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/float_literal_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/float_literal_expression.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/for_loop_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/for_loop_statement.h8
-rw-r--r--chromium/third_party/dawn/src/tint/ast/function.cc11
-rw-r--r--chromium/third_party/dawn/src/tint/ast/function.h24
-rw-r--r--chromium/third_party/dawn/src/tint/ast/function_test.cc74
-rw-r--r--chromium/third_party/dawn/src/tint/ast/group_attribute.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/group_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/group_attribute_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/i32.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/i32.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/id_attribute.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/id_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/id_attribute_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/identifier_expression.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/identifier_expression.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/if_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/if_statement.h2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.h7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/index_accessor_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/index_accessor_expression.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/int_literal_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/int_literal_expression.h5
-rw-r--r--chromium/third_party/dawn/src/tint/ast/internal_attribute.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/internal_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/interpolate_attribute.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/interpolate_attribute.h2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/invariant_attribute.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/invariant_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/let.cc53
-rw-r--r--chromium/third_party/dawn/src/tint/ast/let.h66
-rw-r--r--chromium/third_party/dawn/src/tint/ast/literal_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/literal_expression.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/location_attribute.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/location_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/location_attribute_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/loop_statement.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/loop_statement.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/loop_statement_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/matrix.cc9
-rw-r--r--chromium/third_party/dawn/src/tint/ast/matrix.h8
-rw-r--r--chromium/third_party/dawn/src/tint/ast/matrix_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/member_accessor_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/member_accessor_expression.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/module.cc54
-rw-r--r--chromium/third_party/dawn/src/tint/ast/module.h67
-rw-r--r--chromium/third_party/dawn/src/tint/ast/module_clone_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/ast/module_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/ast/multisampled_texture.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/multisampled_texture.h7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/node.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/node.h7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/node_id.h36
-rw-r--r--chromium/third_party/dawn/src/tint/ast/override.cc58
-rw-r--r--chromium/third_party/dawn/src/tint/ast/override.h75
-rw-r--r--chromium/third_party/dawn/src/tint/ast/override_test.cc (renamed from chromium/third_party/dawn/src/tint/utils/to_const_ptr_vec.h)34
-rw-r--r--chromium/third_party/dawn/src/tint/ast/parameter.cc49
-rw-r--r--chromium/third_party/dawn/src/tint/ast/parameter.h68
-rw-r--r--chromium/third_party/dawn/src/tint/ast/phony_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/phony_expression.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/pointer.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/pointer.h2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/return_statement.cc13
-rw-r--r--chromium/third_party/dawn/src/tint/ast/return_statement.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/sampled_texture.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/ast/sampled_texture.h7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/sampler.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/sampler.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/stage_attribute.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/stage_attribute.h5
-rw-r--r--chromium/third_party/dawn/src/tint/ast/statement.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/statement.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/static_assert.cc40
-rw-r--r--chromium/third_party/dawn/src/tint/ast/static_assert.h50
-rw-r--r--chromium/third_party/dawn/src/tint/ast/static_assert_test.cc66
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class.cc77
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class.cc.tmpl25
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class.h49
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class.h.tmpl37
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc88
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc.tmpl29
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class_test.cc86
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_class_test.cc.tmpl30
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_texture.cc64
-rw-r--r--chromium/third_party/dawn/src/tint/ast/storage_texture.h29
-rw-r--r--chromium/third_party/dawn/src/tint/ast/stride_attribute.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/stride_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/stride_attribute_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct.cc11
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct.h11
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member.h10
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_member_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/ast/struct_test.cc46
-rw-r--r--chromium/third_party/dawn/src/tint/ast/switch_statement.cc9
-rw-r--r--chromium/third_party/dawn/src/tint/ast/switch_statement.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/switch_statement_test.cc33
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format.cc122
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format.cc.tmpl22
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format.h63
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format.h.tmpl26
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc69
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc.tmpl26
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format_test.cc106
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texel_format_test.cc.tmpl27
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texture.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/texture.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/traverse_expressions.h24
-rw-r--r--chromium/third_party/dawn/src/tint/ast/traverse_expressions_test.cc20
-rw-r--r--chromium/third_party/dawn/src/tint/ast/type.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/type_decl.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/type_decl.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/type_name.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/type_name.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/u32.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/u32.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/unary_op_expression.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/unary_op_expression.h6
-rw-r--r--chromium/third_party/dawn/src/tint/ast/var.cc54
-rw-r--r--chromium/third_party/dawn/src/tint/ast/var.h91
-rw-r--r--chromium/third_party/dawn/src/tint/ast/variable.cc42
-rw-r--r--chromium/third_party/dawn/src/tint/ast/variable.h121
-rw-r--r--chromium/third_party/dawn/src/tint/ast/variable_decl_statement.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/ast/variable_decl_statement.h8
-rw-r--r--chromium/third_party/dawn/src/tint/ast/variable_test.cc26
-rw-r--r--chromium/third_party/dawn/src/tint/ast/vector.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/vector.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/vector_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/ast/void.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/ast/void.h3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/while_statement.cc49
-rw-r--r--chromium/third_party/dawn/src/tint/ast/while_statement.h57
-rw-r--r--chromium/third_party/dawn/src/tint/ast/while_statement_test.cc85
-rw-r--r--chromium/third_party/dawn/src/tint/ast/workgroup_attribute.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/ast/workgroup_attribute.h2
-rw-r--r--chromium/third_party/dawn/src/tint/bench/benchmark.h4
-rw-r--r--chromium/third_party/dawn/src/tint/castable.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/castable.h74
-rw-r--r--chromium/third_party/dawn/src/tint/castable_bench.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/clone_context.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/clone_context.h84
-rw-r--r--chromium/third_party/dawn/src/tint/clone_context_test.cc31
-rw-r--r--chromium/third_party/dawn/src/tint/cmd/main.cc289
-rw-r--r--chromium/third_party/dawn/src/tint/demangler.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn6
-rw-r--r--chromium/third_party/dawn/src/tint/inspector/entry_point.h54
-rw-r--r--chromium/third_party/dawn/src/tint/inspector/inspector.cc173
-rw-r--r--chromium/third_party/dawn/src/tint/inspector/inspector.h19
-rw-r--r--chromium/third_party/dawn/src/tint/inspector/inspector_test.cc1421
-rw-r--r--chromium/third_party/dawn/src/tint/inspector/resource_binding.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.cc220
-rw-r--r--chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.h138
-rw-r--r--chromium/third_party/dawn/src/tint/intrinsics.def669
-rw-r--r--chromium/third_party/dawn/src/tint/number.cc270
-rw-r--r--chromium/third_party/dawn/src/tint/number.h240
-rw-r--r--chromium/third_party/dawn/src/tint/number_test.cc508
-rw-r--r--chromium/third_party/dawn/src/tint/program.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/program.h9
-rw-r--r--chromium/third_party/dawn/src/tint/program_builder.cc20
-rw-r--r--chromium/third_party/dawn/src/tint/program_builder.h766
-rw-r--r--chromium/third_party/dawn/src/tint/program_builder_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/program_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/construct.h5
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.h10
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.cc36
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.h4
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/enum_converter_test.cc74
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/function.cc763
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/function.h113
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/function_call_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/function_cfg_test.cc67
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/function_misc_test.cc45
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/function_var_test.cc59
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.cc160
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.h72
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_barrier_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc24
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_handle_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_module_var_test.cc68
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.h20
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_type.cc11
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_type.h9
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/parser_type_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/spirv/usage_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/lexer.cc469
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/lexer.h9
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/lexer_test.cc534
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.cc1919
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.h244
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc74
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_bitwise_expression_test.cc345
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_case_body_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc (renamed from chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_body_stmt_test.cc)20
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_expr_test.cc173
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_literal_test.cc279
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_core_lhs_expression_test.cc93
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc52
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_error_msg_test.cc300
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc38
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc112
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_decl_test.cc34
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_header_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc231
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_decl_test.cc141
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc92
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc32
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_lhs_expression_test.cc138
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc32
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_param_list_test.cc28
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_paren_expression_test.cc (renamed from chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc)10
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc228
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc14
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampler_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statement_test.cc44
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statements_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_class_test.cc17
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc24
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc32
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_body_test.cc24
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc26
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test_helper.h2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc42
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_alias_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_decl_test.cc38
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc142
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc24
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc56
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc13
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc30
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc157
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/parser_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/token.cc34
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/token.h56
-rw-r--r--chromium/third_party/dawn/src/tint/reader/wgsl/token_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/array_accessor_test.cc146
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/assignment_validation_test.cc97
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/atomics_test.cc16
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/atomics_validation_test.cc128
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/attribute_validation_test.cc562
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/builtin_test.cc2374
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/builtin_validation_test.cc126
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/builtins_validation_test.cc734
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/call_test.cc17
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/call_validation_test.cc149
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/compound_assignment_validation_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/compound_statement_test.cc60
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/const_eval.cc879
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/const_eval.h242
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/const_eval_test.cc3507
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/control_block_validation_test.cc14
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl10
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h5
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h.tmpl9
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/dependency_graph.cc122
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/dependency_graph.h2
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/dependency_graph_test.cc363
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/entry_point_validation_test.cc771
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/evaluation_stage_test.cc297
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/function_validation_test.cc425
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/host_shareable_validation_test.cc95
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/increment_decrement_validation_test.cc18
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/inferred_type_test.cc22
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/intrinsic_table.cc327
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/intrinsic_table.h28
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl9744
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl.tmpl42
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/intrinsic_table_test.cc453
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/is_host_shareable_test.cc43
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/is_storeable_test.cc52
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/materialize_test.cc759
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/override_test.cc (renamed from chromium/third_party/dawn/src/tint/resolver/pipeline_overridable_constant_test.cc)68
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/ptr_ref_test.cc26
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/ptr_ref_validation_test.cc20
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/resolver.cc1347
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/resolver.h200
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/resolver_behavior_test.cc65
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/resolver_constants.cc275
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/resolver_constants_test.cc515
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/resolver_test.cc590
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/resolver_test_helper.h33
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/side_effects_test.cc254
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/source_variable_test.cc26
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/static_assert_test.cc110
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/storage_class_layout_validation_test.cc177
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/storage_class_validation_test.cc630
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/struct_layout_test.cc302
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/struct_pipeline_stage_use_test.cc72
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/struct_storage_class_use_test.cc60
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/type_constructor_validation_test.cc1433
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/type_validation_test.cc465
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/uniformity.cc145
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/uniformity_test.cc530
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/validation_test.cc193
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/validator.cc773
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/validator.h102
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/validator_is_storeable_test.cc40
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/var_let_test.cc676
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/var_let_validation_test.cc319
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/variable_test.cc1300
-rw-r--r--chromium/third_party/dawn/src/tint/resolver/variable_validation_test.cc454
-rw-r--r--chromium/third_party/dawn/src/tint/sem/abstract_numeric.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/sem/abstract_numeric.h2
-rw-r--r--chromium/third_party/dawn/src/tint/sem/builtin.cc49
-rw-r--r--chromium/third_party/dawn/src/tint/sem/builtin.h4
-rw-r--r--chromium/third_party/dawn/src/tint/sem/builtin_test.cc1
-rw-r--r--chromium/third_party/dawn/src/tint/sem/builtin_type.cc24
-rw-r--r--chromium/third_party/dawn/src/tint/sem/builtin_type.cc.tmpl11
-rw-r--r--chromium/third_party/dawn/src/tint/sem/builtin_type.h8
-rw-r--r--chromium/third_party/dawn/src/tint/sem/builtin_type.h.tmpl9
-rw-r--r--chromium/third_party/dawn/src/tint/sem/call.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/sem/call.h12
-rw-r--r--chromium/third_party/dawn/src/tint/sem/call_target.cc21
-rw-r--r--chromium/third_party/dawn/src/tint/sem/call_target.h16
-rw-r--r--chromium/third_party/dawn/src/tint/sem/constant.cc92
-rw-r--r--chromium/third_party/dawn/src/tint/sem/constant.h189
-rw-r--r--chromium/third_party/dawn/src/tint/sem/constant_test.cc304
-rw-r--r--chromium/third_party/dawn/src/tint/sem/evaluation_stage.h60
-rw-r--r--chromium/third_party/dawn/src/tint/sem/expression.cc5
-rw-r--r--chromium/third_party/dawn/src/tint/sem/expression.h16
-rw-r--r--chromium/third_party/dawn/src/tint/sem/expression_test.cc24
-rw-r--r--chromium/third_party/dawn/src/tint/sem/f16.h2
-rw-r--r--chromium/third_party/dawn/src/tint/sem/function.cc75
-rw-r--r--chromium/third_party/dawn/src/tint/sem/function.h40
-rw-r--r--chromium/third_party/dawn/src/tint/sem/index_accessor_expression.cc40
-rw-r--r--chromium/third_party/dawn/src/tint/sem/index_accessor_expression.h68
-rw-r--r--chromium/third_party/dawn/src/tint/sem/info.h67
-rw-r--r--chromium/third_party/dawn/src/tint/sem/materialize.cc14
-rw-r--r--chromium/third_party/dawn/src/tint/sem/materialize.h2
-rw-r--r--chromium/third_party/dawn/src/tint/sem/member_accessor_expression.cc31
-rw-r--r--chromium/third_party/dawn/src/tint/sem/member_accessor_expression.h29
-rw-r--r--chromium/third_party/dawn/src/tint/sem/module.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/sem/module.h9
-rw-r--r--chromium/third_party/dawn/src/tint/sem/parameter_usage.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/sem/parameter_usage.cc.tmpl9
-rw-r--r--chromium/third_party/dawn/src/tint/sem/parameter_usage.h4
-rw-r--r--chromium/third_party/dawn/src/tint/sem/parameter_usage.h.tmpl9
-rw-r--r--chromium/third_party/dawn/src/tint/sem/sem_struct_test.cc16
-rw-r--r--chromium/third_party/dawn/src/tint/sem/storage_texture.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/sem/struct.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/sem/struct.h18
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type.cc65
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type.h47
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type_constructor.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type_constructor.h6
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type_conversion.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type_conversion.h3
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type_mappings.h11
-rw-r--r--chromium/third_party/dawn/src/tint/sem/type_test.cc683
-rw-r--r--chromium/third_party/dawn/src/tint/sem/variable.cc26
-rw-r--r--chromium/third_party/dawn/src/tint/sem/variable.h51
-rw-r--r--chromium/third_party/dawn/src/tint/sem/while_statement.cc34
-rw-r--r--chromium/third_party/dawn/src/tint/sem/while_statement.h60
-rw-r--r--chromium/third_party/dawn/src/tint/symbol.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/symbol.h4
-rw-r--r--chromium/third_party/dawn/src/tint/templates/enums.tmpl.inc160
-rw-r--r--chromium/third_party/dawn/src/tint/text/unicode.cc16
-rw-r--r--chromium/third_party/dawn/src/tint/tint.natvis36
-rw-r--r--chromium/third_party/dawn/src/tint/traits.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/add_empty_entry_point.cc5
-rw-r--r--chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.cc23
-rw-r--r--chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.h3
-rw-r--r--chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute_test.cc65
-rw-r--r--chromium/third_party/dawn/src/tint/transform/array_length_from_uniform.cc13
-rw-r--r--chromium/third_party/dawn/src/tint/transform/binding_remapper.cc17
-rw-r--r--chromium/third_party/dawn/src/tint/transform/binding_remapper_test.cc18
-rw-r--r--chromium/third_party/dawn/src/tint/transform/builtin_polyfill.cc184
-rw-r--r--chromium/third_party/dawn/src/tint/transform/builtin_polyfill.h8
-rw-r--r--chromium/third_party/dawn/src/tint/transform/builtin_polyfill_test.cc286
-rw-r--r--chromium/third_party/dawn/src/tint/transform/calculate_array_length.cc73
-rw-r--r--chromium/third_party/dawn/src/tint/transform/calculate_array_length.h3
-rw-r--r--chromium/third_party/dawn/src/tint/transform/calculate_array_length_test.cc60
-rw-r--r--chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io.cc222
-rw-r--r--chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io_test.cc48
-rw-r--r--chromium/third_party/dawn/src/tint/transform/combine_samplers.cc58
-rw-r--r--chromium/third_party/dawn/src/tint/transform/decompose_memory_access.cc402
-rw-r--r--chromium/third_party/dawn/src/tint/transform/decompose_memory_access.h5
-rw-r--r--chromium/third_party/dawn/src/tint/transform/decompose_memory_access_test.cc920
-rw-r--r--chromium/third_party/dawn/src/tint/transform/decompose_strided_array.cc18
-rw-r--r--chromium/third_party/dawn/src/tint/transform/decompose_strided_array_test.cc122
-rw-r--r--chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix.cc31
-rw-r--r--chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix_test.cc170
-rw-r--r--chromium/third_party/dawn/src/tint/transform/disable_uniformity_analysis.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/expand_compound_assignment_test.cc20
-rw-r--r--chromium/third_party/dawn/src/tint/transform/first_index_offset.cc29
-rw-r--r--chromium/third_party/dawn/src/tint/transform/fold_trivial_single_use_lets.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/transform/for_loop_to_loop.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.cc29
-rw-r--r--chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.h3
-rw-r--r--chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/loop_to_for_loop_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/manager.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/transform/manager.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.cc438
-rw-r--r--chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param_test.cc181
-rw-r--r--chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.cc190
-rw-r--r--chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.h9
-rw-r--r--chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture_test.cc163
-rw-r--r--chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.cc16
-rw-r--r--chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.h6
-rw-r--r--chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var.cc81
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var_test.cc625
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.cc109
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.h48
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let_test.cc1256
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.cc66
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl_test.cc81
-rw-r--r--chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch_test.cc54
-rw-r--r--chromium/third_party/dawn/src/tint/transform/remove_phonies.cc140
-rw-r--r--chromium/third_party/dawn/src/tint/transform/remove_phonies.h4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/remove_phonies_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/remove_unreachable_statements.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/renamer.h6
-rw-r--r--chromium/third_party/dawn/src/tint/transform/renamer_test.cc654
-rw-r--r--chromium/third_party/dawn/src/tint/transform/robustness.cc25
-rw-r--r--chromium/third_party/dawn/src/tint/transform/robustness.h4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/robustness_test.cc64
-rw-r--r--chromium/third_party/dawn/src/tint/transform/simplify_pointers.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/transform/simplify_pointers.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/single_entry_point.cc61
-rw-r--r--chromium/third_party/dawn/src/tint/transform/single_entry_point.h4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/single_entry_point_test.cc36
-rw-r--r--chromium/third_party/dawn/src/tint/transform/spirv_atomic.cc302
-rw-r--r--chromium/third_party/dawn/src/tint/transform/spirv_atomic.h85
-rw-r--r--chromium/third_party/dawn/src/tint/transform/spirv_atomic_test.cc1410
-rw-r--r--chromium/third_party/dawn/src/tint/transform/substitute_override.cc96
-rw-r--r--chromium/third_party/dawn/src/tint/transform/substitute_override.h91
-rw-r--r--chromium/third_party/dawn/src/tint/transform/substitute_override_test.cc242
-rw-r--r--chromium/third_party/dawn/src/tint/transform/transform.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/transform_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/unshadow.cc35
-rw-r--r--chromium/third_party/dawn/src/tint/transform/unshadow.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/unshadow_test.cc287
-rw-r--r--chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.cc22
-rw-r--r--chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/unwind_discard_functions_test.cc61
-rw-r--r--chromium/third_party/dawn/src/tint/transform/utils/get_insertion_point_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before.cc106
-rw-r--r--chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before_test.cc92
-rw-r--r--chromium/third_party/dawn/src/tint/transform/var_for_dynamic_index_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.cc34
-rw-r--r--chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.h2
-rw-r--r--chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc51
-rw-r--r--chromium/third_party/dawn/src/tint/transform/vertex_pulling.cc78
-rw-r--r--chromium/third_party/dawn/src/tint/transform/vertex_pulling.h4
-rw-r--r--chromium/third_party/dawn/src/tint/transform/while_to_loop.cc67
-rw-r--r--chromium/third_party/dawn/src/tint/transform/while_to_loop.h (renamed from chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var.h)22
-rw-r--r--chromium/third_party/dawn/src/tint/transform/while_to_loop_test.cc129
-rw-r--r--chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.cc158
-rw-r--r--chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.h88
-rw-r--r--chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs_test.cc422
-rw-r--r--chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.cc41
-rw-r--r--chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.h2
-rw-r--r--chromium/third_party/dawn/src/tint/utils/bitset.h102
-rw-r--r--chromium/third_party/dawn/src/tint/utils/bitset_test.cc119
-rw-r--r--chromium/third_party/dawn/src/tint/utils/block_allocator.h152
-rw-r--r--chromium/third_party/dawn/src/tint/utils/block_allocator_test.cc23
-rw-r--r--chromium/third_party/dawn/src/tint/utils/compiler_macros.h13
-rw-r--r--chromium/third_party/dawn/src/tint/utils/hash.h11
-rw-r--r--chromium/third_party/dawn/src/tint/utils/hash_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/utils/hashmap.h305
-rw-r--r--chromium/third_party/dawn/src/tint/utils/hashmap_test.cc179
-rw-r--r--chromium/third_party/dawn/src/tint/utils/hashset.h508
-rw-r--r--chromium/third_party/dawn/src/tint/utils/hashset_test.cc142
-rw-r--r--chromium/third_party/dawn/src/tint/utils/io/command_posix.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/utils/io/command_windows.cc39
-rw-r--r--chromium/third_party/dawn/src/tint/utils/result.h5
-rw-r--r--chromium/third_party/dawn/src/tint/utils/string.h10
-rw-r--r--chromium/third_party/dawn/src/tint/utils/string_test.cc5
-rw-r--r--chromium/third_party/dawn/src/tint/utils/transform.h67
-rw-r--r--chromium/third_party/dawn/src/tint/utils/transform_test.cc152
-rw-r--r--chromium/third_party/dawn/src/tint/utils/unique_vector.h60
-rw-r--r--chromium/third_party/dawn/src/tint/utils/unique_vector_test.cc117
-rw-r--r--chromium/third_party/dawn/src/tint/utils/vector.h826
-rw-r--r--chromium/third_party/dawn/src/tint/utils/vector_test.cc2069
-rw-r--r--chromium/third_party/dawn/src/tint/val/hlsl.cc102
-rw-r--r--chromium/third_party/dawn/src/tint/val/val.h14
-rw-r--r--chromium/third_party/dawn/src/tint/writer/append_vector.cc48
-rw-r--r--chromium/third_party/dawn/src/tint/writer/append_vector.h5
-rw-r--r--chromium/third_party/dawn/src/tint/writer/append_vector_test.cc92
-rw-r--r--chromium/third_party/dawn/src/tint/writer/flatten_bindings_test.cc53
-rw-r--r--chromium/third_party/dawn/src/tint/writer/float_to_string_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/generate_external_texture_bindings_test.cc25
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.cc825
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.h74
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_array_accessor_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_assign_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_binary_test.cc466
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_test.cc657
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_call_test.cc18
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_case_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_constructor_test.cc222
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_function_test.cc330
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_identifier_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_if_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_import_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_loop_test.cc72
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_member_accessor_test.cc95
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_module_constant_test.cc336
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_return_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_sanitizer_test.cc92
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc22
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_switch_test.cc14
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_test.cc34
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_type_test.cc152
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_unary_op_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc388
-rw-r--r--chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator.h2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.cc692
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.h45
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_assign_test.cc133
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_binary_test.cc339
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_test.cc543
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_call_test.cc18
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_case_test.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_constructor_test.cc215
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_function_test.cc369
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_identifier_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_if_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_import_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_loop_test.cc70
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc100
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_module_constant_test.cc250
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_return_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc122
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_static_assert_test.cc47
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_switch_test.cc6
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_test.cc26
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_type_test.cc139
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_unary_op_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc341
-rw-r--r--chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl.cc652
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl.h38
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_array_accessor_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_binary_test.cc30
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_test.cc677
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_texture_test.cc3
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_call_test.cc21
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_case_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_constructor_test.cc260
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_function_test.cc294
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_import_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_loop_test.cc83
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_member_accessor_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_module_constant_test.cc320
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_return_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_sanitizer_test.cc186
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_static_assert_test.cc54
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_switch_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_test.cc173
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_type_test.cc495
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_unary_op_test.cc17
-rw-r--r--chromium/third_party/dawn/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc441
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder.cc442
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder.h4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_accessor_expression_test.cc1682
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_assign_test.cc18
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_binary_expression_test.cc797
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_test.cc3535
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_texture_test.cc18
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_call_test.cc30
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_constructor_expression_test.cc2618
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_entry_point_test.cc74
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_function_attribute_test.cc70
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_function_test.cc66
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_function_variable_test.cc72
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_global_variable_test.cc318
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_ident_expression_test.cc27
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_if_test.cc39
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_literal_test.cc35
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_loop_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_return_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_static_assert_test.cc54
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_switch_test.cc62
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/builder_type_test.cc181
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/generator_impl.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/operand.h3
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant.h22
-rw-r--r--chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant_test.cc7
-rw-r--r--chromium/third_party/dawn/src/tint/writer/text_generator.cc11
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.cc164
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.h14
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_alias_type_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_assign_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_binary_test.cc4
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_call_test.cc24
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_case_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_cast_test.cc30
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_constructor_test.cc66
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_function_test.cc84
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_global_decl_test.cc66
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_identifier_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_if_test.cc12
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_literal_test.cc212
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_loop_test.cc65
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc8
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_return_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_static_assert_test.cc47
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_switch_test.cc14
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_test.cc2
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_type_test.cc92
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_unary_op_test.cc10
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc301
-rw-r--r--chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_test.cc93
1003 files changed, 73640 insertions, 31437 deletions
diff --git a/chromium/third_party/dawn/src/dawn/BUILD.gn b/chromium/third_party/dawn/src/dawn/BUILD.gn
index 67991adbac9..83e1b40bb2a 100644
--- a/chromium/third_party/dawn/src/dawn/BUILD.gn
+++ b/chromium/third_party/dawn/src/dawn/BUILD.gn
@@ -77,23 +77,3 @@ dawn_json_generator("emscripten_bits_gen") {
"emscripten-bits/library_webgpu_enum_tables.js",
]
}
-
-################################################################################
-# Build target aliases
-# TODO(crbug.com/dawn/1275) - remove these
-################################################################################
-group("dawncpp") {
- public_deps = [ ":cpp" ]
-}
-group("dawncpp_headers") {
- public_deps = [ "${dawn_root}/include/dawn:cpp_headers" ]
-}
-group("dawn_proc") {
- public_deps = [ ":proc" ]
-}
-group("dawn_headers") {
- public_deps = [ "${dawn_root}/include/dawn:headers" ]
-}
-group("dawn_cpp") {
- public_deps = [ ":cpp" ]
-}
diff --git a/chromium/third_party/dawn/src/dawn/CMakeLists.txt b/chromium/third_party/dawn/src/dawn/CMakeLists.txt
index f1f834eea11..73f465fc772 100644
--- a/chromium/third_party/dawn/src/dawn/CMakeLists.txt
+++ b/chromium/third_party/dawn/src/dawn/CMakeLists.txt
@@ -22,6 +22,7 @@ add_subdirectory(native)
add_subdirectory(wire)
# TODO(dawn:269): Remove once the implementation-based swapchains are removed.
add_subdirectory(utils)
+add_subdirectory(glfw)
if (DAWN_BUILD_SAMPLES)
#TODO(dawn:269): Add this once implementation-based swapchains are removed.
@@ -112,6 +113,8 @@ common_compile_options(dawncpp)
target_sources(dawncpp PRIVATE ${DAWNCPP_GEN_SOURCES})
target_link_libraries(dawncpp PUBLIC dawncpp_headers)
+add_library(webgpu_cpp ALIAS dawncpp)
+
###############################################################################
# libdawn_proc
###############################################################################
diff --git a/chromium/third_party/dawn/src/dawn/common/Assert.cpp b/chromium/third_party/dawn/src/dawn/common/Assert.cpp
index 2599e12417f..ecc92dfc837 100644
--- a/chromium/third_party/dawn/src/dawn/common/Assert.cpp
+++ b/chromium/third_party/dawn/src/dawn/common/Assert.cpp
@@ -17,6 +17,38 @@
#include <cstdlib>
#include "dawn/common/Log.h"
+#include "dawn/common/Platform.h"
+
+#if DAWN_COMPILER_IS(CLANG) || DAWN_COMPILER_IS(GCC)
+void BreakPoint() {
+#if DAWN_PLATFORM_IS(X86)
+ __asm__ __volatile__("int $3\n\t");
+#elif DAWN_PLATFORM_IS(ARM32)
+ __asm__ __volatile__("bkpt 0");
+#elif DAWN_PLATFORM_IS(ARM64)
+ __asm__ __volatile__("brk 0");
+#elif DAWN_PLATFORM_IS(RISCV)
+ __asm__ __volatile__("ebreak");
+#elif DAWN_PLATFORM_IS(MIPS)
+ __asm__ __volatile__("break");
+#elif DAWN_PLATFORM_IS(S390) || DAWN_PLATFORM_IS_(S390X)
+ __asm__ __volatile__(".word 0x0001");
+#elif DAWN_PLATFORM_IS(PPC) || DAWN_PLATFORM_IS_(PPC64)
+ __asm__ __volatile__("twge 2,2");
+#else
+#error "Unsupported platform"
+#endif
+}
+
+#elif DAWN_COMPILER_IS(MSVC)
+extern void __cdecl __debugbreak(void);
+void BreakPoint() {
+ __debugbreak();
+}
+
+#else
+#error "Unsupported compiler"
+#endif
void HandleAssertionFailure(const char* file,
const char* function,
@@ -27,6 +59,6 @@ void HandleAssertionFailure(const char* file,
#if defined(DAWN_ABORT_ON_ASSERT)
abort();
#else
- DAWN_BREAKPOINT();
+ BreakPoint();
#endif
}
diff --git a/chromium/third_party/dawn/src/dawn/common/BUILD.gn b/chromium/third_party/dawn/src/dawn/common/BUILD.gn
index a9ecded0c81..ef8400cbff4 100644
--- a/chromium/third_party/dawn/src/dawn/common/BUILD.gn
+++ b/chromium/third_party/dawn/src/dawn/common/BUILD.gn
@@ -185,6 +185,16 @@ dawn_generator("dawn_version_gen") {
"--dawn-dir",
rebase_path("${dawn_root}", root_build_dir),
]
+
+ # We can use the explicit version file if it is generated instead of relying
+ # on the existence of git.
+ if (dawn_version_file != "") {
+ args += [
+ "--version-file",
+ rebase_path(dawn_version_file, root_build_dir),
+ ]
+ }
+
outputs = [ "src/dawn/common/Version_autogen.h" ]
}
@@ -192,7 +202,7 @@ dawn_generator("dawn_gpu_info_gen") {
script = "${dawn_root}/generator/dawn_gpu_info_generator.py"
args = [
"--gpu-info-json",
- rebase_path("${dawn_root}/gpu_info.json", root_build_dir),
+ rebase_path("${dawn_root}/src/dawn/gpu_info.json", root_build_dir),
]
outputs = [
"src/dawn/common/GPUInfo_autogen.h",
@@ -267,6 +277,9 @@ if (is_win || is_linux || is_chromeos || is_mac || is_fuchsia || is_android) {
sources += [ "SystemUtils_mac.mm" ]
}
+ # Note that while this doesn't make `internal_config` a public config of
+ # Dawn libraries because `:common` is only used as a private deps of Dawn
+ # targets, so `internal_config` doesn't leak out of Dawn.
public_configs = [ ":internal_config" ]
deps = [
"${dawn_root}/include/dawn:cpp_headers",
diff --git a/chromium/third_party/dawn/src/dawn/common/CMakeLists.txt b/chromium/third_party/dawn/src/dawn/common/CMakeLists.txt
index 7e1c373146d..a2741d1ad43 100644
--- a/chromium/third_party/dawn/src/dawn/common/CMakeLists.txt
+++ b/chromium/third_party/dawn/src/dawn/common/CMakeLists.txt
@@ -24,7 +24,7 @@ DawnGenerator(
SCRIPT "${Dawn_SOURCE_DIR}/generator/dawn_gpu_info_generator.py"
PRINT_NAME "Dawn GPU info utilities"
ARGS "--gpu-info-json"
- "${Dawn_SOURCE_DIR}/gpu_info.json"
+ "${Dawn_SOURCE_DIR}/src/dawn/gpu_info.json"
RESULT_VARIABLE "DAWN_GPU_INFO_AUTOGEN_SOURCES"
)
diff --git a/chromium/third_party/dawn/src/dawn/common/Compiler.h b/chromium/third_party/dawn/src/dawn/common/Compiler.h
index eb7e6239f15..e55f9696982 100644
--- a/chromium/third_party/dawn/src/dawn/common/Compiler.h
+++ b/chromium/third_party/dawn/src/dawn/common/Compiler.h
@@ -17,7 +17,6 @@
// Defines macros for compiler-specific functionality
// - DAWN_COMPILER_IS(CLANG|GCC|MSVC): Compiler detection
-// - DAWN_BREAKPOINT(): Raises an exception and breaks in the debugger
// - DAWN_BUILTIN_UNREACHABLE(): Hints the compiler that a code path is unreachable
// - DAWN_(UN)?LIKELY(EXPR): Where available, hints the compiler that the expression will be true
// (resp. false) to help it generate code that leads to better branch prediction.
@@ -35,13 +34,6 @@
#define DAWN_COMPILER_IS_GCC 1
#endif
-#if defined(__i386__) || defined(__x86_64__)
-#define DAWN_BREAKPOINT() __asm__ __volatile__("int $3\n\t")
-#else
-// TODO(cwallez@chromium.org): Implement breakpoint on all supported architectures
-#define DAWN_BREAKPOINT()
-#endif
-
#define DAWN_BUILTIN_UNREACHABLE() __builtin_unreachable()
#define DAWN_LIKELY(x) __builtin_expect(!!(x), 1)
#define DAWN_UNLIKELY(x) __builtin_expect(!!(x), 0)
@@ -60,9 +52,6 @@
#elif defined(_MSC_VER)
#define DAWN_COMPILER_IS_MSVC 1
-extern void __cdecl __debugbreak(void);
-#define DAWN_BREAKPOINT() __debugbreak()
-
#define DAWN_BUILTIN_UNREACHABLE() __assume(false)
#define DAWN_DECLARE_UNUSED
diff --git a/chromium/third_party/dawn/src/dawn/common/Log.cpp b/chromium/third_party/dawn/src/dawn/common/Log.cpp
index 5edc40e1319..265d156bffb 100644
--- a/chromium/third_party/dawn/src/dawn/common/Log.cpp
+++ b/chromium/third_party/dawn/src/dawn/common/Log.cpp
@@ -28,6 +28,7 @@ namespace dawn {
namespace {
+#if !defined(DAWN_DISABLE_LOGGING)
const char* SeverityName(LogSeverity severity) {
switch (severity) {
case LogSeverity::Debug:
@@ -43,6 +44,7 @@ const char* SeverityName(LogSeverity severity) {
return "";
}
}
+#endif
#if DAWN_PLATFORM_IS(ANDROID)
android_LogPriority AndroidLogPriority(LogSeverity severity) {
@@ -70,12 +72,15 @@ LogMessage::LogMessage(LogMessage&& other) = default;
LogMessage& LogMessage::operator=(LogMessage&& other) = default;
-LogMessage::~LogMessage() {
#if defined(DAWN_DISABLE_LOGGING)
+LogMessage::~LogMessage() {
+ (void)mSeverity;
// Don't print logs to make fuzzing more efficient. Implemented as
// an early return to avoid warnings about unused member variables.
return;
-#endif
+}
+#else // defined(DAWN_DISABLE_LOGGING)
+LogMessage::~LogMessage() {
std::string fullMessage = mStream.str();
// If this message has been moved, its stream is empty.
@@ -99,6 +104,7 @@ LogMessage::~LogMessage() {
fflush(outputStream);
#endif // DAWN_PLATFORM_IS(ANDROID)
}
+#endif // defined(DAWN_DISABLE_LOGGING)
LogMessage DebugLog() {
return LogMessage(LogSeverity::Debug);
diff --git a/chromium/third_party/dawn/src/dawn/common/Numeric.h b/chromium/third_party/dawn/src/dawn/common/Numeric.h
index 50f6d40ba79..f4b084b4dae 100644
--- a/chromium/third_party/dawn/src/dawn/common/Numeric.h
+++ b/chromium/third_party/dawn/src/dawn/common/Numeric.h
@@ -15,6 +15,7 @@
#ifndef SRC_DAWN_COMMON_NUMERIC_H_
#define SRC_DAWN_COMMON_NUMERIC_H_
+#include <cstdint>
#include <limits>
#include <type_traits>
diff --git a/chromium/third_party/dawn/src/dawn/common/Platform.h b/chromium/third_party/dawn/src/dawn/common/Platform.h
index 2a8643489f7..39d5eb41020 100644
--- a/chromium/third_party/dawn/src/dawn/common/Platform.h
+++ b/chromium/third_party/dawn/src/dawn/common/Platform.h
@@ -15,6 +15,25 @@
#ifndef SRC_DAWN_COMMON_PLATFORM_H_
#define SRC_DAWN_COMMON_PLATFORM_H_
+// Use #if DAWN_PLATFORM_IS(X) for platform specific code.
+// Do not use #ifdef or the naked macro DAWN_PLATFORM_IS_X.
+// This can help avoid common mistakes like not including "Platform.h" and falling into unwanted
+// code block as usage of undefined macro "function" will be blocked by the compiler.
+#define DAWN_PLATFORM_IS(X) (1 == DAWN_PLATFORM_IS_##X)
+
+// Define platform macros for OSes:
+//
+// - WINDOWS
+// - WIN32
+// - WINUWP
+// - POSIX
+// - LINUX
+// - ANDROID
+// - APPLE
+// - IOS
+// - MACOS
+// - FUCHSIA
+// - EMSCRIPTEN
#if defined(_WIN32) || defined(_WIN64)
#include <winapifamily.h>
#define DAWN_PLATFORM_IS_WINDOWS 1
@@ -57,22 +76,81 @@
#error "Unsupported platform."
#endif
-// Distinguish mips32.
-#if defined(__mips__) && (_MIPS_SIM == _ABIO32) && !defined(__mips32__)
-#define __mips32__
+// Define platform macros for CPU architectures:
+//
+// - X86
+// - I386
+// - X86_64
+// - ARM
+// - ARM32
+// - ARM64
+// - RISCV
+// - RISCV32
+// - RISCV64
+// - MIPS
+// - MIPS32
+// - MIPS64
+// - S390
+// - S390X
+// - PPC
+// - PPC64
+#if defined(__i386__) || defined(_M_IX86)
+#define DAWN_PLATFORM_IS_X86 1
+#define DAWN_PLATFORM_IS_I386 1
+#elif defined(__x86_64__) || defined(_M_X64)
+#define DAWN_PLATFORM_IS_X86 1
+#define DAWN_PLATFORM_IS_X86_64 1
+
+#elif defined(__arm__) || defined(_M_ARM)
+#define DAWN_PLATFORM_IS_ARM 1
+#define DAWN_PLATFORM_IS_ARM32 1
+#elif defined(__aarch64__) || defined(_M_ARM64)
+#define DAWN_PLATFORM_IS_ARM 1
+#define DAWN_PLATFORM_IS_ARM64 1
+
+#elif defined(__riscv)
+#define DAWN_PLATFORM_IS_RISCV 1
+#if __riscv_xlen == 32
+#define DAWN_PLATFORM_IS_RISCV32 1
+#else
+#define DAWN_PLATFORM_IS_RISCV64 1
+#endif
+
+#elif defined(__mips__)
+#define DAWN_PLATFORM_IS_MIPS 1
+#if _MIPS_SIM == _ABIO32
+#define DAWN_PLATFORM_IS_MIPS32 1
+#else
+#define DAWN_PLATFORM_IS_MIPS64 1
#endif
-// Distinguish mips64.
-#if defined(__mips__) && (_MIPS_SIM == _ABI64) && !defined(__mips64__)
-#define __mips64__
+#elif defiend(__s390__)
+#define DAWN_PLATFORM_IS_S390 1
+#elif defiend(__s390x__)
+#define DAWN_PLATFORM_IS_S390X 1
+
+#elif defined(__PPC__)
+#define DAWN_PLATFORM_IS_PPC 1
+#elif defined(__PPC64__)
+#define DAWN_PLATFORM_IS_PPC64 1
+
+#else
+#error "Unsupported platform."
#endif
-#if defined(_WIN64) || defined(__aarch64__) || defined(__x86_64__) || defined(__mips64__) || \
- defined(__s390x__) || defined(__PPC64__)
+// Define platform macros for pointer width:
+//
+// - 64_BIT
+// - 32_BIT
+#if defined(DAWN_PLATFORM_IS_X86_64) || defined(DAWN_PLATFORM_IS_ARM64) || \
+ defined(DAWN_PLATFORM_IS_RISCV64) || defined(DAWN_PLATFORM_IS_MIPS64) || \
+ defined(DAWN_PLATFORM_IS_S390X) || defined(DAWN_PLATFORM_IS_PPC64)
#define DAWN_PLATFORM_IS_64_BIT 1
static_assert(sizeof(sizeof(char)) == 8, "Expect sizeof(size_t) == 8");
-#elif defined(_WIN32) || defined(__arm__) || defined(__i386__) || defined(__mips32__) || \
- defined(__s390__) || defined(__EMSCRIPTEN__)
+#elif defined(DAWN_PLATFORM_IS_I386) || defined(DAWN_PLATFORM_IS_ARM32) || \
+ defined(DAWN_PLATFORM_IS_RISCV32) || defined(DAWN_PLATFORM_IS_MIPS32) || \
+ defined(DAWN_PLATFORM_IS_S390) || defined(DAWN_PLATFORM_IS_PPC32) || \
+ defined(DAWN_PLATFORM_IS_EMSCRIPTEN)
#define DAWN_PLATFORM_IS_32_BIT 1
static_assert(sizeof(sizeof(char)) == 4, "Expect sizeof(size_t) == 4");
#else
@@ -118,6 +196,60 @@ static_assert(sizeof(sizeof(char)) == 4, "Expect sizeof(size_t) == 4");
#define DAWN_PLATFORM_IS_EMSCRIPTEN 0
#endif
+#if !defined(DAWN_PLATFORM_IS_X86)
+#define DAWN_PLATFORM_IS_X86 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_I386)
+#define DAWN_PLATFORM_IS_I386 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_X86_64)
+#define DAWN_PLATFORM_IS_X86_64 0
+#endif
+
+#if !defined(DAWN_PLATFORM_IS_ARM)
+#define DAWN_PLATFORM_IS_ARM 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_ARM32)
+#define DAWN_PLATFORM_IS_ARM32 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_ARM64)
+#define DAWN_PLATFORM_IS_ARM64 0
+#endif
+
+#if !defined(DAWN_PLATFORM_IS_RISCV)
+#define DAWN_PLATFORM_IS_RISCV 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_RISCV32)
+#define DAWN_PLATFORM_IS_RISCV32 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_RISCV64)
+#define DAWN_PLATFORM_IS_RISCV64 0
+#endif
+
+#if !defined(DAWN_PLATFORM_IS_MIPS)
+#define DAWN_PLATFORM_IS_MIPS 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_MIPS32)
+#define DAWN_PLATFORM_IS_MIPS32 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_MIPS64)
+#define DAWN_PLATFORM_IS_MIPS64 0
+#endif
+
+#if !defined(DAWN_PLATFORM_IS_S390)
+#define DAWN_PLATFORM_IS_S390 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_S390X)
+#define DAWN_PLATFORM_IS_S390X 0
+#endif
+
+#if !defined(DAWN_PLATFORM_IS_PPC)
+#define DAWN_PLATFORM_IS_PPC 0
+#endif
+#if !defined(DAWN_PLATFORM_IS_PPC64)
+#define DAWN_PLATFORM_IS_PPC64 0
+#endif
+
#if !defined(DAWN_PLATFORM_IS_64_BIT)
#define DAWN_PLATFORM_IS_64_BIT 0
#endif
@@ -125,10 +257,4 @@ static_assert(sizeof(sizeof(char)) == 4, "Expect sizeof(size_t) == 4");
#define DAWN_PLATFORM_IS_32_BIT 0
#endif
-// Use #if DAWN_PLATFORM_IS(XXX) for platform specific code.
-// Do not use #ifdef or the naked macro DAWN_PLATFORM_IS_XXX.
-// This can help avoid common mistakes like not including "Platform.h" and falling into unwanted
-// code block as usage of undefined macro "function" will be blocked by the compiler.
-#define DAWN_PLATFORM_IS(X) (1 == DAWN_PLATFORM_IS_##X)
-
#endif // SRC_DAWN_COMMON_PLATFORM_H_
diff --git a/chromium/third_party/dawn/src/dawn/glfw/BUILD.gn b/chromium/third_party/dawn/src/dawn/glfw/BUILD.gn
new file mode 100644
index 00000000000..4c7c82595f4
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/glfw/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright 2022 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../../scripts/dawn_overrides_with_defaults.gni")
+
+import("${dawn_root}/scripts/dawn_component.gni")
+import("${dawn_root}/scripts/dawn_features.gni")
+
+###############################################################################
+# GLFW utils
+###############################################################################
+
+if (dawn_supports_glfw_for_windowing) {
+ static_library("glfw") {
+ defines = [ "WGPU_GLFW_IMPLEMENTATION" ]
+
+ sources = [ "utils.cpp" ]
+ deps = [
+ "${dawn_root}/src/dawn:cpp",
+ "${dawn_root}/src/dawn:proc",
+ "${dawn_root}/src/dawn/common",
+ ]
+
+ if (dawn_enable_metal) {
+ sources += [ "utils_metal.mm" ]
+ frameworks = [
+ "Metal.framework",
+ "QuartzCore.framework",
+ ]
+ }
+
+ public_deps = [
+ "${dawn_root}/include/dawn:cpp_headers",
+ "${dawn_root}/third_party/gn/glfw",
+ ]
+ }
+} else {
+ group("glfw") {
+ }
+}
diff --git a/chromium/third_party/dawn/src/dawn/glfw/CMakeLists.txt b/chromium/third_party/dawn/src/dawn/glfw/CMakeLists.txt
new file mode 100644
index 00000000000..74062a35837
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/glfw/CMakeLists.txt
@@ -0,0 +1,45 @@
+# Copyright 2022 The Dawn Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if(DAWN_SUPPORTS_GLFW_FOR_WINDOWING)
+
+add_library(dawn_glfw STATIC ${DAWN_PLACEHOLDER_FILE})
+common_compile_options(dawn_glfw)
+target_sources(dawn_glfw PRIVATE
+ "utils.cpp"
+)
+target_link_libraries(dawn_glfw
+ PUBLIC
+ glfw
+ dawncpp_headers
+ dawn_common
+ PRIVATE
+ dawn_internal_config
+)
+
+target_compile_definitions(dawn_glfw PRIVATE "WGPU_IMPLEMENTATION")
+if(BUILD_SHARED_LIBS)
+ target_compile_definitions(dawn_glfw PRIVATE "WGPU_SHARED_LIBRARY")
+endif()
+
+if (DAWN_ENABLE_METAL)
+ target_link_libraries(dawn_glfw PRIVATE "-framework Metal")
+ target_sources(dawn_glfw PRIVATE
+ "utils_metal.mm"
+ )
+endif()
+
+add_library(webgpu_glfw ALIAS dawn_glfw)
+
+endif()
diff --git a/chromium/third_party/dawn/src/dawn/glfw/README.md b/chromium/third_party/dawn/src/dawn/glfw/README.md
new file mode 100644
index 00000000000..f38624c54bd
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/glfw/README.md
@@ -0,0 +1,5 @@
+In order to use Dawn WebGPU implementation with GLFW there is some
+boilerplate code needed in order to create the WebGPU surface. This repo
+contains an implementation of that boilerplate which can be used by
+downstream applications. It can also serve as an example of how to
+integrate Dawn and GLFW if there is desire to not use this helper.
diff --git a/chromium/third_party/dawn/src/dawn/glfw/utils.cpp b/chromium/third_party/dawn/src/dawn/glfw/utils.cpp
new file mode 100644
index 00000000000..0ae95ff5891
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/glfw/utils.cpp
@@ -0,0 +1,85 @@
+// Copyright 2020 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstdlib>
+#include <memory>
+#include <utility>
+
+#include "GLFW/glfw3.h"
+#include "dawn/common/Platform.h"
+#include "webgpu/webgpu_glfw.h"
+
+#if DAWN_PLATFORM_IS(WINDOWS)
+#define GLFW_EXPOSE_NATIVE_WIN32
+#endif
+#if defined(DAWN_USE_X11)
+#define GLFW_EXPOSE_NATIVE_X11
+#endif
+#if defined(DAWN_USE_WAYLAND)
+#define GLFW_EXPOSE_NATIVE_WAYLAND
+#endif
+#include "GLFW/glfw3native.h"
+
+namespace wgpu::glfw {
+
+wgpu::Surface CreateSurfaceForWindow(const wgpu::Instance& instance, GLFWwindow* window) {
+ std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
+ SetupWindowAndGetSurfaceDescriptor(window);
+
+ wgpu::SurfaceDescriptor descriptor;
+ descriptor.nextInChain = chainedDescriptor.get();
+ wgpu::Surface surface = instance.CreateSurface(&descriptor);
+
+ return surface;
+}
+
+// SetupWindowAndGetSurfaceDescriptorCocoa defined in GLFWUtils_metal.mm
+std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(GLFWwindow* window);
+
+std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window) {
+#if DAWN_PLATFORM_IS(WINDOWS)
+ std::unique_ptr<wgpu::SurfaceDescriptorFromWindowsHWND> desc =
+ std::make_unique<wgpu::SurfaceDescriptorFromWindowsHWND>();
+ desc->hwnd = glfwGetWin32Window(window);
+ desc->hinstance = GetModuleHandle(nullptr);
+ return std::move(desc);
+#elif defined(DAWN_ENABLE_BACKEND_METAL)
+ return SetupWindowAndGetSurfaceDescriptorCocoa(window);
+#elif defined(DAWN_USE_WAYLAND) || defined(DAWN_USE_X11)
+#if defined(GLFW_PLATFORM_WAYLAND) && defined(DAWN_USE_WAYLAND)
+ if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
+ std::unique_ptr<wgpu::SurfaceDescriptorFromWaylandSurface> desc =
+ std::make_unique<wgpu::SurfaceDescriptorFromWaylandSurface>();
+ desc->display = glfwGetWaylandDisplay();
+ desc->surface = glfwGetWaylandWindow(window);
+ return std::move(desc);
+ } else // NOLINT(readability/braces)
+#endif
+#if defined(DAWN_USE_X11)
+ {
+ std::unique_ptr<wgpu::SurfaceDescriptorFromXlibWindow> desc =
+ std::make_unique<wgpu::SurfaceDescriptorFromXlibWindow>();
+ desc->display = glfwGetX11Display();
+ desc->window = glfwGetX11Window(window);
+ return std::move(desc);
+ }
+#else
+ { return nullptr; }
+#endif
+#else
+ return nullptr;
+#endif
+}
+
+} // namespace wgpu::glfw
diff --git a/chromium/third_party/dawn/src/dawn/utils/GLFWUtils_metal.mm b/chromium/third_party/dawn/src/dawn/glfw/utils_metal.mm
index d07eecaf0ba..d5576f91181 100644
--- a/chromium/third_party/dawn/src/dawn/utils/GLFWUtils_metal.mm
+++ b/chromium/third_party/dawn/src/dawn/glfw/utils_metal.mm
@@ -13,10 +13,10 @@
// limitations under the License.
#if !defined(DAWN_ENABLE_BACKEND_METAL)
-#error "GLFWUtils_metal.mm requires the Metal backend to be enabled."
+#error "utils_metal.mm requires the Metal backend to be enabled."
#endif // !defined(DAWN_ENABLE_BACKEND_METAL)
-#include "dawn/utils/GLFWUtils.h"
+#include "webgpu/webgpu_glfw.h"
#import <QuartzCore/CAMetalLayer.h>
#include "GLFW/glfw3.h"
@@ -26,28 +26,24 @@
#define GLFW_EXPOSE_NATIVE_COCOA
#include "GLFW/glfw3native.h"
-namespace utils {
+namespace wgpu::glfw {
std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(GLFWwindow* window) {
- if (@available(macOS 10.11, *)) {
- NSWindow* nsWindow = glfwGetCocoaWindow(window);
- NSView* view = [nsWindow contentView];
+ NSWindow* nsWindow = glfwGetCocoaWindow(window);
+ NSView* view = [nsWindow contentView];
- // Create a CAMetalLayer that covers the whole window that will be passed to
- // CreateSurface.
- [view setWantsLayer:YES];
- [view setLayer:[CAMetalLayer layer]];
+ // Create a CAMetalLayer that covers the whole window that will be passed to
+ // CreateSurface.
+ [view setWantsLayer:YES];
+ [view setLayer:[CAMetalLayer layer]];
- // Use retina if the window was created with retina support.
- [[view layer] setContentsScale:[nsWindow backingScaleFactor]];
+ // Use retina if the window was created with retina support.
+ [[view layer] setContentsScale:[nsWindow backingScaleFactor]];
- std::unique_ptr<wgpu::SurfaceDescriptorFromMetalLayer> desc =
- std::make_unique<wgpu::SurfaceDescriptorFromMetalLayer>();
- desc->layer = [view layer];
- return std::move(desc);
- }
-
- return nullptr;
+ std::unique_ptr<wgpu::SurfaceDescriptorFromMetalLayer> desc =
+ std::make_unique<wgpu::SurfaceDescriptorFromMetalLayer>();
+ desc->layer = [view layer];
+ return std::move(desc);
}
-} // namespace utils
+} // namespace wgpu::glfw
diff --git a/chromium/third_party/dawn/src/dawn/gpu_info.json b/chromium/third_party/dawn/src/dawn/gpu_info.json
new file mode 100644
index 00000000000..64643b4af73
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/gpu_info.json
@@ -0,0 +1,219 @@
+{
+ "_comment": [
+ "Copyright 2022 The Dawn Authors",
+ "",
+ "Licensed under the Apache License, Version 2.0 (the \"License\");",
+ "you may not use this file except in compliance with the License.",
+ "You may obtain a copy of the License at",
+ "",
+ " http://www.apache.org/licenses/LICENSE-2.0",
+ "",
+ "Unless required by applicable law or agreed to in writing, software",
+ "distributed under the License is distributed on an \"AS IS\" BASIS,",
+ "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
+ "See the License for the specific language governing permissions and",
+ "limitations under the License."
+ ],
+
+ "vendors": {
+
+ "_Example Vendor": {
+ "_comment": [
+ "Each vendor must have an `id` field, which is it's PCI Vendor ID, and may optionally ",
+ "have a `devices` field which defines device -> architecture mappings which will be ",
+ "when populating the GPUAdapterInfo. Keys that begin with an `_` (like this one) denote ",
+ "commnents, and will be ignored by the parser."
+ ],
+
+ "id": "0xDEAD",
+
+ "devices": [{
+ "_comment": [
+ "The `devices` is an array of 'Device Sets', each of which contains an `architecture` ",
+ "object which defines an architecture name as a key followed by an array of ",
+ "PCI device IDs that map to that architecture. The architecture name is what will be ",
+ "reported to the GPUAdapterInfo, made lower-case and with spaces converted to hyphens."
+ ],
+
+ "architecture": {
+ "Alpha": ["0x0A01", "0x0A02"],
+ "Beta": ["0x0B01", "0x0B02", "0x0B03"]
+ }
+ }, {
+ "_comment": [
+ "A Device Set can also define a binary `mask`, which will be be applied to any device ",
+ "ID prior to comparison, making it easier to capture ranges of device IDs. ",
+ "Architectures may be duplicated between Device Sets as long as the device ID values ",
+ "Don't overlap."
+ ],
+
+ "mask": "0xFF00",
+ "architecture": {
+ "Beta": ["0x1B00"],
+ "Gamma": ["0x0C00", "0x1C00"]
+ }
+ }, {
+ "_comment": [
+ "Finally, Device Sets may be flagged as `internal`. Architectures defined in an ",
+ "internal device set will never be reported in the GPUAdapterInfo, but will generate ",
+ "appropriate helper functions in Dawn (such as `IsExampleVendorDelta()`) in order to ",
+ "aid in applying workarounds. Device IDs of internal device sets may overlap with ",
+ "ones defined in non-internal device sets, but architectures must be unique between ",
+ "internal and non-internal device sets.",
+
+ "Internal architectures facilitate the (hopefully rare) cases where more targeted ",
+ "GPU identification is required by Dawn's implementation than is provided by the normal ",
+ "architecture groupings. When possible, however, using non-internal architectures ",
+ "should be preferred when applying workarounds."
+ ],
+
+ "internal": true,
+ "mask": "0xFFF0",
+ "architecture": {
+ "Beta Rev 3": ["0x1B30"]
+ }
+ }]
+ },
+
+ "AMD": {
+ "id": "0x1002",
+
+ "devices": [{
+ "mask": "0xFF00",
+ "architecture": {
+ "GCN 2": ["0x1300"],
+ "GCN 5": ["0x1500", "0x1600"],
+ "RDNA 2": ["0x7400"]
+ }
+ }, {
+ "mask": "0xFFF0",
+ "architecture": {
+ "GCN 1": ["0x6600", "0x6610", "0x6660", "0x6790", "0x6800", "0x6810", "0x6820", "0x6830"],
+ "GCN 2": ["0x6640", "0x6650", "0x67A0", "0x67B0", "0x9830", "0x9850"],
+ "GCN 3": ["0x6900", "0x6920", "0x6930", "0x7300", "0x9870", "0x98E0"],
+ "GCN 4": ["0x67C0", "0x67D0", "0x67E0", "0x67F0", "0x6980", "0x6990"],
+ "GCN 5": ["0x66A0", "0x6860", "0x6870", "0x6940", "0x69A0"],
+ "RDNA 1": ["0x7310", "0x7340", "0x7360"],
+ "RDNA 2": ["0x73A0", "0x73B0", "0x73D0", "0x73E0", "0x73F0"]
+ }
+ }]
+ },
+
+ "Apple": {
+ "id": "0x106b",
+
+ "_comment": [
+ "Apple GPUs do not report a DeviceID via the Metal API, and as such the typical device",
+ "pattern matching does not work for them. The recommended approach is to find the highest",
+ "supported 'common' family supported and report it as the architecture.",
+ "Examples: 'common-1', 'common-3'",
+ "https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/detecting_gpu_features_and_metal_software_versions"
+ ]
+ },
+
+ "ARM": {
+ "id": "0x13B5",
+
+ "devices": [{
+ "mask": "0xF0000000",
+ "architecture": {
+ "_comment": [
+ "The Midgard GPUs have device IDs like 0x07______ and 0x08______, but it's easiest to",
+ "mask those values out and simply check for the highest octet being zero, since that",
+ "distinguishes it from the other architectures."
+ ],
+
+ "Midgard": ["0x00000000"],
+ "Bifrost": ["0x60000000", "0x70000000"],
+ "Valhall": ["0x90000000", "0xA0000000"]
+ }
+ }]
+ },
+
+ "Google": {
+ "id": "0x1AE0",
+
+ "devices": [{
+ "architecture": {
+ "Swiftshader": ["0xC0DE"]
+ }
+ }]
+ },
+
+ "Img Tec": {
+ "id": "0x1010"
+ },
+
+ "Intel": {
+ "id": "0x8086",
+
+ "devices": [{
+ "mask": "0xFF00",
+ "architecture": {
+ "Gen 7": ["0x0100", "0x0400", "0x0A00", "0x0D00", "0x0F00"],
+ "Gen 8": ["0x1600", "0x2200"],
+ "Gen 9": ["0x1900", "0x3100", "0x3E00", "0x5A00", "0x5900", "0x9B00"],
+ "Gen 11": ["0x8A00"],
+ "Gen 12 LP": ["0x4600", "0x4C00", "0x4900", "0x9A00"],
+ "Gen 12 HP": ["0x4F00", "0x5600"]
+ }
+ }]
+ },
+
+ "Mesa": {
+ "id": "0x10005"
+ },
+
+ "Microsoft": {
+ "id": "0x1414",
+
+ "devices": [{
+ "architecture": {
+ "WARP": ["0x8c"]
+ }
+ }]
+ },
+
+ "Nvidia": {
+ "id": "0x10DE",
+
+ "devices": [{
+ "mask": "0xFF00",
+ "architecture": {
+ "Fermi": ["0x0D00"],
+ "Kepler": ["0x0F00", "0x1000", "0x1100", "0x1200"],
+ "Maxwell": ["0x1300", "0x1400", "0x1600", "0x1700"],
+ "Pascal": ["0x1500", "0x1B00", "0x1C00", "0x1D00"],
+ "Turing": ["0x1E00", "0x1F00", "0x2100"],
+ "Ampere": ["0x2200", "0x2400", "0x2500"]
+ }
+ }]
+ },
+
+ "Qualcomm": {
+ "id": "0x5143",
+
+ "devices": [{
+ "mask": "0xFF000000",
+ "architecture": {
+ "Adreno 4xx": ["0x04000000"],
+ "Adreno 5xx": ["0x05000000"],
+ "Adreno 6xx": ["0x06000000"],
+ "Adreno 7xx": ["0x07000000"]
+ }
+ }]
+ },
+
+ "Samsung": {
+ "id": "0x144d",
+
+ "devices": [{
+ "architecture": {
+ "RDNA 2": ["0x73A0"]
+ }
+ }]
+ }
+
+ }
+
+}
diff --git a/chromium/third_party/dawn/src/dawn/native/Adapter.cpp b/chromium/third_party/dawn/src/dawn/native/Adapter.cpp
index 53580aa6e64..68e04203466 100644
--- a/chromium/third_party/dawn/src/dawn/native/Adapter.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Adapter.cpp
@@ -33,6 +33,8 @@ AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend)
MaybeError AdapterBase::Initialize() {
DAWN_TRY_CONTEXT(InitializeImpl(), "initializing adapter (backend=%s)", mBackend);
+ InitializeVendorArchitectureImpl();
+
DAWN_TRY_CONTEXT(
InitializeSupportedFeaturesImpl(),
"gathering supported features for \"%s\" - \"%s\" (vendorId=%#06x deviceId=%#06x "
@@ -44,12 +46,11 @@ MaybeError AdapterBase::Initialize() {
"backend=%s type=%s)",
mName, mDriverDescription, mVendorId, mDeviceId, mBackend, mAdapterType);
- mVendorName = gpu_info::GetVendorName(mVendorId);
- mArchitectureName = gpu_info::GetArchitectureName(mVendorId, mDeviceId);
-
// Enforce internal Dawn constants.
mLimits.v1.maxVertexBufferArrayStride =
std::min(mLimits.v1.maxVertexBufferArrayStride, kMaxVertexBufferArrayStride);
+ mLimits.v1.maxColorAttachments =
+ std::min(mLimits.v1.maxColorAttachments, uint32_t(kMaxColorAttachments));
mLimits.v1.maxBindGroups = std::min(mLimits.v1.maxBindGroups, kMaxBindGroups);
mLimits.v1.maxVertexAttributes =
std::min(mLimits.v1.maxVertexAttributes, uint32_t(kMaxVertexAttributes));
@@ -138,6 +139,11 @@ void AdapterBase::APIRequestDevice(const DeviceDescriptor* descriptor,
callback(status, ToAPI(device.Detach()), nullptr, userdata);
}
+void AdapterBase::InitializeVendorArchitectureImpl() {
+ mVendorName = gpu_info::GetVendorName(mVendorId);
+ mArchitectureName = gpu_info::GetArchitectureName(mVendorId, mDeviceId);
+}
+
uint32_t AdapterBase::GetVendorId() const {
return mVendorId;
}
@@ -168,22 +174,6 @@ bool AdapterBase::SupportsAllRequiredFeatures(
return true;
}
-WGPUDeviceProperties AdapterBase::GetAdapterProperties() const {
- WGPUDeviceProperties adapterProperties = {};
- adapterProperties.deviceID = mDeviceId;
- adapterProperties.vendorID = mVendorId;
- adapterProperties.adapterType = static_cast<WGPUAdapterType>(mAdapterType);
-
- mSupportedFeatures.InitializeDeviceProperties(&adapterProperties);
- // This is OK for now because there are no limit feature structs.
- // If we add additional structs, the caller will need to provide memory
- // to store them (ex. by calling GetLimits directly instead). Currently,
- // we keep this function as it's only used internally in Chromium to
- // send the adapter properties across the wire.
- GetLimits(FromAPI(&adapterProperties.limits));
- return adapterProperties;
-}
-
bool AdapterBase::GetLimits(SupportedLimits* limits) const {
ASSERT(limits != nullptr);
if (limits->nextInChain != nullptr) {
diff --git a/chromium/third_party/dawn/src/dawn/native/Adapter.h b/chromium/third_party/dawn/src/dawn/native/Adapter.h
index a02e77c253e..f979b35d8d3 100644
--- a/chromium/third_party/dawn/src/dawn/native/Adapter.h
+++ b/chromium/third_party/dawn/src/dawn/native/Adapter.h
@@ -57,7 +57,6 @@ class AdapterBase : public RefCounted {
FeaturesSet GetSupportedFeatures() const;
bool SupportsAllRequiredFeatures(
const ityp::span<size_t, const wgpu::FeatureName>& features) const;
- WGPUDeviceProperties GetAdapterProperties() const;
bool GetLimits(SupportedLimits* limits) const;
@@ -86,6 +85,8 @@ class AdapterBase : public RefCounted {
// Check base WebGPU limits and populate supported limits.
virtual MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) = 0;
+ virtual void InitializeVendorArchitectureImpl();
+
ResultOrError<Ref<DeviceBase>> CreateDeviceInternal(const DeviceDescriptor* descriptor);
virtual MaybeError ResetInternalDeviceForTestingImpl();
diff --git a/chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.cpp b/chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.cpp
new file mode 100644
index 00000000000..02f83ad8668
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.cpp
@@ -0,0 +1,396 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/native/ApplyClearColorValueWithDrawHelper.h"
+
+#include <limits>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "dawn/native/BindGroup.h"
+#include "dawn/native/BindGroupLayout.h"
+#include "dawn/native/Device.h"
+#include "dawn/native/InternalPipelineStore.h"
+#include "dawn/native/ObjectContentHasher.h"
+#include "dawn/native/RenderPassEncoder.h"
+#include "dawn/native/RenderPipeline.h"
+#include "dawn/native/utils/WGPUHelpers.h"
+
+namespace dawn::native {
+
+namespace {
+
+// General helper functions and data structures for applying clear values with draw
+static const char kVSSource[] = R"(
+@vertex
+fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
+ var pos = array<vec2<f32>, 6>(
+ vec2<f32>( 0.0, -1.0),
+ vec2<f32>( 1.0, -1.0),
+ vec2<f32>( 0.0, 1.0),
+ vec2<f32>( 0.0, 1.0),
+ vec2<f32>( 1.0, -1.0),
+ vec2<f32>( 1.0, 1.0));
+ return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
+})";
+
+const char* GetTextureComponentTypeString(DeviceBase* device, wgpu::TextureFormat format) {
+ ASSERT(format != wgpu::TextureFormat::Undefined);
+
+ const Format& formatInfo = device->GetValidInternalFormat(format);
+ switch (formatInfo.GetAspectInfo(Aspect::Color).baseType) {
+ case wgpu::TextureComponentType::Sint:
+ return "i32";
+ case wgpu::TextureComponentType::Uint:
+ return "u32";
+ case wgpu::TextureComponentType::Float:
+ case wgpu::TextureComponentType::DepthComparison:
+ default:
+ UNREACHABLE();
+ return "";
+ }
+}
+
+// Construct the fragment shader to apply the input color values to the corresponding color
+// attachments of KeyOfApplyClearColorValueWithDrawPipelines.
+std::string ConstructFragmentShader(DeviceBase* device,
+ const KeyOfApplyClearColorValueWithDrawPipelines& key) {
+ std::ostringstream outputColorDeclarationStream;
+ std::ostringstream clearValueUniformBufferDeclarationStream;
+ std::ostringstream assignOutputColorStream;
+
+ outputColorDeclarationStream << "struct OutputColor {" << std::endl;
+ clearValueUniformBufferDeclarationStream << "struct ClearColors {" << std::endl;
+
+ // Only generate the assignments we need.
+ for (uint32_t i : IterateBitSet(key.colorTargetsToApplyClearColorValue)) {
+ wgpu::TextureFormat currentFormat = key.colorTargetFormats[i];
+ ASSERT(currentFormat != wgpu::TextureFormat::Undefined);
+
+ const char* type = GetTextureComponentTypeString(device, currentFormat);
+
+ outputColorDeclarationStream << "@location(" << i << ") output" << i << " : vec4<" << type
+ << ">," << std::endl;
+ clearValueUniformBufferDeclarationStream << "color" << i << " : vec4<" << type << ">,"
+ << std::endl;
+ assignOutputColorStream << "outputColor.output" << i << " = clearColors.color" << i << ";"
+ << std::endl;
+ }
+ outputColorDeclarationStream << "}" << std::endl;
+ clearValueUniformBufferDeclarationStream << "}" << std::endl;
+
+ std::ostringstream fragmentShaderStream;
+ fragmentShaderStream << outputColorDeclarationStream.str()
+ << clearValueUniformBufferDeclarationStream.str() << R"(
+@group(0) @binding(0) var<uniform> clearColors : ClearColors;
+
+@fragment
+fn main() -> OutputColor {
+ var outputColor : OutputColor;
+)" << assignOutputColorStream.str()
+ << R"(
+return outputColor;
+})";
+
+ return fragmentShaderStream.str();
+}
+
+RenderPipelineBase* GetCachedPipeline(InternalPipelineStore* store,
+ const KeyOfApplyClearColorValueWithDrawPipelines& key) {
+ auto iter = store->applyClearColorValueWithDrawPipelines.find(key);
+ if (iter != store->applyClearColorValueWithDrawPipelines.end()) {
+ return iter->second.Get();
+ }
+ return nullptr;
+}
+
+ResultOrError<RenderPipelineBase*> GetOrCreateApplyClearValueWithDrawPipeline(
+ DeviceBase* device,
+ const KeyOfApplyClearColorValueWithDrawPipelines& key) {
+ InternalPipelineStore* store = device->GetInternalPipelineStore();
+ RenderPipelineBase* cachedPipeline = GetCachedPipeline(store, key);
+ if (cachedPipeline != nullptr) {
+ return cachedPipeline;
+ }
+
+ // Prepare the vertex stage
+ Ref<ShaderModuleBase> vertexModule;
+ DAWN_TRY_ASSIGN(vertexModule, utils::CreateShaderModule(device, kVSSource));
+ VertexState vertex = {};
+ vertex.module = vertexModule.Get();
+ vertex.entryPoint = "main";
+
+ // Prepare the fragment stage
+ std::string fragmentShader = ConstructFragmentShader(device, key);
+ Ref<ShaderModuleBase> fragmentModule;
+ DAWN_TRY_ASSIGN(fragmentModule, utils::CreateShaderModule(device, fragmentShader.c_str()));
+ FragmentState fragment = {};
+ fragment.module = fragmentModule.Get();
+ fragment.entryPoint = "main";
+
+ // Prepare the color states
+ std::array<ColorTargetState, kMaxColorAttachments> colorTargets = {};
+ for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+ colorTargets[i].format = key.colorTargetFormats[i];
+ // We shouldn't change the color targets that are not involved in.
+ if (!key.colorTargetsToApplyClearColorValue[i]) {
+ colorTargets[i].writeMask = wgpu::ColorWriteMask::None;
+ }
+ }
+
+ // Create RenderPipeline
+ RenderPipelineDescriptor renderPipelineDesc = {};
+
+ renderPipelineDesc.vertex = vertex;
+ renderPipelineDesc.fragment = &fragment;
+ renderPipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
+ fragment.targetCount = key.colorAttachmentCount;
+ fragment.targets = colorTargets.data();
+
+ Ref<RenderPipelineBase> pipeline;
+ DAWN_TRY_ASSIGN(pipeline, device->CreateRenderPipeline(&renderPipelineDesc));
+ store->applyClearColorValueWithDrawPipelines.insert({key, std::move(pipeline)});
+
+ return GetCachedPipeline(store, key);
+}
+
+Color GetClearColorValue(const RenderPassColorAttachment& attachment) {
+ return HasDeprecatedColor(attachment) ? attachment.clearColor : attachment.clearValue;
+}
+
+ResultOrError<Ref<BufferBase>> CreateUniformBufferWithClearValues(
+ DeviceBase* device,
+ const RenderPassDescriptor* renderPassDescriptor,
+ const KeyOfApplyClearColorValueWithDrawPipelines& key) {
+ std::array<uint8_t, sizeof(uint32_t)* 4 * kMaxColorAttachments> clearValues = {};
+ uint32_t offset = 0;
+ for (uint32_t i : IterateBitSet(key.colorTargetsToApplyClearColorValue)) {
+ const Format& format = renderPassDescriptor->colorAttachments[i].view->GetFormat();
+ wgpu::TextureComponentType baseType = format.GetAspectInfo(Aspect::Color).baseType;
+
+ Color initialClearValue = GetClearColorValue(renderPassDescriptor->colorAttachments[i]);
+ Color clearValue = ClampClearColorValueToLegalRange(initialClearValue, format);
+ switch (baseType) {
+ case wgpu::TextureComponentType::Uint: {
+ uint32_t* clearValuePtr = reinterpret_cast<uint32_t*>(clearValues.data() + offset);
+ clearValuePtr[0] = static_cast<uint32_t>(clearValue.r);
+ clearValuePtr[1] = static_cast<uint32_t>(clearValue.g);
+ clearValuePtr[2] = static_cast<uint32_t>(clearValue.b);
+ clearValuePtr[3] = static_cast<uint32_t>(clearValue.a);
+ break;
+ }
+ case wgpu::TextureComponentType::Sint: {
+ int32_t* clearValuePtr = reinterpret_cast<int32_t*>(clearValues.data() + offset);
+ clearValuePtr[0] = static_cast<int32_t>(clearValue.r);
+ clearValuePtr[1] = static_cast<int32_t>(clearValue.g);
+ clearValuePtr[2] = static_cast<int32_t>(clearValue.b);
+ clearValuePtr[3] = static_cast<int32_t>(clearValue.a);
+ break;
+ }
+ case wgpu::TextureComponentType::Float: {
+ float* clearValuePtr = reinterpret_cast<float*>(clearValues.data() + offset);
+ clearValuePtr[0] = static_cast<float>(clearValue.r);
+ clearValuePtr[1] = static_cast<float>(clearValue.g);
+ clearValuePtr[2] = static_cast<float>(clearValue.b);
+ clearValuePtr[3] = static_cast<float>(clearValue.a);
+ break;
+ }
+
+ case wgpu::TextureComponentType::DepthComparison:
+ default:
+ UNREACHABLE();
+ break;
+ }
+ offset += sizeof(uint32_t) * 4;
+ }
+
+ ASSERT(offset > 0);
+
+ Ref<BufferBase> outputBuffer;
+ DAWN_TRY_ASSIGN(
+ outputBuffer,
+ utils::CreateBufferFromData(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform,
+ clearValues.data(), offset));
+
+ return std::move(outputBuffer);
+}
+
+// Helper functions for applying big integer clear values with draw
+bool ShouldApplyClearBigIntegerColorValueWithDraw(
+ const RenderPassColorAttachment& colorAttachmentInfo) {
+ if (colorAttachmentInfo.view == nullptr) {
+ return false;
+ }
+
+ if (colorAttachmentInfo.loadOp != wgpu::LoadOp::Clear) {
+ return false;
+ }
+
+ // We should only apply this workaround on 32-bit signed and unsigned integer formats.
+ const Format& format = colorAttachmentInfo.view->GetFormat();
+ switch (format.format) {
+ case wgpu::TextureFormat::R32Sint:
+ case wgpu::TextureFormat::RG32Sint:
+ case wgpu::TextureFormat::RGBA32Sint:
+ case wgpu::TextureFormat::R32Uint:
+ case wgpu::TextureFormat::RG32Uint:
+ case wgpu::TextureFormat::RGBA32Uint:
+ break;
+ default:
+ return false;
+ }
+
+ // TODO(dawn:537): only check the color channels that are available in the current color format.
+ Color clearValue = GetClearColorValue(colorAttachmentInfo);
+ switch (format.GetAspectInfo(Aspect::Color).baseType) {
+ case wgpu::TextureComponentType::Uint: {
+ constexpr double kMaxUintRepresentableInFloat = 1 << std::numeric_limits<float>::digits;
+ if (clearValue.r <= kMaxUintRepresentableInFloat &&
+ clearValue.g <= kMaxUintRepresentableInFloat &&
+ clearValue.b <= kMaxUintRepresentableInFloat &&
+ clearValue.a <= kMaxUintRepresentableInFloat) {
+ return false;
+ }
+ break;
+ }
+ case wgpu::TextureComponentType::Sint: {
+ constexpr double kMaxSintRepresentableInFloat = 1 << std::numeric_limits<float>::digits;
+ constexpr double kMinSintRepresentableInFloat = -kMaxSintRepresentableInFloat;
+ if (clearValue.r <= kMaxSintRepresentableInFloat &&
+ clearValue.r >= kMinSintRepresentableInFloat &&
+ clearValue.g <= kMaxSintRepresentableInFloat &&
+ clearValue.g >= kMinSintRepresentableInFloat &&
+ clearValue.b <= kMaxSintRepresentableInFloat &&
+ clearValue.b >= kMinSintRepresentableInFloat &&
+ clearValue.a <= kMaxSintRepresentableInFloat &&
+ clearValue.a >= kMinSintRepresentableInFloat) {
+ return false;
+ }
+ break;
+ }
+ case wgpu::TextureComponentType::Float:
+ case wgpu::TextureComponentType::DepthComparison:
+ default:
+ UNREACHABLE();
+ return false;
+ }
+
+ return true;
+}
+
+KeyOfApplyClearColorValueWithDrawPipelines GetKeyOfApplyClearColorValueWithDrawPipelines(
+ const RenderPassDescriptor* renderPassDescriptor) {
+ KeyOfApplyClearColorValueWithDrawPipelines key;
+ key.colorAttachmentCount = renderPassDescriptor->colorAttachmentCount;
+
+ key.colorTargetFormats.fill(wgpu::TextureFormat::Undefined);
+ for (uint32_t i = 0; i < renderPassDescriptor->colorAttachmentCount; ++i) {
+ if (renderPassDescriptor->colorAttachments[i].view != nullptr) {
+ key.colorTargetFormats[i] =
+ renderPassDescriptor->colorAttachments[i].view->GetFormat().format;
+ }
+
+ if (ShouldApplyClearBigIntegerColorValueWithDraw(
+ renderPassDescriptor->colorAttachments[i])) {
+ key.colorTargetsToApplyClearColorValue.set(i);
+ }
+ }
+ return key;
+}
+
+} // namespace
+
+size_t KeyOfApplyClearColorValueWithDrawPipelinesHashFunc::operator()(
+ KeyOfApplyClearColorValueWithDrawPipelines key) const {
+ size_t hash = 0;
+
+ HashCombine(&hash, key.colorAttachmentCount);
+
+ HashCombine(&hash, key.colorTargetsToApplyClearColorValue);
+
+ for (wgpu::TextureFormat format : key.colorTargetFormats) {
+ HashCombine(&hash, format);
+ }
+
+ return hash;
+}
+
+bool KeyOfApplyClearColorValueWithDrawPipelinesEqualityFunc::operator()(
+ KeyOfApplyClearColorValueWithDrawPipelines key1,
+ KeyOfApplyClearColorValueWithDrawPipelines key2) const {
+ if (key1.colorAttachmentCount != key2.colorAttachmentCount) {
+ return false;
+ }
+
+ if (key1.colorTargetsToApplyClearColorValue != key2.colorTargetsToApplyClearColorValue) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+ if (key1.colorTargetFormats[i] != key2.colorTargetFormats[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ShouldApplyClearBigIntegerColorValueWithDraw(
+ const DeviceBase* device,
+ const RenderPassDescriptor* renderPassDescriptor) {
+ if (!device->IsToggleEnabled(Toggle::ApplyClearBigIntegerColorValueWithDraw)) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < renderPassDescriptor->colorAttachmentCount; ++i) {
+ if (ShouldApplyClearBigIntegerColorValueWithDraw(
+ renderPassDescriptor->colorAttachments[i])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+MaybeError ApplyClearBigIntegerColorValueWithDraw(
+ RenderPassEncoder* renderPassEncoder,
+ const RenderPassDescriptor* renderPassDescriptor) {
+ DeviceBase* device = renderPassEncoder->GetDevice();
+
+ KeyOfApplyClearColorValueWithDrawPipelines key =
+ GetKeyOfApplyClearColorValueWithDrawPipelines(renderPassDescriptor);
+
+ RenderPipelineBase* pipeline = nullptr;
+ DAWN_TRY_ASSIGN(pipeline, GetOrCreateApplyClearValueWithDrawPipeline(device, key));
+
+ Ref<BindGroupLayoutBase> layout;
+ DAWN_TRY_ASSIGN(layout, pipeline->GetBindGroupLayout(0));
+
+ Ref<BufferBase> uniformBufferWithClearColorValues;
+ DAWN_TRY_ASSIGN(uniformBufferWithClearColorValues,
+ CreateUniformBufferWithClearValues(device, renderPassDescriptor, key));
+
+ Ref<BindGroupBase> bindGroup;
+ DAWN_TRY_ASSIGN(bindGroup,
+ utils::MakeBindGroup(device, layout, {{0, uniformBufferWithClearColorValues}},
+ UsageValidationMode::Internal));
+
+ renderPassEncoder->APISetBindGroup(0, bindGroup.Get());
+ renderPassEncoder->APISetPipeline(pipeline);
+ renderPassEncoder->APIDraw(6);
+
+ return {};
+}
+
+} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.h b/chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.h
new file mode 100644
index 00000000000..60fce8b4332
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/ApplyClearColorValueWithDrawHelper.h
@@ -0,0 +1,55 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_APPLYCLEARVALUEWITHDRAWHELPER_H_
+#define SRC_DAWN_NATIVE_APPLYCLEARVALUEWITHDRAWHELPER_H_
+
+#include <bitset>
+#include <unordered_map>
+#include "dawn/common/Constants.h"
+#include "dawn/native/Error.h"
+
+namespace dawn::native {
+class BufferBase;
+class RenderPassEncoder;
+struct RenderPassDescriptor;
+
+struct KeyOfApplyClearColorValueWithDrawPipelines {
+ uint8_t colorAttachmentCount;
+ std::array<wgpu::TextureFormat, kMaxColorAttachments> colorTargetFormats;
+ std::bitset<kMaxColorAttachments> colorTargetsToApplyClearColorValue;
+};
+
+struct KeyOfApplyClearColorValueWithDrawPipelinesHashFunc {
+ size_t operator()(KeyOfApplyClearColorValueWithDrawPipelines key) const;
+};
+struct KeyOfApplyClearColorValueWithDrawPipelinesEqualityFunc {
+ bool operator()(KeyOfApplyClearColorValueWithDrawPipelines key1,
+ const KeyOfApplyClearColorValueWithDrawPipelines key2) const;
+};
+using ApplyClearColorValueWithDrawPipelinesCache =
+ std::unordered_map<KeyOfApplyClearColorValueWithDrawPipelines,
+ Ref<RenderPipelineBase>,
+ KeyOfApplyClearColorValueWithDrawPipelinesHashFunc,
+ KeyOfApplyClearColorValueWithDrawPipelinesEqualityFunc>;
+
+bool ShouldApplyClearBigIntegerColorValueWithDraw(const DeviceBase* device,
+ const RenderPassDescriptor* renderPassDescriptor);
+
+MaybeError ApplyClearBigIntegerColorValueWithDraw(RenderPassEncoder* renderPassEncoder,
+ const RenderPassDescriptor* renderPassDescriptor);
+
+} // namespace dawn::native
+
+#endif
diff --git a/chromium/third_party/dawn/src/dawn/native/BUILD.gn b/chromium/third_party/dawn/src/dawn/native/BUILD.gn
index b9cef200014..19ca4d4b85d 100644
--- a/chromium/third_party/dawn/src/dawn/native/BUILD.gn
+++ b/chromium/third_party/dawn/src/dawn/native/BUILD.gn
@@ -97,9 +97,9 @@ dawn_json_generator("utils_gen") {
"src/dawn/native/ValidationUtils_autogen.cpp",
"src/dawn/native/webgpu_absl_format_autogen.h",
"src/dawn/native/webgpu_absl_format_autogen.cpp",
+ "src/dawn/native/webgpu_StreamImpl_autogen.cpp",
"src/dawn/native/ObjectType_autogen.h",
"src/dawn/native/ObjectType_autogen.cpp",
- "src/dawn/native/CacheKey_autogen.cpp",
]
}
@@ -175,6 +175,8 @@ source_set("sources") {
sources += [
"Adapter.cpp",
"Adapter.h",
+ "ApplyClearColorValueWithDrawHelper.cpp",
+ "ApplyClearColorValueWithDrawHelper.h",
"AsyncTask.cpp",
"AsyncTask.h",
"AttachmentState.cpp",
@@ -200,6 +202,9 @@ source_set("sources") {
"Buffer.h",
"CacheKey.cpp",
"CacheKey.h",
+ "CacheRequest.cpp",
+ "CacheRequest.h",
+ "CacheResult.h",
"CachedObject.cpp",
"CachedObject.h",
"CallbackTaskManager.cpp",
@@ -308,10 +313,12 @@ source_set("sources") {
"Sampler.h",
"ScratchBuffer.cpp",
"ScratchBuffer.h",
+ "Serializable.h",
"ShaderModule.cpp",
"ShaderModule.h",
"StagingBuffer.cpp",
"StagingBuffer.h",
+ "StreamImplTint.cpp",
"Subresource.cpp",
"Subresource.h",
"SubresourceStorage.h",
@@ -326,9 +333,19 @@ source_set("sources") {
"ToBackend.h",
"Toggles.cpp",
"Toggles.h",
+ "UsageValidationMode.h",
"VertexFormat.cpp",
"VertexFormat.h",
+ "VisitableMembers.h",
"dawn_platform.h",
+ "stream/BlobSource.cpp",
+ "stream/BlobSource.h",
+ "stream/ByteVectorSink.cpp",
+ "stream/ByteVectorSink.h",
+ "stream/Sink.h",
+ "stream/Source.h",
+ "stream/Stream.cpp",
+ "stream/Stream.h",
"utils/WGPUHelpers.cpp",
"utils/WGPUHelpers.h",
"webgpu_absl_format.cpp",
@@ -382,7 +399,6 @@ source_set("sources") {
"d3d12/BufferD3D12.h",
"d3d12/CPUDescriptorHeapAllocationD3D12.cpp",
"d3d12/CPUDescriptorHeapAllocationD3D12.h",
- "d3d12/CacheKeyD3D12.cpp",
"d3d12/CommandAllocatorManager.cpp",
"d3d12/CommandAllocatorManager.h",
"d3d12/CommandBufferD3D12.cpp",
@@ -443,6 +459,7 @@ source_set("sources") {
"d3d12/StagingBufferD3D12.h",
"d3d12/StagingDescriptorAllocatorD3D12.cpp",
"d3d12/StagingDescriptorAllocatorD3D12.h",
+ "d3d12/StreamImplD3D12.cpp",
"d3d12/SwapChainD3D12.cpp",
"d3d12/SwapChainD3D12.h",
"d3d12/TextureCopySplitter.cpp",
@@ -539,8 +556,12 @@ source_set("sources") {
"opengl/CommandBufferGL.h",
"opengl/ComputePipelineGL.cpp",
"opengl/ComputePipelineGL.h",
+ "opengl/ContextEGL.cpp",
+ "opengl/ContextEGL.h",
"opengl/DeviceGL.cpp",
"opengl/DeviceGL.h",
+ "opengl/EGLFunctions.cpp",
+ "opengl/EGLFunctions.h",
"opengl/Forward.h",
"opengl/GLFormat.cpp",
"opengl/GLFormat.h",
@@ -570,10 +591,13 @@ source_set("sources") {
"opengl/SwapChainGL.h",
"opengl/TextureGL.cpp",
"opengl/TextureGL.h",
+ "opengl/UtilsEGL.cpp",
+ "opengl/UtilsEGL.h",
"opengl/UtilsGL.cpp",
"opengl/UtilsGL.h",
"opengl/opengl_platform.h",
]
+ include_dirs = [ "//third_party/khronos" ]
}
if (dawn_enable_vulkan) {
@@ -591,8 +615,6 @@ source_set("sources") {
"vulkan/BindGroupVk.h",
"vulkan/BufferVk.cpp",
"vulkan/BufferVk.h",
- "vulkan/CacheKeyVk.cpp",
- "vulkan/CacheKeyVk.h",
"vulkan/CommandBufferVk.cpp",
"vulkan/CommandBufferVk.h",
"vulkan/CommandRecordingContext.h",
@@ -631,6 +653,7 @@ source_set("sources") {
"vulkan/ShaderModuleVk.h",
"vulkan/StagingBufferVk.cpp",
"vulkan/StagingBufferVk.h",
+ "vulkan/StreamImplVk.cpp",
"vulkan/SwapChainVk.cpp",
"vulkan/SwapChainVk.h",
"vulkan/TextureVk.cpp",
diff --git a/chromium/third_party/dawn/src/dawn/native/BindGroup.cpp b/chromium/third_party/dawn/src/dawn/native/BindGroup.cpp
index 0d3af775b3c..c5e0afcdfe9 100644
--- a/chromium/third_party/dawn/src/dawn/native/BindGroup.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/BindGroup.cpp
@@ -20,12 +20,14 @@
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/Buffer.h"
#include "dawn/native/ChainUtils_autogen.h"
+#include "dawn/native/CommandValidation.h"
#include "dawn/native/Device.h"
#include "dawn/native/ExternalTexture.h"
#include "dawn/native/ObjectBase.h"
#include "dawn/native/ObjectType_autogen.h"
#include "dawn/native/Sampler.h"
#include "dawn/native/Texture.h"
+#include "dawn/native/utils/WGPUHelpers.h"
namespace dawn::native {
@@ -114,7 +116,8 @@ MaybeError ValidateBufferBinding(const DeviceBase* device,
MaybeError ValidateTextureBinding(DeviceBase* device,
const BindGroupEntry& entry,
- const BindingInfo& bindingInfo) {
+ const BindingInfo& bindingInfo,
+ UsageValidationMode mode) {
DAWN_INVALID_IF(entry.textureView == nullptr, "Binding entry textureView not set.");
DAWN_INVALID_IF(entry.sampler != nullptr || entry.buffer != nullptr,
@@ -136,9 +139,7 @@ MaybeError ValidateTextureBinding(DeviceBase* device,
texture->GetFormat().GetAspectInfo(aspect).supportedSampleTypes;
SampleTypeBit requiredType = SampleTypeToSampleTypeBit(bindingInfo.texture.sampleType);
- DAWN_INVALID_IF(!(texture->GetUsage() & wgpu::TextureUsage::TextureBinding),
- "Usage (%s) of %s doesn't include TextureUsage::TextureBinding.",
- texture->GetUsage(), texture);
+ DAWN_TRY(ValidateCanUseAs(texture, wgpu::TextureUsage::TextureBinding, mode));
DAWN_INVALID_IF(texture->IsMultisampledTexture() != bindingInfo.texture.multisampled,
"Sample count (%u) of %s doesn't match expectation (multisampled: %d).",
@@ -157,9 +158,7 @@ MaybeError ValidateTextureBinding(DeviceBase* device,
break;
}
case BindingInfoType::StorageTexture: {
- DAWN_INVALID_IF(!(texture->GetUsage() & wgpu::TextureUsage::StorageBinding),
- "Usage (%s) of %s doesn't include TextureUsage::StorageBinding.",
- texture->GetUsage(), texture);
+ DAWN_TRY(ValidateCanUseAs(texture, wgpu::TextureUsage::StorageBinding, mode));
ASSERT(!texture->IsMultisampledTexture());
@@ -253,7 +252,9 @@ MaybeError ValidateExternalTextureBinding(
} // anonymous namespace
-MaybeError ValidateBindGroupDescriptor(DeviceBase* device, const BindGroupDescriptor* descriptor) {
+MaybeError ValidateBindGroupDescriptor(DeviceBase* device,
+ const BindGroupDescriptor* descriptor,
+ UsageValidationMode mode) {
DAWN_INVALID_IF(descriptor->nextInChain != nullptr, "nextInChain must be nullptr.");
DAWN_TRY(device->ValidateObject(descriptor->layout));
@@ -314,6 +315,7 @@ MaybeError ValidateBindGroupDescriptor(DeviceBase* device, const BindGroupDescri
// Perform binding-type specific validation.
switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer:
+ // TODO(dawn:1485): Validate buffer binding with usage validation mode.
DAWN_TRY_CONTEXT(ValidateBufferBinding(device, entry, bindingInfo),
"validating entries[%u] as a Buffer."
"\nExpected entry layout: %s",
@@ -321,7 +323,7 @@ MaybeError ValidateBindGroupDescriptor(DeviceBase* device, const BindGroupDescri
break;
case BindingInfoType::Texture:
case BindingInfoType::StorageTexture:
- DAWN_TRY_CONTEXT(ValidateTextureBinding(device, entry, bindingInfo),
+ DAWN_TRY_CONTEXT(ValidateTextureBinding(device, entry, bindingInfo, mode),
"validating entries[%u] as a Texture."
"\nExpected entry layout: %s",
i, bindingInfo);
diff --git a/chromium/third_party/dawn/src/dawn/native/BindGroup.h b/chromium/third_party/dawn/src/dawn/native/BindGroup.h
index 236e4fb9774..34c122b0c19 100644
--- a/chromium/third_party/dawn/src/dawn/native/BindGroup.h
+++ b/chromium/third_party/dawn/src/dawn/native/BindGroup.h
@@ -24,6 +24,7 @@
#include "dawn/native/Error.h"
#include "dawn/native/Forward.h"
#include "dawn/native/ObjectBase.h"
+#include "dawn/native/UsageValidationMode.h"
#include "dawn/native/dawn_platform.h"
@@ -31,7 +32,9 @@ namespace dawn::native {
class DeviceBase;
-MaybeError ValidateBindGroupDescriptor(DeviceBase* device, const BindGroupDescriptor* descriptor);
+MaybeError ValidateBindGroupDescriptor(DeviceBase* device,
+ const BindGroupDescriptor* descriptor,
+ UsageValidationMode mode);
struct BufferBinding {
BufferBase* buffer;
diff --git a/chromium/third_party/dawn/src/dawn/native/Blob.cpp b/chromium/third_party/dawn/src/dawn/native/Blob.cpp
index a3ac2b28efd..78b18e7d604 100644
--- a/chromium/third_party/dawn/src/dawn/native/Blob.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Blob.cpp
@@ -15,14 +15,25 @@
#include <utility>
#include "dawn/common/Assert.h"
+#include "dawn/common/Math.h"
#include "dawn/native/Blob.h"
+#include "dawn/native/stream/Stream.h"
namespace dawn::native {
-Blob CreateBlob(size_t size) {
+Blob CreateBlob(size_t size, size_t alignment) {
+ ASSERT(IsPowerOfTwo(alignment));
+ ASSERT(alignment != 0);
if (size > 0) {
- uint8_t* data = new uint8_t[size];
- return Blob::UnsafeCreateWithDeleter(data, size, [=]() { delete[] data; });
+ // Allocate extra space so that there will be sufficient space for |size| even after
+ // the |data| pointer is aligned.
+ // TODO(crbug.com/dawn/824): Use aligned_alloc when possible. It should be available
+ // with C++17 but on macOS it also requires macOS 10.15 to work.
+ size_t allocatedSize = size + alignment - 1;
+ uint8_t* data = new uint8_t[allocatedSize];
+ uint8_t* ptr = AlignPtr(data, alignment);
+ ASSERT(ptr + size <= data + allocatedSize);
+ return Blob::UnsafeCreateWithDeleter(ptr, size, [=]() { delete[] data; });
} else {
return Blob();
}
@@ -43,6 +54,7 @@ Blob::Blob(uint8_t* data, size_t size, std::function<void()> deleter)
Blob::Blob(Blob&& rhs) : mData(rhs.mData), mSize(rhs.mSize) {
mDeleter = std::move(rhs.mDeleter);
+ rhs.mDeleter = nullptr;
}
Blob& Blob::operator=(Blob&& rhs) {
@@ -52,6 +64,7 @@ Blob& Blob::operator=(Blob&& rhs) {
mDeleter();
}
mDeleter = std::move(rhs.mDeleter);
+ rhs.mDeleter = nullptr;
return *this;
}
@@ -77,4 +90,39 @@ size_t Blob::Size() const {
return mSize;
}
+void Blob::AlignTo(size_t alignment) {
+ if (IsPtrAligned(mData, alignment)) {
+ return;
+ }
+
+ Blob blob = CreateBlob(mSize, alignment);
+ memcpy(blob.Data(), mData, mSize);
+ *this = std::move(blob);
+}
+
+template <>
+void stream::Stream<Blob>::Write(stream::Sink* s, const Blob& b) {
+ size_t size = b.Size();
+ StreamIn(s, size);
+ if (size > 0) {
+ void* ptr = s->GetSpace(size);
+ memcpy(ptr, b.Data(), size);
+ }
+}
+
+template <>
+MaybeError stream::Stream<Blob>::Read(stream::Source* s, Blob* b) {
+ size_t size;
+ DAWN_TRY(StreamOut(s, &size));
+ if (size > 0) {
+ const void* ptr;
+ DAWN_TRY(s->Read(&ptr, size));
+ *b = CreateBlob(size);
+ memcpy(b->Data(), ptr, size);
+ } else {
+ *b = Blob();
+ }
+ return {};
+}
+
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/Blob.h b/chromium/third_party/dawn/src/dawn/native/Blob.h
index 4bdcef7be3f..807082c728c 100644
--- a/chromium/third_party/dawn/src/dawn/native/Blob.h
+++ b/chromium/third_party/dawn/src/dawn/native/Blob.h
@@ -15,8 +15,11 @@
#ifndef SRC_DAWN_NATIVE_BLOB_H_
#define SRC_DAWN_NATIVE_BLOB_H_
+#include <cstdint>
#include <functional>
-#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
namespace dawn::native {
@@ -43,6 +46,10 @@ class Blob {
uint8_t* Data();
size_t Size() const;
+ // If the blob data is not aligned to |alignment|, copy it into a new backing store which
+ // is aligned.
+ void AlignTo(size_t alignment);
+
private:
// The constructor should be responsible to take ownership of |data| and releases ownership by
// calling |deleter|. The deleter function is called at ~Blob() and during std::move.
@@ -53,7 +60,16 @@ class Blob {
std::function<void()> mDeleter;
};
-Blob CreateBlob(size_t size);
+Blob CreateBlob(size_t size, size_t alignment = 1);
+
+template <typename T, typename = std::enable_if_t<std::is_fundamental_v<T>>>
+Blob CreateBlob(std::vector<T> vec) {
+ uint8_t* data = reinterpret_cast<uint8_t*>(vec.data());
+ size_t size = vec.size() * sizeof(T);
+ // Move the vector into a new allocation so we can destruct it in the deleter.
+ auto* wrapped_vec = new std::vector<T>(std::move(vec));
+ return Blob::UnsafeCreateWithDeleter(data, size, [wrapped_vec]() { delete wrapped_vec; });
+}
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/BlobCache.cpp b/chromium/third_party/dawn/src/dawn/native/BlobCache.cpp
index 435f12dd493..a9193184205 100644
--- a/chromium/third_party/dawn/src/dawn/native/BlobCache.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/BlobCache.cpp
@@ -14,7 +14,10 @@
#include "dawn/native/BlobCache.h"
+#include <algorithm>
+
#include "dawn/common/Assert.h"
+#include "dawn/common/Version_autogen.h"
#include "dawn/native/CacheKey.h"
#include "dawn/native/Instance.h"
#include "dawn/platform/DawnPlatform.h"
@@ -39,6 +42,7 @@ void BlobCache::Store(const CacheKey& key, const Blob& value) {
}
Blob BlobCache::LoadInternal(const CacheKey& key) {
+ ASSERT(ValidateCacheKey(key));
if (mCache == nullptr) {
return Blob();
}
@@ -55,6 +59,7 @@ Blob BlobCache::LoadInternal(const CacheKey& key) {
}
void BlobCache::StoreInternal(const CacheKey& key, size_t valueSize, const void* value) {
+ ASSERT(ValidateCacheKey(key));
ASSERT(value != nullptr);
ASSERT(valueSize > 0);
if (mCache == nullptr) {
@@ -63,4 +68,9 @@ void BlobCache::StoreInternal(const CacheKey& key, size_t valueSize, const void*
mCache->StoreData(key.data(), key.size(), value, valueSize);
}
+bool BlobCache::ValidateCacheKey(const CacheKey& key) {
+ return std::search(key.begin(), key.end(), kDawnVersion.begin(), kDawnVersion.end()) !=
+ key.end();
+}
+
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/BlobCache.h b/chromium/third_party/dawn/src/dawn/native/BlobCache.h
index 615af2f877c..e3035cd8624 100644
--- a/chromium/third_party/dawn/src/dawn/native/BlobCache.h
+++ b/chromium/third_party/dawn/src/dawn/native/BlobCache.h
@@ -19,6 +19,7 @@
#include "dawn/common/Platform.h"
#include "dawn/native/Blob.h"
+#include "dawn/native/CacheResult.h"
namespace dawn::platform {
class CachingInterface;
@@ -42,12 +43,25 @@ class BlobCache {
void Store(const CacheKey& key, size_t valueSize, const void* value);
void Store(const CacheKey& key, const Blob& value);
+ // Store a CacheResult into the cache if it isn't cached yet.
+ // Calls T::ToBlob which should be defined elsewhere.
+ template <typename T>
+ void EnsureStored(const CacheResult<T>& cacheResult) {
+ if (!cacheResult.IsCached()) {
+ Store(cacheResult.GetCacheKey(), cacheResult->ToBlob());
+ }
+ }
+
private:
// Non-thread safe internal implementations of load and store. Exposed callers that use
// these helpers need to make sure that these are entered with `mMutex` held.
Blob LoadInternal(const CacheKey& key);
void StoreInternal(const CacheKey& key, size_t valueSize, const void* value);
+ // Validates the cache key for this version of Dawn. At the moment, this is naively checking
+ // that the cache key contains the dawn version string in it.
+ bool ValidateCacheKey(const CacheKey& key);
+
// Protects thread safety of access to mCache.
std::mutex mMutex;
dawn::platform::CachingInterface* mCache;
diff --git a/chromium/third_party/dawn/src/dawn/native/CMakeLists.txt b/chromium/third_party/dawn/src/dawn/native/CMakeLists.txt
index f704ccbb016..3f417bcbd20 100644
--- a/chromium/third_party/dawn/src/dawn/native/CMakeLists.txt
+++ b/chromium/third_party/dawn/src/dawn/native/CMakeLists.txt
@@ -32,6 +32,8 @@ target_sources(dawn_native PRIVATE
${DAWN_NATIVE_UTILS_GEN_SOURCES}
"Adapter.cpp"
"Adapter.h"
+ "ApplyClearColorValueWithDrawHelper.cpp"
+ "ApplyClearColorValueWithDrawHelper.h"
"AsyncTask.cpp"
"AsyncTask.h"
"AttachmentState.cpp"
@@ -59,6 +61,9 @@ target_sources(dawn_native PRIVATE
"CachedObject.h"
"CacheKey.cpp"
"CacheKey.h"
+ "CacheRequest.cpp"
+ "CacheRequest.h"
+ "CacheResult.h"
"CallbackTaskManager.cpp"
"CallbackTaskManager.h"
"CommandAllocator.cpp"
@@ -165,10 +170,12 @@ target_sources(dawn_native PRIVATE
"Sampler.h"
"ScratchBuffer.cpp"
"ScratchBuffer.h"
+ "Serializable.h"
"ShaderModule.cpp"
"ShaderModule.h"
"StagingBuffer.cpp"
"StagingBuffer.h"
+ "StreamImplTint.cpp"
"Subresource.cpp"
"Subresource.h"
"SubresourceStorage.h"
@@ -183,11 +190,21 @@ target_sources(dawn_native PRIVATE
"ToBackend.h"
"Toggles.cpp"
"Toggles.h"
+ "UsageValidationMode.h"
"VertexFormat.cpp"
"VertexFormat.h"
+ "VisitableMembers.h"
"dawn_platform.h"
"webgpu_absl_format.cpp"
"webgpu_absl_format.h"
+ "stream/BlobSource.cpp"
+ "stream/BlobSource.h"
+ "stream/ByteVectorSink.cpp"
+ "stream/ByteVectorSink.h"
+ "stream/Sink.h"
+ "stream/Source.h"
+ "stream/Stream.cpp"
+ "stream/Stream.h"
"utils/WGPUHelpers.cpp"
"utils/WGPUHelpers.h"
)
@@ -251,7 +268,6 @@ if (DAWN_ENABLE_D3D12)
"d3d12/CPUDescriptorHeapAllocationD3D12.h"
"d3d12/CommandAllocatorManager.cpp"
"d3d12/CommandAllocatorManager.h"
- "d3d12/CacheKeyD3D12.cpp"
"d3d12/CommandBufferD3D12.cpp"
"d3d12/CommandBufferD3D12.h"
"d3d12/CommandRecordingContext.cpp"
@@ -310,6 +326,7 @@ if (DAWN_ENABLE_D3D12)
"d3d12/StagingBufferD3D12.h"
"d3d12/StagingDescriptorAllocatorD3D12.cpp"
"d3d12/StagingDescriptorAllocatorD3D12.h"
+ "d3d12/StreamImplD3D12.cpp"
"d3d12/SwapChainD3D12.cpp"
"d3d12/SwapChainD3D12.h"
"d3d12/TextureCopySplitter.cpp"
@@ -417,8 +434,12 @@ if (DAWN_ENABLE_OPENGL)
"opengl/CommandBufferGL.h"
"opengl/ComputePipelineGL.cpp"
"opengl/ComputePipelineGL.h"
+ "opengl/ContextEGL.cpp"
+ "opengl/ContextEGL.h"
"opengl/DeviceGL.cpp"
"opengl/DeviceGL.h"
+ "opengl/EGLFunctions.cpp"
+ "opengl/EGLFunctions.h"
"opengl/Forward.h"
"opengl/GLFormat.cpp"
"opengl/GLFormat.h"
@@ -448,11 +469,14 @@ if (DAWN_ENABLE_OPENGL)
"opengl/SwapChainGL.h"
"opengl/TextureGL.cpp"
"opengl/TextureGL.h"
+ "opengl/UtilsEGL.cpp"
+ "opengl/UtilsEGL.h"
"opengl/UtilsGL.cpp"
"opengl/UtilsGL.h"
"opengl/opengl_platform.h"
)
+ target_include_directories(dawn_native PRIVATE ${DAWN_KHRONOS_DIR})
target_link_libraries(dawn_native PRIVATE dawn_khronos_platform)
endif()
@@ -473,8 +497,6 @@ if (DAWN_ENABLE_VULKAN)
"vulkan/BindGroupVk.h"
"vulkan/BufferVk.cpp"
"vulkan/BufferVk.h"
- "vulkan/CacheKeyVk.cpp"
- "vulkan/CacheKeyVk.h"
"vulkan/CommandBufferVk.cpp"
"vulkan/CommandBufferVk.h"
"vulkan/CommandRecordingContext.h"
@@ -513,6 +535,7 @@ if (DAWN_ENABLE_VULKAN)
"vulkan/ShaderModuleVk.h"
"vulkan/StagingBufferVk.cpp"
"vulkan/StagingBufferVk.h"
+ "vulkan/StreamImplVk.cpp"
"vulkan/SwapChainVk.cpp"
"vulkan/SwapChainVk.h"
"vulkan/TextureVk.cpp"
@@ -574,6 +597,7 @@ DawnJSONGenerator(
add_library(webgpu_dawn ${DAWN_PLACEHOLDER_FILE})
common_compile_options(webgpu_dawn)
target_link_libraries(webgpu_dawn PRIVATE dawn_native)
+target_link_libraries(webgpu_dawn PUBLIC dawn_headers)
target_compile_definitions(webgpu_dawn PRIVATE "WGPU_IMPLEMENTATION")
if(BUILD_SHARED_LIBS)
target_compile_definitions(webgpu_dawn PRIVATE "WGPU_SHARED_LIBRARY")
diff --git a/chromium/third_party/dawn/src/dawn/native/CacheKey.cpp b/chromium/third_party/dawn/src/dawn/native/CacheKey.cpp
index 495b013ed98..de1a75e3b8d 100644
--- a/chromium/third_party/dawn/src/dawn/native/CacheKey.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/CacheKey.cpp
@@ -14,30 +14,11 @@
#include "dawn/native/CacheKey.h"
-#include <iomanip>
-
namespace dawn::native {
-std::ostream& operator<<(std::ostream& os, const CacheKey& key) {
- os << std::hex;
- for (const int b : key) {
- os << std::setfill('0') << std::setw(2) << b << " ";
- }
- os << std::dec;
- return os;
-}
-
-template <>
-void CacheKeySerializer<std::string>::Serialize(CacheKey* key, const std::string& t) {
- key->Record(static_cast<size_t>(t.length()));
- key->insert(key->end(), t.begin(), t.end());
-}
-
template <>
-void CacheKeySerializer<CacheKey>::Serialize(CacheKey* key, const CacheKey& t) {
- // For nested cache keys, we do not record the length, and just copy the key so that it
- // appears we just flatten the keys into a single key.
- key->insert(key->end(), t.begin(), t.end());
+void stream::Stream<CacheKey>::Write(stream::Sink* sink, const CacheKey& t) {
+ StreamIn(sink, static_cast<const ByteVectorSink&>(t));
}
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/CacheKey.h b/chromium/third_party/dawn/src/dawn/native/CacheKey.h
index 357ce4b325b..6cec3b6b8f0 100644
--- a/chromium/third_party/dawn/src/dawn/native/CacheKey.h
+++ b/chromium/third_party/dawn/src/dawn/native/CacheKey.h
@@ -15,187 +15,41 @@
#ifndef SRC_DAWN_NATIVE_CACHEKEY_H_
#define SRC_DAWN_NATIVE_CACHEKEY_H_
-#include <bitset>
-#include <iostream>
-#include <limits>
-#include <string>
-#include <type_traits>
-#include <vector>
+#include <utility>
-#include "dawn/common/TypedInteger.h"
-#include "dawn/common/ityp_array.h"
+#include "dawn/native/stream/ByteVectorSink.h"
+#include "dawn/native/stream/Stream.h"
namespace dawn::native {
-// Forward declare classes because of co-dependency.
-class CacheKey;
-class CachedObject;
-
-// Stream operator for CacheKey for debugging.
-std::ostream& operator<<(std::ostream& os, const CacheKey& key);
-
-// Overridable serializer struct that should be implemented for cache key serializable
-// types/classes.
-template <typename T, typename SFINAE = void>
-class CacheKeySerializer {
- public:
- static void Serialize(CacheKey* key, const T& t);
-};
-
-class CacheKey : public std::vector<uint8_t> {
+class CacheKey : public stream::ByteVectorSink {
public:
- using std::vector<uint8_t>::vector;
+ using stream::ByteVectorSink::ByteVectorSink;
enum class Type { ComputePipeline, RenderPipeline, Shader };
template <typename T>
- CacheKey& Record(const T& t) {
- CacheKeySerializer<T>::Serialize(this, t);
- return *this;
- }
- template <typename T, typename... Args>
- CacheKey& Record(const T& t, const Args&... args) {
- CacheKeySerializer<T>::Serialize(this, t);
- return Record(args...);
- }
-
- // Records iterables by prepending the number of elements. Some common iterables are have a
- // CacheKeySerializer implemented to avoid needing to split them out when recording, i.e.
- // strings and CacheKeys, but they fundamentally do the same as this function.
- template <typename IterableT>
- CacheKey& RecordIterable(const IterableT& iterable) {
- // Always record the size of generic iterables as a size_t for now.
- Record(static_cast<size_t>(iterable.size()));
- for (auto it = iterable.begin(); it != iterable.end(); ++it) {
- Record(*it);
- }
- return *this;
- }
- template <typename Index, typename Value, size_t Size>
- CacheKey& RecordIterable(const ityp::array<Index, Value, Size>& iterable) {
- Record(static_cast<Index>(iterable.size()));
- for (auto it = iterable.begin(); it != iterable.end(); ++it) {
- Record(*it);
- }
- return *this;
- }
- template <typename Ptr>
- CacheKey& RecordIterable(const Ptr* ptr, size_t n) {
- Record(n);
- for (size_t i = 0; i < n; ++i) {
- Record(ptr[i]);
- }
- return *this;
- }
-};
-
-// Specialized overload for fundamental types.
-template <typename T>
-class CacheKeySerializer<T, std::enable_if_t<std::is_fundamental_v<T>>> {
- public:
- static void Serialize(CacheKey* key, const T t) {
- const char* it = reinterpret_cast<const char*>(&t);
- key->insert(key->end(), it, (it + sizeof(T)));
- }
-};
-
-// Specialized overload for bitsets that are smaller than 64.
-template <size_t N>
-class CacheKeySerializer<std::bitset<N>, std::enable_if_t<(N <= 64)>> {
- public:
- static void Serialize(CacheKey* key, const std::bitset<N>& t) { key->Record(t.to_ullong()); }
-};
-
-// Specialized overload for bitsets since using the built-in to_ullong have a size limit.
-template <size_t N>
-class CacheKeySerializer<std::bitset<N>, std::enable_if_t<(N > 64)>> {
- public:
- static void Serialize(CacheKey* key, const std::bitset<N>& t) {
- // Serializes the bitset into series of uint8_t, along with recording the size.
- static_assert(N > 0);
- key->Record(static_cast<size_t>(N));
- uint8_t value = 0;
- for (size_t i = 0; i < N; i++) {
- value <<= 1;
- // Explicitly convert to numeric since MSVC doesn't like mixing of bools.
- value |= t[i] ? 1 : 0;
- if (i % 8 == 7) {
- // Whenever we fill an 8 bit value, record it and zero it out.
- key->Record(value);
- value = 0;
- }
- }
- // Serialize the last value if we are not a multiple of 8.
- if (N % 8 != 0) {
- key->Record(value);
- }
- }
-};
-
-// Specialized overload for enums.
-template <typename T>
-class CacheKeySerializer<T, std::enable_if_t<std::is_enum_v<T>>> {
- public:
- static void Serialize(CacheKey* key, const T t) {
- CacheKeySerializer<std::underlying_type_t<T>>::Serialize(
- key, static_cast<std::underlying_type_t<T>>(t));
- }
-};
-
-// Specialized overload for TypedInteger.
-template <typename Tag, typename Integer>
-class CacheKeySerializer<::detail::TypedIntegerImpl<Tag, Integer>> {
- public:
- static void Serialize(CacheKey* key, const ::detail::TypedIntegerImpl<Tag, Integer> t) {
- CacheKeySerializer<Integer>::Serialize(key, static_cast<Integer>(t));
- }
-};
+ class UnsafeUnkeyedValue {
+ public:
+ UnsafeUnkeyedValue() = default;
+ // NOLINTNEXTLINE(runtime/explicit) allow implicit construction to decrease verbosity
+ UnsafeUnkeyedValue(T&& value) : mValue(std::forward<T>(value)) {}
-// Specialized overload for pointers. Since we are serializing for a cache key, we always
-// serialize via value, not by pointer. To handle nullptr scenarios, we always serialize whether
-// the pointer was nullptr followed by the contents if applicable.
-template <typename T>
-class CacheKeySerializer<T, std::enable_if_t<std::is_pointer_v<T>>> {
- public:
- static void Serialize(CacheKey* key, const T t) {
- key->Record(t == nullptr);
- if (t != nullptr) {
- CacheKeySerializer<std::remove_cv_t<std::remove_pointer_t<T>>>::Serialize(key, *t);
- }
- }
-};
+ const T& UnsafeGetValue() const { return mValue; }
-// Specialized overload for fixed arrays of primitives.
-template <typename T, size_t N>
-class CacheKeySerializer<T[N], std::enable_if_t<std::is_fundamental_v<T>>> {
- public:
- static void Serialize(CacheKey* key, const T (&t)[N]) {
- static_assert(N > 0);
- key->Record(static_cast<size_t>(N));
- const char* it = reinterpret_cast<const char*>(t);
- key->insert(key->end(), it, it + sizeof(t));
- }
-};
+ // Friend definition of StreamIn which can be found by ADL to override
+ // stream::StreamIn<T>.
+ friend constexpr void StreamIn(stream::Sink*, const UnsafeUnkeyedValue&) {}
-// Specialized overload for fixed arrays of non-primitives.
-template <typename T, size_t N>
-class CacheKeySerializer<T[N], std::enable_if_t<!std::is_fundamental_v<T>>> {
- public:
- static void Serialize(CacheKey* key, const T (&t)[N]) {
- static_assert(N > 0);
- key->Record(static_cast<size_t>(N));
- for (size_t i = 0; i < N; i++) {
- key->Record(t[i]);
- }
- }
+ private:
+ T mValue;
+ };
};
-// Specialized overload for CachedObjects.
template <typename T>
-class CacheKeySerializer<T, std::enable_if_t<std::is_base_of_v<CachedObject, T>>> {
- public:
- static void Serialize(CacheKey* key, const T& t) { key->Record(t.GetCacheKey()); }
-};
+CacheKey::UnsafeUnkeyedValue<T> UnsafeUnkeyedValue(T&& value) {
+ return CacheKey::UnsafeUnkeyedValue<T>(std::forward<T>(value));
+}
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/include/dawn/dawn_wsi.h b/chromium/third_party/dawn/src/dawn/native/CacheRequest.cpp
index 3803d3911d1..2b35b1224d3 100644
--- a/chromium/third_party/dawn/src/include/dawn/dawn_wsi.h
+++ b/chromium/third_party/dawn/src/dawn/native/CacheRequest.cpp
@@ -12,9 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_INCLUDE_DAWN_DAWN_WSI_H_
-#define SRC_INCLUDE_DAWN_DAWN_WSI_H_
+#include "dawn/native/CacheRequest.h"
-#include "dawn/dawn_wsi.h"
+#include "dawn/common/Log.h"
-#endif // SRC_INCLUDE_DAWN_DAWN_WSI_H_
+namespace dawn::native::detail {
+
+void LogCacheHitError(std::unique_ptr<ErrorData> error) {
+ dawn::ErrorLog() << error->GetFormattedMessage();
+}
+
+} // namespace dawn::native::detail
diff --git a/chromium/third_party/dawn/src/dawn/native/CacheRequest.h b/chromium/third_party/dawn/src/dawn/native/CacheRequest.h
new file mode 100644
index 00000000000..2999449b7d5
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/CacheRequest.h
@@ -0,0 +1,193 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_CACHEREQUEST_H_
+#define SRC_DAWN_NATIVE_CACHEREQUEST_H_
+
+#include <memory>
+#include <utility>
+
+#include "dawn/common/Assert.h"
+#include "dawn/common/Compiler.h"
+#include "dawn/native/Blob.h"
+#include "dawn/native/BlobCache.h"
+#include "dawn/native/CacheKey.h"
+#include "dawn/native/CacheResult.h"
+#include "dawn/native/Device.h"
+#include "dawn/native/Error.h"
+#include "dawn/native/VisitableMembers.h"
+
+namespace dawn::native {
+
+namespace detail {
+
+template <typename T>
+struct UnwrapResultOrError {
+ using type = T;
+};
+
+template <typename T>
+struct UnwrapResultOrError<ResultOrError<T>> {
+ using type = T;
+};
+
+template <typename T>
+struct IsResultOrError {
+ static constexpr bool value = false;
+};
+
+template <typename T>
+struct IsResultOrError<ResultOrError<T>> {
+ static constexpr bool value = true;
+};
+
+void LogCacheHitError(std::unique_ptr<ErrorData> error);
+
+} // namespace detail
+
+// Implementation of a CacheRequest which provides a LoadOrRun friend function which can be found
+// via argument-dependent lookup. So, it doesn't need to be called with a fully qualified function
+// name.
+//
+// Example usage:
+// Request r = { ... };
+// ResultOrError<CacheResult<T>> cacheResult =
+// LoadOrRun(device, std::move(r),
+// [](Blob blob) -> T { /* handle cache hit */ },
+// [](Request r) -> ResultOrError<T> { /* handle cache miss */ }
+// );
+// Or with free functions:
+/// T OnCacheHit(Blob blob) { ... }
+// ResultOrError<T> OnCacheMiss(Request r) { ... }
+// // ...
+// Request r = { ... };
+// auto result = LoadOrRun(device, std::move(r), OnCacheHit, OnCacheMiss);
+//
+// LoadOrRun generates a CacheKey from the request and loads from the device's BlobCache. On cache
+// hit, calls CacheHitFn and returns a CacheResult<T>. On cache miss or if CacheHitFn returned an
+// Error, calls CacheMissFn -> ResultOrError<T> with the request data and returns a
+// ResultOrError<CacheResult<T>>. CacheHitFn must return the same unwrapped type as CacheMissFn.
+// i.e. it doesn't need to be wrapped in ResultOrError.
+//
+// CacheMissFn may not have any additional data bound to it. It may not be a lambda or std::function
+// which captures additional information, so it can only operate on the request data. This is
+// enforced with a compile-time static_assert, and ensures that the result created from the
+// computation is exactly the data included in the CacheKey.
+template <typename Request>
+class CacheRequestImpl {
+ public:
+ CacheRequestImpl() = default;
+
+ // Require CacheRequests to be move-only to avoid unnecessary copies.
+ CacheRequestImpl(CacheRequestImpl&&) = default;
+ CacheRequestImpl& operator=(CacheRequestImpl&&) = default;
+ CacheRequestImpl(const CacheRequestImpl&) = delete;
+ CacheRequestImpl& operator=(const CacheRequestImpl&) = delete;
+
+ // Create a CacheKey from the request type and all members
+ CacheKey CreateCacheKey(const DeviceBase* device) const {
+ CacheKey key = device->GetCacheKey();
+ StreamIn(&key, Request::kName);
+ static_cast<const Request*>(this)->VisitAll(
+ [&](const auto&... members) { StreamIn(&key, members...); });
+ return key;
+ }
+
+ template <typename CacheHitFn, typename CacheMissFn>
+ friend auto LoadOrRun(DeviceBase* device,
+ Request&& r,
+ CacheHitFn cacheHitFn,
+ CacheMissFn cacheMissFn) {
+ // Get return types and check that CacheMissReturnType can be cast to a raw function
+ // pointer. This means it's not a std::function or lambda that captures additional data.
+ using CacheHitReturnType = decltype(cacheHitFn(std::declval<Blob>()));
+ using CacheMissReturnType = decltype(cacheMissFn(std::declval<Request>()));
+ static_assert(
+ std::is_convertible_v<CacheMissFn, CacheMissReturnType (*)(Request)>,
+ "CacheMissFn function signature does not match, or it is not a free function.");
+
+ static_assert(detail::IsResultOrError<CacheMissReturnType>::value,
+ "CacheMissFn should return a ResultOrError.");
+ using UnwrappedReturnType = typename detail::UnwrapResultOrError<CacheMissReturnType>::type;
+
+ static_assert(std::is_same_v<typename detail::UnwrapResultOrError<CacheHitReturnType>::type,
+ UnwrappedReturnType>,
+ "If CacheMissFn returns T, CacheHitFn must return T or ResultOrError<T>.");
+
+ using CacheResultType = CacheResult<UnwrappedReturnType>;
+ using ReturnType = ResultOrError<CacheResultType>;
+
+ CacheKey key = r.CreateCacheKey(device);
+ BlobCache* cache = device->GetBlobCache();
+ Blob blob;
+ if (cache != nullptr) {
+ blob = cache->Load(key);
+ }
+
+ if (!blob.Empty()) {
+ // Cache hit. Handle the cached blob.
+ auto result = cacheHitFn(std::move(blob));
+
+ if constexpr (!detail::IsResultOrError<CacheHitReturnType>::value) {
+ // If the result type is not a ResultOrError, return it.
+ return ReturnType(CacheResultType::CacheHit(std::move(key), std::move(result)));
+ } else {
+ // Otherwise, if the value is a success, also return it.
+ if (DAWN_LIKELY(result.IsSuccess())) {
+ return ReturnType(
+ CacheResultType::CacheHit(std::move(key), result.AcquireSuccess()));
+ }
+ // On error, continue to the cache miss path and log the error.
+ detail::LogCacheHitError(result.AcquireError());
+ }
+ }
+ // Cache miss, or the CacheHitFn failed.
+ auto result = cacheMissFn(std::move(r));
+ if (DAWN_LIKELY(result.IsSuccess())) {
+ return ReturnType(CacheResultType::CacheMiss(std::move(key), result.AcquireSuccess()));
+ }
+ return ReturnType(result.AcquireError());
+ }
+};
+
+} // namespace dawn::native
+
+// Helper for X macro to declare a struct member.
+#define DAWN_INTERNAL_CACHE_REQUEST_DECL_STRUCT_MEMBER(type, name) type name{};
+
+// Helper for X macro for recording cache request fields into a CacheKey.
+#define DAWN_INTERNAL_CACHE_REQUEST_RECORD_KEY(type, name) StreamIn(&key, name);
+
+// Helper X macro to define a CacheRequest struct.
+// Example usage:
+// #define REQUEST_MEMBERS(X) \
+// X(int, a) \
+// X(float, b) \
+// X(Foo, foo) \
+// X(Bar, bar)
+// DAWN_MAKE_CACHE_REQUEST(MyCacheRequest, REQUEST_MEMBERS)
+// #undef REQUEST_MEMBERS
+#define DAWN_MAKE_CACHE_REQUEST(Request, MEMBERS) \
+ class Request : public ::dawn::native::CacheRequestImpl<Request> { \
+ public: \
+ static constexpr char kName[] = #Request; \
+ Request() = default; \
+ DAWN_VISITABLE_MEMBERS(MEMBERS) \
+ };
+
+// Helper macro for the common pattern of DAWN_TRY_ASSIGN around LoadOrRun.
+// Requires an #include of dawn/native/Error.h
+#define DAWN_TRY_LOAD_OR_RUN(var, ...) DAWN_TRY_ASSIGN(var, LoadOrRun(__VA_ARGS__))
+
+#endif // SRC_DAWN_NATIVE_CACHEREQUEST_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/CacheResult.h b/chromium/third_party/dawn/src/dawn/native/CacheResult.h
new file mode 100644
index 00000000000..138d9f81518
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/CacheResult.h
@@ -0,0 +1,77 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_CACHERESULT_H_
+#define SRC_DAWN_NATIVE_CACHERESULT_H_
+
+#include <memory>
+#include <utility>
+
+#include "dawn/common/Assert.h"
+#include "dawn/native/CacheKey.h"
+
+namespace dawn::native {
+
+template <typename T>
+class CacheResult {
+ public:
+ static CacheResult CacheHit(CacheKey key, T value) {
+ return CacheResult(std::move(key), std::move(value), true);
+ }
+
+ static CacheResult CacheMiss(CacheKey key, T value) {
+ return CacheResult(std::move(key), std::move(value), false);
+ }
+
+ CacheResult() : mKey(), mValue(), mIsCached(false), mIsValid(false) {}
+
+ bool IsCached() const {
+ ASSERT(mIsValid);
+ return mIsCached;
+ }
+ const CacheKey& GetCacheKey() const {
+ ASSERT(mIsValid);
+ return mKey;
+ }
+
+ // Note: Getting mValue is always const, since mutating it would invalidate consistency with
+ // mKey.
+ const T* operator->() const {
+ ASSERT(mIsValid);
+ return &mValue;
+ }
+ const T& operator*() const {
+ ASSERT(mIsValid);
+ return mValue;
+ }
+
+ T Acquire() {
+ ASSERT(mIsValid);
+ mIsValid = false;
+ return std::move(mValue);
+ }
+
+ private:
+ CacheResult(CacheKey key, T value, bool isCached)
+ : mKey(std::move(key)), mValue(std::move(value)), mIsCached(isCached), mIsValid(true) {}
+
+ CacheKey mKey;
+ T mValue;
+ bool mIsCached;
+ bool mIsValid;
+};
+
+} // namespace dawn::native
+
+#endif // SRC_DAWN_NATIVE_CACHERESULT_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/CachedObject.cpp b/chromium/third_party/dawn/src/dawn/native/CachedObject.cpp
index 5fa6a0affd9..249b0d6b375 100644
--- a/chromium/third_party/dawn/src/dawn/native/CachedObject.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/CachedObject.cpp
@@ -46,4 +46,10 @@ const CacheKey& CachedObject::GetCacheKey() const {
return mCacheKey;
}
+// static
+template <>
+void stream::Stream<CachedObject>::Write(stream::Sink* sink, const CachedObject& obj) {
+ StreamIn(sink, obj.GetCacheKey());
+}
+
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/CommandEncoder.cpp b/chromium/third_party/dawn/src/dawn/native/CommandEncoder.cpp
index 197e0c0c1a0..9bb8c0dd869 100644
--- a/chromium/third_party/dawn/src/dawn/native/CommandEncoder.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/CommandEncoder.cpp
@@ -20,6 +20,7 @@
#include "dawn/common/BitSetIterator.h"
#include "dawn/common/Math.h"
+#include "dawn/native/ApplyClearColorValueWithDrawHelper.h"
#include "dawn/native/BindGroup.h"
#include "dawn/native/Buffer.h"
#include "dawn/native/ChainUtils_autogen.h"
@@ -44,11 +45,6 @@ namespace dawn::native {
namespace {
-bool HasDeprecatedColor(const RenderPassColorAttachment& attachment) {
- return !std::isnan(attachment.clearColor.r) || !std::isnan(attachment.clearColor.g) ||
- !std::isnan(attachment.clearColor.b) || !std::isnan(attachment.clearColor.a);
-}
-
MaybeError ValidateB2BCopyAlignment(uint64_t dataSize, uint64_t srcOffset, uint64_t dstOffset) {
// Copy size must be a multiple of 4 bytes on macOS.
DAWN_INVALID_IF(dataSize % 4 != 0, "Copy size (%u) is not a multiple of 4.", dataSize);
@@ -92,7 +88,6 @@ MaybeError ValidateTextureDepthStencilToBufferCopyRestrictions(const ImageCopyTe
switch (src.texture->GetFormat().format) {
case wgpu::TextureFormat::Depth24Plus:
case wgpu::TextureFormat::Depth24PlusStencil8:
- case wgpu::TextureFormat::Depth24UnormStencil8:
return DAWN_FORMAT_VALIDATION_ERROR(
"The depth aspect of %s format %s cannot be selected in a texture to "
"buffer copy.",
@@ -383,10 +378,16 @@ MaybeError ValidateRenderPassDepthStencilAttachment(
if (!std::isnan(depthStencilAttachment->clearDepth)) {
// TODO(dawn:1269): Remove this branch after the deprecation period.
device->EmitDeprecationWarning("clearDepth is deprecated, prefer depthClearValue instead.");
- } else {
- DAWN_INVALID_IF(depthStencilAttachment->depthLoadOp == wgpu::LoadOp::Clear &&
- std::isnan(depthStencilAttachment->depthClearValue),
+ DAWN_INVALID_IF(
+ depthStencilAttachment->clearDepth < 0.0f || depthStencilAttachment->clearDepth > 1.0f,
+ "clearDepth is not between 0.0 and 1.0");
+
+ } else if (depthStencilAttachment->depthLoadOp == wgpu::LoadOp::Clear) {
+ DAWN_INVALID_IF(std::isnan(depthStencilAttachment->depthClearValue),
"depthClearValue is NaN.");
+ DAWN_INVALID_IF(depthStencilAttachment->depthClearValue < 0.0f ||
+ depthStencilAttachment->depthClearValue > 1.0f,
+ "depthClearValue is not between 0.0 and 1.0");
}
// TODO(dawn:1269): Remove after the deprecation period.
@@ -445,10 +446,14 @@ MaybeError ValidateRenderPassDescriptor(DeviceBase* device,
uint32_t* height,
uint32_t* sampleCount,
UsageValidationMode usageValidationMode) {
+ DAWN_TRY(ValidateSingleSType(descriptor->nextInChain,
+ wgpu::SType::RenderPassDescriptorMaxDrawCount));
+
+ uint32_t maxColorAttachments = device->GetLimits().v1.maxColorAttachments;
DAWN_INVALID_IF(
- descriptor->colorAttachmentCount > kMaxColorAttachments,
+ descriptor->colorAttachmentCount > maxColorAttachments,
"Color attachment count (%u) exceeds the maximum number of color attachments (%u).",
- descriptor->colorAttachmentCount, kMaxColorAttachments);
+ descriptor->colorAttachmentCount, maxColorAttachments);
bool isAllColorAttachmentNull = true;
for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) {
@@ -647,6 +652,45 @@ bool IsReadOnlyDepthStencilAttachment(
} // namespace
+bool HasDeprecatedColor(const RenderPassColorAttachment& attachment) {
+ return !std::isnan(attachment.clearColor.r) || !std::isnan(attachment.clearColor.g) ||
+ !std::isnan(attachment.clearColor.b) || !std::isnan(attachment.clearColor.a);
+}
+
+Color ClampClearColorValueToLegalRange(const Color& originalColor, const Format& format) {
+ const AspectInfo& aspectInfo = format.GetAspectInfo(Aspect::Color);
+ double minValue = 0;
+ double maxValue = 0;
+ switch (aspectInfo.baseType) {
+ case wgpu::TextureComponentType::Float: {
+ return originalColor;
+ }
+ case wgpu::TextureComponentType::Sint: {
+ const uint32_t bitsPerComponent =
+ (aspectInfo.block.byteSize * 8 / format.componentCount);
+ maxValue =
+ static_cast<double>((static_cast<uint64_t>(1) << (bitsPerComponent - 1)) - 1);
+ minValue = -static_cast<double>(static_cast<uint64_t>(1) << (bitsPerComponent - 1));
+ break;
+ }
+ case wgpu::TextureComponentType::Uint: {
+ const uint32_t bitsPerComponent =
+ (aspectInfo.block.byteSize * 8 / format.componentCount);
+ maxValue = static_cast<double>((static_cast<uint64_t>(1) << bitsPerComponent) - 1);
+ break;
+ }
+ case wgpu::TextureComponentType::DepthComparison:
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return {std::clamp(originalColor.r, minValue, maxValue),
+ std::clamp(originalColor.g, minValue, maxValue),
+ std::clamp(originalColor.b, minValue, maxValue),
+ std::clamp(originalColor.a, minValue, maxValue)};
+}
+
MaybeError ValidateCommandEncoderDescriptor(const DeviceBase* device,
const CommandEncoderDescriptor* descriptor) {
DAWN_TRY(ValidateSingleSType(descriptor->nextInChain,
@@ -735,8 +779,6 @@ ComputePassEncoder* CommandEncoder::APIBeginComputePass(const ComputePassDescrip
Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) {
DeviceBase* device = GetDevice();
- std::vector<TimestampWrite> timestampWritesAtBeginning;
- std::vector<TimestampWrite> timestampWritesAtEnd;
bool success = mEncodingContext.TryEncode(
this,
[&](CommandAllocator* allocator) -> MaybeError {
@@ -749,27 +791,27 @@ Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescri
return {};
}
- // Split the timestampWrites used in BeginComputePassCmd and EndComputePassCmd
+ // Record timestamp writes at the beginning and end of compute pass. The timestamp write
+ // at the end also be needed in BeginComputePassCmd because it's required by compute
+ // pass descriptor when beginning compute pass on Metal.
for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
switch (descriptor->timestampWrites[i].location) {
case wgpu::ComputePassTimestampLocation::Beginning:
- timestampWritesAtBeginning.push_back({querySet, queryIndex});
+ cmd->beginTimestamp.querySet = querySet;
+ cmd->beginTimestamp.queryIndex = queryIndex;
break;
case wgpu::ComputePassTimestampLocation::End:
- timestampWritesAtEnd.push_back({querySet, queryIndex});
- break;
- default:
+ cmd->endTimestamp.querySet = querySet;
+ cmd->endTimestamp.queryIndex = queryIndex;
break;
}
TrackQueryAvailability(querySet, queryIndex);
}
- cmd->timestampWrites = std::move(timestampWritesAtBeginning);
-
return {};
},
"encoding %s.BeginComputePass(%s).", this, descriptor);
@@ -780,8 +822,8 @@ Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescri
descriptor = &defaultDescriptor;
}
- Ref<ComputePassEncoder> passEncoder = ComputePassEncoder::Create(
- device, descriptor, this, &mEncodingContext, std::move(timestampWritesAtEnd));
+ Ref<ComputePassEncoder> passEncoder =
+ ComputePassEncoder::Create(device, descriptor, this, &mEncodingContext);
mEncodingContext.EnterPass(passEncoder.Get());
return passEncoder;
}
@@ -803,8 +845,6 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
bool depthReadOnly = false;
bool stencilReadOnly = false;
Ref<AttachmentState> attachmentState;
- std::vector<TimestampWrite> timestampWritesAtBeginning;
- std::vector<TimestampWrite> timestampWritesAtEnd;
bool success = mEncodingContext.TryEncode(
this,
[&](CommandAllocator* allocator) -> MaybeError {
@@ -822,28 +862,6 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
attachmentState = cmd->attachmentState;
- // Split the timestampWrites used in BeginRenderPassCmd and EndRenderPassCmd
- for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
- QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
- uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
-
- switch (descriptor->timestampWrites[i].location) {
- case wgpu::RenderPassTimestampLocation::Beginning:
- timestampWritesAtBeginning.push_back({querySet, queryIndex});
- break;
- case wgpu::RenderPassTimestampLocation::End:
- timestampWritesAtEnd.push_back({querySet, queryIndex});
- break;
- default:
- break;
- }
-
- TrackQueryAvailability(querySet, queryIndex);
- // Track the query availability with true on render pass again for rewrite
- // validation and query reset on Vulkan
- usageTracker.TrackQueryAvailability(querySet, queryIndex);
- }
-
for (ColorAttachmentIndex index :
IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
uint8_t i = static_cast<uint8_t>(index);
@@ -855,10 +873,12 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
cmd->colorAttachments[index].loadOp = descriptor->colorAttachments[i].loadOp;
cmd->colorAttachments[index].storeOp = descriptor->colorAttachments[i].storeOp;
+ Color color = HasDeprecatedColor(descriptor->colorAttachments[i])
+ ? descriptor->colorAttachments[i].clearColor
+ : descriptor->colorAttachments[i].clearValue;
+
cmd->colorAttachments[index].clearColor =
- HasDeprecatedColor(descriptor->colorAttachments[i])
- ? descriptor->colorAttachments[i].clearColor
- : descriptor->colorAttachments[i].clearValue;
+ ClampClearColorValueToLegalRange(color, view->GetFormat());
usageTracker.TextureViewUsedAs(view, wgpu::TextureUsage::RenderAttachment);
@@ -945,7 +965,29 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
cmd->occlusionQuerySet = descriptor->occlusionQuerySet;
- cmd->timestampWrites = std::move(timestampWritesAtBeginning);
+ // Record timestamp writes at the beginning and end of render pass. The timestamp write
+ // at the end also be needed in BeginComputePassCmd because it's required by render pass
+ // descriptor when beginning render pass on Metal.
+ for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
+ QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
+ uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
+
+ switch (descriptor->timestampWrites[i].location) {
+ case wgpu::RenderPassTimestampLocation::Beginning:
+ cmd->beginTimestamp.querySet = querySet;
+ cmd->beginTimestamp.queryIndex = queryIndex;
+ break;
+ case wgpu::RenderPassTimestampLocation::End:
+ cmd->endTimestamp.querySet = querySet;
+ cmd->endTimestamp.queryIndex = queryIndex;
+ break;
+ }
+
+ TrackQueryAvailability(querySet, queryIndex);
+ // Track the query availability with true on render pass again for rewrite
+ // validation and query reset on Vulkan
+ usageTracker.TrackQueryAvailability(querySet, queryIndex);
+ }
return {};
},
@@ -954,9 +996,17 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
if (success) {
Ref<RenderPassEncoder> passEncoder = RenderPassEncoder::Create(
device, descriptor, this, &mEncodingContext, std::move(usageTracker),
- std::move(attachmentState), std::move(timestampWritesAtEnd), width, height,
- depthReadOnly, stencilReadOnly);
+ std::move(attachmentState), width, height, depthReadOnly, stencilReadOnly);
mEncodingContext.EnterPass(passEncoder.Get());
+
+ if (ShouldApplyClearBigIntegerColorValueWithDraw(device, descriptor)) {
+ MaybeError error =
+ ApplyClearBigIntegerColorValueWithDraw(passEncoder.Get(), descriptor);
+ if (error.IsError()) {
+ return RenderPassEncoder::MakeError(device, this, &mEncodingContext);
+ }
+ }
+
return passEncoder;
}
diff --git a/chromium/third_party/dawn/src/dawn/native/CommandEncoder.h b/chromium/third_party/dawn/src/dawn/native/CommandEncoder.h
index 79e6e96f348..e43c6e77ce2 100644
--- a/chromium/third_party/dawn/src/dawn/native/CommandEncoder.h
+++ b/chromium/third_party/dawn/src/dawn/native/CommandEncoder.h
@@ -29,6 +29,10 @@ namespace dawn::native {
enum class UsageValidationMode;
+bool HasDeprecatedColor(const RenderPassColorAttachment& attachment);
+
+Color ClampClearColorValueToLegalRange(const Color& originalColor, const Format& format);
+
MaybeError ValidateCommandEncoderDescriptor(const DeviceBase* device,
const CommandEncoderDescriptor* descriptor);
diff --git a/chromium/third_party/dawn/src/dawn/native/CommandValidation.cpp b/chromium/third_party/dawn/src/dawn/native/CommandValidation.cpp
index 723f658d1fa..d0bdb0c3b03 100644
--- a/chromium/third_party/dawn/src/dawn/native/CommandValidation.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/CommandValidation.cpp
@@ -471,7 +471,6 @@ MaybeError ValidateCanUseAs(const TextureBase* texture,
texture->GetInternalUsage(), usage);
break;
}
-
return {};
}
diff --git a/chromium/third_party/dawn/src/dawn/native/CommandValidation.h b/chromium/third_party/dawn/src/dawn/native/CommandValidation.h
index ede6b310b4a..bf4e8aabef5 100644
--- a/chromium/third_party/dawn/src/dawn/native/CommandValidation.h
+++ b/chromium/third_party/dawn/src/dawn/native/CommandValidation.h
@@ -20,6 +20,7 @@
#include "dawn/native/CommandAllocator.h"
#include "dawn/native/Error.h"
#include "dawn/native/Texture.h"
+#include "dawn/native/UsageValidationMode.h"
namespace dawn::native {
@@ -82,11 +83,6 @@ MaybeError ValidateTextureToTextureCopyRestrictions(const ImageCopyTexture& src,
const ImageCopyTexture& dst,
const Extent3D& copySize);
-enum class UsageValidationMode {
- Default,
- Internal,
-};
-
MaybeError ValidateCanUseAs(const TextureBase* texture,
wgpu::TextureUsage usage,
UsageValidationMode mode);
diff --git a/chromium/third_party/dawn/src/dawn/native/Commands.cpp b/chromium/third_party/dawn/src/dawn/native/Commands.cpp
index 6f3d6df4674..c1be63922fd 100644
--- a/chromium/third_party/dawn/src/dawn/native/Commands.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Commands.cpp
@@ -361,9 +361,7 @@ void SkipCommand(CommandIterator* commands, Command type) {
}
}
-TimestampWrite::TimestampWrite(const Ref<QuerySetBase>& set, uint32_t idx)
- : querySet(set), queryIndex(idx) {}
-TimestampWrite::TimestampWrite(TimestampWrite&&) = default;
+TimestampWrite::TimestampWrite() = default;
TimestampWrite::~TimestampWrite() = default;
BeginComputePassCmd::BeginComputePassCmd() = default;
diff --git a/chromium/third_party/dawn/src/dawn/native/Commands.h b/chromium/third_party/dawn/src/dawn/native/Commands.h
index c7bfa042113..456a1b5961d 100644
--- a/chromium/third_party/dawn/src/dawn/native/Commands.h
+++ b/chromium/third_party/dawn/src/dawn/native/Commands.h
@@ -70,8 +70,7 @@ enum class Command {
};
struct TimestampWrite {
- TimestampWrite(const Ref<QuerySetBase>& set, uint32_t idx);
- TimestampWrite(TimestampWrite&&);
+ TimestampWrite();
~TimestampWrite();
Ref<QuerySetBase> querySet;
@@ -82,7 +81,8 @@ struct BeginComputePassCmd {
BeginComputePassCmd();
~BeginComputePassCmd();
- std::vector<TimestampWrite> timestampWrites;
+ TimestampWrite beginTimestamp;
+ TimestampWrite endTimestamp;
};
struct BeginOcclusionQueryCmd {
@@ -133,7 +133,8 @@ struct BeginRenderPassCmd {
uint32_t height;
Ref<QuerySetBase> occlusionQuerySet;
- std::vector<TimestampWrite> timestampWrites;
+ TimestampWrite beginTimestamp;
+ TimestampWrite endTimestamp;
};
struct BufferCopy {
@@ -228,8 +229,6 @@ struct DrawIndexedIndirectCmd : DrawIndirectCmd {};
struct EndComputePassCmd {
EndComputePassCmd();
~EndComputePassCmd();
-
- std::vector<TimestampWrite> timestampWrites;
};
struct EndOcclusionQueryCmd {
@@ -243,8 +242,6 @@ struct EndOcclusionQueryCmd {
struct EndRenderPassCmd {
EndRenderPassCmd();
~EndRenderPassCmd();
-
- std::vector<TimestampWrite> timestampWrites;
};
struct ExecuteBundlesCmd {
diff --git a/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.cpp b/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.cpp
index e70aea31935..65d00cbc910 100644
--- a/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.cpp
@@ -46,23 +46,23 @@ ResultOrError<ComputePipelineBase*> GetOrCreateIndirectDispatchValidationPipelin
Ref<ShaderModuleBase> shaderModule;
DAWN_TRY_ASSIGN(shaderModule, utils::CreateShaderModule(device, R"(
struct UniformParams {
- maxComputeWorkgroupsPerDimension: u32;
- clientOffsetInU32: u32;
- enableValidation: u32;
- duplicateNumWorkgroups: u32;
- };
+ maxComputeWorkgroupsPerDimension: u32,
+ clientOffsetInU32: u32,
+ enableValidation: u32,
+ duplicateNumWorkgroups: u32,
+ }
struct IndirectParams {
- data: array<u32>;
- };
+ data: array<u32>
+ }
struct ValidatedParams {
- data: array<u32>;
- };
+ data: array<u32>
+ }
@group(0) @binding(0) var<uniform> uniformParams: UniformParams;
@group(0) @binding(1) var<storage, read_write> clientParams: IndirectParams;
- @group(0) @binding(2) var<storage, write> validatedParams: ValidatedParams;
+ @group(0) @binding(2) var<storage, read_write> validatedParams: ValidatedParams;
@compute @workgroup_size(1, 1, 1)
fn main() {
@@ -111,23 +111,18 @@ ResultOrError<ComputePipelineBase*> GetOrCreateIndirectDispatchValidationPipelin
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
const ComputePassDescriptor* descriptor,
CommandEncoder* commandEncoder,
- EncodingContext* encodingContext,
- std::vector<TimestampWrite> timestampWritesAtEnd)
+ EncodingContext* encodingContext)
: ProgrammableEncoder(device, descriptor->label, encodingContext),
- mCommandEncoder(commandEncoder),
- mTimestampWritesAtEnd(std::move(timestampWritesAtEnd)) {
+ mCommandEncoder(commandEncoder) {
TrackInDevice();
}
// static
-Ref<ComputePassEncoder> ComputePassEncoder::Create(
- DeviceBase* device,
- const ComputePassDescriptor* descriptor,
- CommandEncoder* commandEncoder,
- EncodingContext* encodingContext,
- std::vector<TimestampWrite> timestampWritesAtEnd) {
- return AcquireRef(new ComputePassEncoder(device, descriptor, commandEncoder, encodingContext,
- std::move(timestampWritesAtEnd)));
+Ref<ComputePassEncoder> ComputePassEncoder::Create(DeviceBase* device,
+ const ComputePassDescriptor* descriptor,
+ CommandEncoder* commandEncoder,
+ EncodingContext* encodingContext) {
+ return AcquireRef(new ComputePassEncoder(device, descriptor, commandEncoder, encodingContext));
}
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
@@ -162,11 +157,7 @@ void ComputePassEncoder::APIEnd() {
DAWN_TRY(ValidateProgrammableEncoderEnd());
}
- EndComputePassCmd* cmd =
- allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
- // The query availability has already been updated at the beginning of compute
- // pass, and no need to do update here.
- cmd->timestampWrites = std::move(mTimestampWritesAtEnd);
+ allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
return {};
},
@@ -306,7 +297,8 @@ ComputePassEncoder::TransformIndirectDispatchBuffer(Ref<BufferBase> indirectBuff
{1, indirectBuffer, clientIndirectBindingOffset,
clientIndirectBindingSize},
{2, validatedIndirectBuffer, 0, scratchBufferSize},
- }));
+ },
+ UsageValidationMode::Internal));
// Issue commands to validate the indirect buffer.
APISetPipeline(validationPipeline.Get());
diff --git a/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.h b/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.h
index ad950964b2b..f48ef94cb7a 100644
--- a/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.h
+++ b/chromium/third_party/dawn/src/dawn/native/ComputePassEncoder.h
@@ -33,8 +33,7 @@ class ComputePassEncoder final : public ProgrammableEncoder {
static Ref<ComputePassEncoder> Create(DeviceBase* device,
const ComputePassDescriptor* descriptor,
CommandEncoder* commandEncoder,
- EncodingContext* encodingContext,
- std::vector<TimestampWrite> timestampWritesAtEnd);
+ EncodingContext* encodingContext);
static Ref<ComputePassEncoder> MakeError(DeviceBase* device,
CommandEncoder* commandEncoder,
EncodingContext* encodingContext);
@@ -72,8 +71,7 @@ class ComputePassEncoder final : public ProgrammableEncoder {
ComputePassEncoder(DeviceBase* device,
const ComputePassDescriptor* descriptor,
CommandEncoder* commandEncoder,
- EncodingContext* encodingContext,
- std::vector<TimestampWrite> timestampWritesAtEnd);
+ EncodingContext* encodingContext);
ComputePassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder,
EncodingContext* encodingContext,
@@ -98,8 +96,6 @@ class ComputePassEncoder final : public ProgrammableEncoder {
// For render and compute passes, the encoding context is borrowed from the command encoder.
// Keep a reference to the encoder to make sure the context isn't freed.
Ref<CommandEncoder> mCommandEncoder;
-
- std::vector<TimestampWrite> mTimestampWritesAtEnd;
};
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/ComputePipeline.cpp b/chromium/third_party/dawn/src/dawn/native/ComputePipeline.cpp
index a1dcf15a481..b0b574d0434 100644
--- a/chromium/third_party/dawn/src/dawn/native/ComputePipeline.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/ComputePipeline.cpp
@@ -50,7 +50,7 @@ ComputePipelineBase::ComputePipelineBase(DeviceBase* device,
TrackInDevice();
// Initialize the cache key to include the cache type and device information.
- mCacheKey.Record(CacheKey::Type::ComputePipeline, device->GetCacheKey());
+ StreamIn(&mCacheKey, CacheKey::Type::ComputePipeline, device->GetCacheKey());
}
ComputePipelineBase::ComputePipelineBase(DeviceBase* device) : PipelineBase(device) {
diff --git a/chromium/third_party/dawn/src/dawn/native/CopyTextureForBrowserHelper.cpp b/chromium/third_party/dawn/src/dawn/native/CopyTextureForBrowserHelper.cpp
index 48cf6e66551..f8cece17da6 100644
--- a/chromium/third_party/dawn/src/dawn/native/CopyTextureForBrowserHelper.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/CopyTextureForBrowserHelper.cpp
@@ -145,9 +145,11 @@ static const char sCopyTextureForBrowserShader[] = R"(
let kEncodeToGammaStep = 0x08u;
let kPremultiplyStep = 0x10u;
let kDecodeForSrgbDstFormat = 0x20u;
+ let kClearSrcAlphaToOne = 0x40u;
// Unpremultiply step. Appling color space conversion op on premultiplied source texture
// also needs to unpremultiply first.
+ // This step is exclusive with clear src alpha to one step.
if (bool(uniforms.steps_mask & kUnpremultiplyStep)) {
if (color.a != 0.0) {
color = vec4<f32>(color.rgb / color.a, color.a);
@@ -180,6 +182,7 @@ static const char sCopyTextureForBrowserShader[] = R"(
}
// Premultiply step.
+ // This step is exclusive with clear src alpha to one step.
if (bool(uniforms.steps_mask & kPremultiplyStep)) {
color = vec4<f32>(color.rgb * color.a, color.a);
}
@@ -192,6 +195,12 @@ static const char sCopyTextureForBrowserShader[] = R"(
color.a);
}
+ // Clear alpha to one step.
+ // This step is exclusive with premultiply/unpremultiply step.
+ if (bool(uniforms.steps_mask & kClearSrcAlphaToOne)) {
+ color.a = 1.0;
+ }
+
return color;
}
)";
@@ -230,6 +239,7 @@ MaybeError ValidateCopyTextureFormatConversion(const wgpu::TextureFormat srcForm
switch (srcFormat) {
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::RGBA8Unorm:
+ case wgpu::TextureFormat::RGBA16Float:
break;
default:
return DAWN_FORMAT_VALIDATION_ERROR("Source texture format (%s) is not supported.",
@@ -354,15 +364,15 @@ MaybeError ValidateCopyTextureForBrowser(DeviceBase* device,
"not 1.",
source->texture->GetSampleCount(), destination->texture->GetSampleCount());
- DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc,
- UsageValidationMode::Default));
- DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::TextureBinding,
- UsageValidationMode::Default));
-
- DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
- UsageValidationMode::Default));
- DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::RenderAttachment,
- UsageValidationMode::Default));
+ DAWN_INVALID_IF(
+ options->internalUsage && !device->IsFeatureEnabled(Feature::DawnInternalUsages),
+ "The internalUsage is true while the dawn-internal-usages feature is not enabled.");
+ UsageValidationMode mode =
+ options->internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default;
+ DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc, mode));
+ DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::TextureBinding, mode));
+ DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst, mode));
+ DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::RenderAttachment, mode));
DAWN_TRY(ValidateCopyTextureFormatConversion(source->texture->GetFormat().format,
destination->texture->GetFormat().format));
@@ -456,11 +466,16 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
constexpr uint32_t kEncodeToGammaStep = 0x08;
constexpr uint32_t kPremultiplyStep = 0x10;
constexpr uint32_t kDecodeForSrgbDstFormat = 0x20;
+ constexpr uint32_t kClearSrcAlphaToOne = 0x40;
if (options->srcAlphaMode == wgpu::AlphaMode::Premultiplied) {
- if (options->needsColorSpaceConversion || options->srcAlphaMode != options->dstAlphaMode) {
+ if (options->needsColorSpaceConversion ||
+ options->dstAlphaMode == wgpu::AlphaMode::Unpremultiplied) {
stepsMask |= kUnpremultiplyStep;
}
+ } else if (options->srcAlphaMode == wgpu::AlphaMode::Opaque) {
+ // Simply clear src alpha channel to 1.0
+ stepsMask |= kClearSrcAlphaToOne;
}
if (options->needsColorSpaceConversion) {
@@ -497,7 +512,8 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
}
if (options->dstAlphaMode == wgpu::AlphaMode::Premultiplied) {
- if (options->needsColorSpaceConversion || options->srcAlphaMode != options->dstAlphaMode) {
+ if (options->needsColorSpaceConversion ||
+ options->srcAlphaMode == wgpu::AlphaMode::Unpremultiplied) {
stepsMask |= kPremultiplyStep;
}
}
@@ -546,14 +562,22 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
device->CreateTextureView(source->texture, &srcTextureViewDesc));
// Create bind group after all binding entries are set.
+ UsageValidationMode mode =
+ options->internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default;
Ref<BindGroupBase> bindGroup;
- DAWN_TRY_ASSIGN(bindGroup,
- utils::MakeBindGroup(device, layout,
- {{0, uniformBuffer}, {1, sampler}, {2, srcTextureView}}));
+ DAWN_TRY_ASSIGN(bindGroup, utils::MakeBindGroup(
+ device, layout,
+ {{0, uniformBuffer}, {1, sampler}, {2, srcTextureView}}, mode));
// Create command encoder.
+ CommandEncoderDescriptor commandEncoderDesc;
+ DawnEncoderInternalUsageDescriptor internalUsageDesc;
+ if (options->internalUsage) {
+ internalUsageDesc.useInternalUsages = true;
+ commandEncoderDesc.nextInChain = &internalUsageDesc;
+ }
Ref<CommandEncoder> encoder;
- DAWN_TRY_ASSIGN(encoder, device->CreateCommandEncoder());
+ DAWN_TRY_ASSIGN(encoder, device->CreateCommandEncoder(&commandEncoderDesc));
// Prepare dst texture view as color Attachment.
TextureViewDescriptor dstTextureViewDesc;
@@ -579,7 +603,7 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
renderPassDesc.colorAttachments = &colorAttachmentDesc;
Ref<RenderPassEncoder> passEncoder = encoder->BeginRenderPass(&renderPassDesc);
- // Start pipeline and encode commands to complete
+ // Start pipeline and encode commands to complete
// the copy from src texture to dst texture with transformation.
passEncoder->APISetPipeline(pipeline);
passEncoder->APISetBindGroup(0, bindGroup.Get());
diff --git a/chromium/third_party/dawn/src/dawn/native/DawnNative.cpp b/chromium/third_party/dawn/src/dawn/native/DawnNative.cpp
index 7eaf0c72ccc..5cb93e20319 100644
--- a/chromium/third_party/dawn/src/dawn/native/DawnNative.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/DawnNative.cpp
@@ -125,10 +125,6 @@ std::vector<const char*> Adapter::GetSupportedFeatures() const {
return supportedFeaturesSet.GetEnabledFeatureNames();
}
-WGPUDeviceProperties Adapter::GetAdapterProperties() const {
- return mImpl->GetAdapterProperties();
-}
-
bool Adapter::GetLimits(WGPUSupportedLimits* limits) const {
return mImpl->GetLimits(FromAPI(limits));
}
diff --git a/chromium/third_party/dawn/src/dawn/native/Device.cpp b/chromium/third_party/dawn/src/dawn/native/Device.cpp
index 55435d810d2..e3145a9246b 100644
--- a/chromium/third_party/dawn/src/dawn/native/Device.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Device.cpp
@@ -20,6 +20,7 @@
#include <unordered_set>
#include "dawn/common/Log.h"
+#include "dawn/common/Version_autogen.h"
#include "dawn/native/Adapter.h"
#include "dawn/native/AsyncTask.h"
#include "dawn/native/AttachmentState.h"
@@ -208,8 +209,8 @@ DeviceBase::DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor)
// Record the cache key from the properties. Note that currently, if a new extension
// descriptor is added (and probably handled here), the cache key recording needs to be
// updated.
- mDeviceCacheKey.Record(adapterProperties, mEnabledFeatures.featuresBitSet,
- mEnabledToggles.toggleBitset, cacheDesc);
+ StreamIn(&mDeviceCacheKey, kDawnVersion, adapterProperties, mEnabledFeatures.featuresBitSet,
+ mEnabledToggles.toggleBitset, cacheDesc);
}
DeviceBase::DeviceBase() : mState(State::Alive) {
@@ -622,9 +623,14 @@ bool DeviceBase::APIPopErrorScope(wgpu::ErrorCallback callback, void* userdata)
}
BlobCache* DeviceBase::GetBlobCache() {
+#if TINT_BUILD_WGSL_WRITER
+ // TODO(crbug.com/dawn/1481): Shader caching currently has a dependency on the WGSL writer to
+ // generate cache keys. We can lift the dependency once we also cache frontend parsing,
+ // transformations, and reflection.
if (IsToggleEnabled(Toggle::EnableBlobCache)) {
return mInstance->GetBlobCache();
}
+#endif
return nullptr;
}
@@ -1221,6 +1227,14 @@ BufferBase* DeviceBase::APICreateErrorBuffer() {
return BufferBase::MakeError(this, &desc);
}
+ExternalTextureBase* DeviceBase::APICreateErrorExternalTexture() {
+ return ExternalTextureBase::MakeError(this);
+}
+
+TextureBase* DeviceBase::APICreateErrorTexture(const TextureDescriptor* desc) {
+ return TextureBase::MakeError(this, desc);
+}
+
// Other Device API methods
// Returns true if future ticking is needed.
@@ -1397,12 +1411,12 @@ QueueBase* DeviceBase::GetQueue() const {
// Implementation details of object creation
-ResultOrError<Ref<BindGroupBase>> DeviceBase::CreateBindGroup(
- const BindGroupDescriptor* descriptor) {
+ResultOrError<Ref<BindGroupBase>> DeviceBase::CreateBindGroup(const BindGroupDescriptor* descriptor,
+ UsageValidationMode mode) {
DAWN_TRY(ValidateIsAlive());
if (IsValidationEnabled()) {
- DAWN_TRY_CONTEXT(ValidateBindGroupDescriptor(this, descriptor), "validating %s against %s",
- descriptor, descriptor->layout);
+ DAWN_TRY_CONTEXT(ValidateBindGroupDescriptor(this, descriptor, mode),
+ "validating %s against %s", descriptor, descriptor->layout);
}
return CreateBindGroupImpl(descriptor);
}
@@ -1914,4 +1928,10 @@ bool DeviceBase::ShouldDuplicateParametersForDrawIndirect(
return false;
}
+uint64_t DeviceBase::GetBufferCopyOffsetAlignmentForDepthStencil() const {
+ // For depth-stencil texture, buffer offset must be a multiple of 4, which is required
+ // by WebGPU and Vulkan SPEC.
+ return 4u;
+}
+
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/Device.h b/chromium/third_party/dawn/src/dawn/native/Device.h
index dc14e152577..0a046457b95 100644
--- a/chromium/third_party/dawn/src/dawn/native/Device.h
+++ b/chromium/third_party/dawn/src/dawn/native/Device.h
@@ -35,6 +35,7 @@
#include "dawn/native/RefCountedWithExternalCount.h"
#include "dawn/native/StagingBuffer.h"
#include "dawn/native/Toggles.h"
+#include "dawn/native/UsageValidationMode.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/dawn_platform.h"
@@ -203,7 +204,9 @@ class DeviceBase : public RefCountedWithExternalCount {
Ref<PipelineCacheBase> GetOrCreatePipelineCache(const CacheKey& key);
// Object creation methods that be used in a reentrant manner.
- ResultOrError<Ref<BindGroupBase>> CreateBindGroup(const BindGroupDescriptor* descriptor);
+ ResultOrError<Ref<BindGroupBase>> CreateBindGroup(
+ const BindGroupDescriptor* descriptor,
+ UsageValidationMode mode = UsageValidationMode::Default);
ResultOrError<Ref<BindGroupLayoutBase>> CreateBindGroupLayout(
const BindGroupLayoutDescriptor* descriptor,
bool allowInternalBinding = false);
@@ -263,6 +266,8 @@ class DeviceBase : public RefCountedWithExternalCount {
// For Dawn Wire
BufferBase* APICreateErrorBuffer();
+ ExternalTextureBase* APICreateErrorExternalTexture();
+ TextureBase* APICreateErrorTexture(const TextureDescriptor* desc);
QueueBase* APIGetQueue();
@@ -357,6 +362,7 @@ class DeviceBase : public RefCountedWithExternalCount {
// BackendMetadata that we can query from the device.
virtual uint32_t GetOptimalBytesPerRowAlignment() const = 0;
virtual uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const = 0;
+ virtual uint64_t GetBufferCopyOffsetAlignmentForDepthStencil() const;
virtual float GetTimestampPeriodInNS() const = 0;
diff --git a/chromium/third_party/dawn/src/dawn/native/ExternalTexture.cpp b/chromium/third_party/dawn/src/dawn/native/ExternalTexture.cpp
index 0dfa963c151..a23faa7bdc2 100644
--- a/chromium/third_party/dawn/src/dawn/native/ExternalTexture.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/ExternalTexture.cpp
@@ -123,8 +123,9 @@ ExternalTextureBase::ExternalTextureBase(DeviceBase* device)
TrackInDevice();
}
+// Error external texture cannot be used in bind group.
ExternalTextureBase::ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag)
- : ApiObjectBase(device, tag) {}
+ : ApiObjectBase(device, tag), mState(ExternalTextureState::Destroyed) {}
ExternalTextureBase::~ExternalTextureBase() = default;
@@ -152,6 +153,8 @@ MaybeError ExternalTextureBase::Initialize(DeviceBase* device,
ExternalTextureParams params;
params.numPlanes = descriptor->plane1 == nullptr ? 1 : 2;
+ params.doYuvToRgbConversionOnly = descriptor->doYuvToRgbConversionOnly ? 1 : 0;
+
// YUV-to-RGB conversion is performed by multiplying the source YUV values with a 4x3 matrix
// passed from Chromium. The matrix was originally sourced from /skia/src/core/SkYUVMath.cpp.
// This matrix is only used in multiplanar scenarios.
diff --git a/chromium/third_party/dawn/src/dawn/native/ExternalTexture.h b/chromium/third_party/dawn/src/dawn/native/ExternalTexture.h
index 50f3b89885f..509a7ee9303 100644
--- a/chromium/third_party/dawn/src/dawn/native/ExternalTexture.h
+++ b/chromium/third_party/dawn/src/dawn/native/ExternalTexture.h
@@ -28,7 +28,9 @@ class TextureViewBase;
struct ExternalTextureParams {
uint32_t numPlanes;
- std::array<uint32_t, 3> padding;
+ // TODO(crbug.com/dawn/1466): Only go as few steps as necessary.
+ uint32_t doYuvToRgbConversionOnly;
+ std::array<uint32_t, 2> padding;
std::array<float, 12> yuvToRgbConversionMatrix;
std::array<float, 8> gammaDecodingParams = {};
std::array<float, 8> gammaEncodingParams = {};
diff --git a/chromium/third_party/dawn/src/dawn/native/Features.cpp b/chromium/third_party/dawn/src/dawn/native/Features.cpp
index a813c6871dc..e43da124e84 100644
--- a/chromium/third_party/dawn/src/dawn/native/Features.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Features.cpp
@@ -26,7 +26,6 @@ namespace {
struct FeatureEnumAndInfo {
Feature feature;
FeatureInfo info;
- bool WGPUDeviceProperties::*memberInWGPUDeviceProperties;
};
using FeatureEnumAndInfoList =
@@ -35,69 +34,52 @@ using FeatureEnumAndInfoList =
static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {{
{Feature::TextureCompressionBC,
{"texture-compression-bc", "Support Block Compressed (BC) texture formats",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=42"},
- &WGPUDeviceProperties::textureCompressionBC},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=42"}},
{Feature::TextureCompressionETC2,
{"texture-compression-etc2",
"Support Ericsson Texture Compressed (ETC2/EAC) texture "
"formats",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
- &WGPUDeviceProperties::textureCompressionETC2},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=955"}},
{Feature::TextureCompressionASTC,
{"texture-compression-astc",
"Support Adaptable Scalable Texture Compressed (ASTC) "
"texture formats",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
- &WGPUDeviceProperties::textureCompressionASTC},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=955"}},
{Feature::ShaderFloat16,
{"shader-float16",
"Support 16bit float arithmetic and declarations in uniform and storage buffers",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=426"},
- &WGPUDeviceProperties::shaderFloat16},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=426"}},
{Feature::PipelineStatisticsQuery,
{"pipeline-statistics-query", "Support Pipeline Statistics Query",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
- &WGPUDeviceProperties::pipelineStatisticsQuery},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=434"}},
{Feature::TimestampQuery,
{"timestamp-query", "Support Timestamp Query",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
- &WGPUDeviceProperties::timestampQuery},
- {Feature::DepthClamping,
- {"depth-clamping", "Clamp depth to [0, 1] in NDC space instead of clipping",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=716"},
- &WGPUDeviceProperties::depthClamping},
- {Feature::Depth24UnormStencil8,
- {"depth24unorm-stencil8", "Support depth24unorm-stencil8 texture format",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=690"},
- &WGPUDeviceProperties::depth24UnormStencil8},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=434"}},
+ {Feature::DepthClipControl,
+ {"depth-clip-control", "Disable depth clipping of primitives to the clip volume",
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=1178"}},
{Feature::Depth32FloatStencil8,
{"depth32float-stencil8", "Support depth32float-stencil8 texture format",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=690"},
- &WGPUDeviceProperties::depth32FloatStencil8},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=690"}},
{Feature::ChromiumExperimentalDp4a,
{"chromium-experimental-dp4a", "Support experimental DP4a instructions in WGSL",
- "https://bugs.chromium.org/p/tint/issues/detail?id=1497"},
- &WGPUDeviceProperties::chromiumExperimentalDp4a},
+ "https://bugs.chromium.org/p/tint/issues/detail?id=1497"}},
{Feature::IndirectFirstInstance,
{"indirect-first-instance", "Support non-zero first instance values on indirect draw calls",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=1197"},
- &WGPUDeviceProperties::indirectFirstInstance},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=1197"}},
{Feature::DawnInternalUsages,
{"dawn-internal-usages",
"Add internal usages to resources to affect how the texture is allocated, but not "
"frontend validation. Other internal commands may access this usage.",
"https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
- "dawn_internal_usages.md"},
- &WGPUDeviceProperties::dawnInternalUsages},
+ "dawn_internal_usages.md"}},
{Feature::MultiPlanarFormats,
{"multiplanar-formats", "Import and use multi-planar texture formats with per plane views",
- "https://bugs.chromium.org/p/dawn/issues/detail?id=551"},
- &WGPUDeviceProperties::multiPlanarFormats},
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=551"}},
{Feature::DawnNative,
{"dawn-native", "WebGPU is running on top of dawn_native.",
"https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
- "dawn_native.md"},
- &WGPUDeviceProperties::dawnNative},
+ "dawn_native.md"}},
}};
Feature FromAPIFeature(wgpu::FeatureName feature) {
@@ -115,10 +97,8 @@ Feature FromAPIFeature(wgpu::FeatureName feature) {
return Feature::TextureCompressionETC2;
case wgpu::FeatureName::TextureCompressionASTC:
return Feature::TextureCompressionASTC;
- case wgpu::FeatureName::DepthClamping:
- return Feature::DepthClamping;
- case wgpu::FeatureName::Depth24UnormStencil8:
- return Feature::Depth24UnormStencil8;
+ case wgpu::FeatureName::DepthClipControl:
+ return Feature::DepthClipControl;
case wgpu::FeatureName::Depth32FloatStencil8:
return Feature::Depth32FloatStencil8;
case wgpu::FeatureName::IndirectFirstInstance:
@@ -149,10 +129,8 @@ wgpu::FeatureName ToAPIFeature(Feature feature) {
return wgpu::FeatureName::PipelineStatisticsQuery;
case Feature::TimestampQuery:
return wgpu::FeatureName::TimestampQuery;
- case Feature::DepthClamping:
- return wgpu::FeatureName::DepthClamping;
- case Feature::Depth24UnormStencil8:
- return wgpu::FeatureName::Depth24UnormStencil8;
+ case Feature::DepthClipControl:
+ return wgpu::FeatureName::DepthClipControl;
case Feature::Depth32FloatStencil8:
return wgpu::FeatureName::Depth32FloatStencil8;
case Feature::IndirectFirstInstance:
@@ -225,14 +203,6 @@ std::vector<const char*> FeaturesSet::GetEnabledFeatureNames() const {
return enabledFeatureNames;
}
-void FeaturesSet::InitializeDeviceProperties(WGPUDeviceProperties* properties) const {
- ASSERT(properties != nullptr);
-
- for (uint32_t i : IterateBitSet(featuresBitSet)) {
- properties->*(kFeatureNameAndInfoList[i].memberInWGPUDeviceProperties) = true;
- }
-}
-
wgpu::FeatureName FeatureEnumToAPIFeature(Feature feature) {
ASSERT(feature != Feature::InvalidEnum);
return ToAPIFeature(feature);
diff --git a/chromium/third_party/dawn/src/dawn/native/Features.h b/chromium/third_party/dawn/src/dawn/native/Features.h
index ebf804e5ca9..f97fd9df675 100644
--- a/chromium/third_party/dawn/src/dawn/native/Features.h
+++ b/chromium/third_party/dawn/src/dawn/native/Features.h
@@ -33,8 +33,7 @@ enum class Feature {
ShaderFloat16,
PipelineStatisticsQuery,
TimestampQuery,
- DepthClamping,
- Depth24UnormStencil8,
+ DepthClipControl,
Depth32FloatStencil8,
ChromiumExperimentalDp4a,
IndirectFirstInstance,
@@ -62,7 +61,6 @@ struct FeaturesSet {
// non-null.
size_t EnumerateFeatures(wgpu::FeatureName* features) const;
std::vector<const char*> GetEnabledFeatureNames() const;
- void InitializeDeviceProperties(WGPUDeviceProperties* properties) const;
};
wgpu::FeatureName FeatureEnumToAPIFeature(Feature feature);
diff --git a/chromium/third_party/dawn/src/dawn/native/Format.cpp b/chromium/third_party/dawn/src/dawn/native/Format.cpp
index f1b4cb87ce0..b6553df8857 100644
--- a/chromium/third_party/dawn/src/dawn/native/Format.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Format.cpp
@@ -403,9 +403,6 @@ FormatTable BuildFormatTable(const DeviceBase* device) {
AddDepthFormat(wgpu::TextureFormat::Depth24Plus, 4, true);
AddMultiAspectFormat(wgpu::TextureFormat::Depth24PlusStencil8,
Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, true, true, 2);
- bool isD24S8Supported = device->IsFeatureEnabled(Feature::Depth24UnormStencil8);
- AddMultiAspectFormat(wgpu::TextureFormat::Depth24UnormStencil8,
- Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, isD24S8Supported, true, 2);
AddDepthFormat(wgpu::TextureFormat::Depth32Float, 4, true);
bool isD32S8Supported = device->IsFeatureEnabled(Feature::Depth32FloatStencil8);
AddMultiAspectFormat(wgpu::TextureFormat::Depth32FloatStencil8,
@@ -480,7 +477,8 @@ FormatTable BuildFormatTable(const DeviceBase* device) {
// clang-format on
// This checks that each format is set at least once, the second part of checking that all
- // formats are checked exactly once.
+ // formats are checked exactly once. If this assertion is failing and texture formats have been
+ // added or removed recently, check that kKnownFormatCount has been updated.
ASSERT(formatsSet.all());
return table;
diff --git a/chromium/third_party/dawn/src/dawn/native/Format.h b/chromium/third_party/dawn/src/dawn/native/Format.h
index 8f750da25b1..e192a2ce83d 100644
--- a/chromium/third_party/dawn/src/dawn/native/Format.h
+++ b/chromium/third_party/dawn/src/dawn/native/Format.h
@@ -79,7 +79,7 @@ struct AspectInfo {
// The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the
// exact number of known format.
-static constexpr uint32_t kKnownFormatCount = 96;
+static constexpr uint32_t kKnownFormatCount = 95;
using FormatIndex = TypedInteger<struct FormatIndexT, uint32_t>;
diff --git a/chromium/third_party/dawn/src/dawn/native/IndirectDrawValidationEncoder.cpp b/chromium/third_party/dawn/src/dawn/native/IndirectDrawValidationEncoder.cpp
index 10a8164026c..abd09cd1121 100644
--- a/chromium/third_party/dawn/src/dawn/native/IndirectDrawValidationEncoder.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/IndirectDrawValidationEncoder.cpp
@@ -81,7 +81,7 @@ static const char sRenderValidationShaderSource[] = R"(
@group(0) @binding(0) var<storage, read> batch: BatchInfo;
@group(0) @binding(1) var<storage, read_write> inputParams: IndirectParams;
- @group(0) @binding(2) var<storage, write> outputParams: IndirectParams;
+ @group(0) @binding(2) var<storage, read_write> outputParams: IndirectParams;
fn numIndirectParamsPerDrawCallInput() -> u32 {
var numParams = kNumDrawIndirectParams;
diff --git a/chromium/third_party/dawn/src/dawn/native/Instance.cpp b/chromium/third_party/dawn/src/dawn/native/Instance.cpp
index 3d8cce91e9a..afe9c1d7ffe 100644
--- a/chromium/third_party/dawn/src/dawn/native/Instance.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Instance.cpp
@@ -20,7 +20,6 @@
#include "dawn/common/GPUInfo.h"
#include "dawn/common/Log.h"
#include "dawn/common/SystemUtils.h"
-#include "dawn/common/Version_autogen.h"
#include "dawn/native/ChainUtils_autogen.h"
#include "dawn/native/ErrorData.h"
#include "dawn/native/Surface.h"
@@ -95,8 +94,8 @@ BackendsBitset GetEnabledBackends() {
}
dawn::platform::CachingInterface* GetCachingInterface(dawn::platform::Platform* platform) {
- if (platform != nullptr && dawn::kGitHash.size() > 0) {
- return platform->GetCachingInterface(dawn::kGitHash.data(), dawn::kGitHash.size());
+ if (platform != nullptr) {
+ return platform->GetCachingInterface();
}
return nullptr;
}
@@ -104,7 +103,7 @@ dawn::platform::CachingInterface* GetCachingInterface(dawn::platform::Platform*
} // anonymous namespace
InstanceBase* APICreateInstance(const InstanceDescriptor* descriptor) {
- return InstanceBase::Create().Detach();
+ return InstanceBase::Create(descriptor).Detach();
}
// InstanceBase
@@ -181,7 +180,14 @@ ResultOrError<Ref<AdapterBase>> InstanceBase::RequestAdapterInternal(
if (GetEnabledBackends()[wgpu::BackendType::Vulkan]) {
dawn_native::vulkan::AdapterDiscoveryOptions vulkanOptions;
vulkanOptions.forceSwiftShader = true;
- DAWN_TRY(DiscoverAdaptersInternal(&vulkanOptions));
+
+ MaybeError result = DiscoverAdaptersInternal(&vulkanOptions);
+ if (result.IsError()) {
+ dawn::WarningLog()
+ << "Skipping Vulkan Swiftshader adapter because initialization failed: "
+ << result.AcquireError()->GetFormattedMessage();
+ return Ref<AdapterBase>(nullptr);
+ }
}
#else
return Ref<AdapterBase>(nullptr);
@@ -277,7 +283,16 @@ void InstanceBase::DiscoverDefaultAdapters() {
// This is just a wrapper around the real logic that uses Error.h error handling.
bool InstanceBase::DiscoverAdapters(const AdapterDiscoveryOptionsBase* options) {
- return !ConsumedError(DiscoverAdaptersInternal(options));
+ MaybeError result = DiscoverAdaptersInternal(options);
+
+ if (result.IsError()) {
+ dawn::WarningLog() << "Skipping " << options->backendType
+ << " adapter because initialization failed: "
+ << result.AcquireError()->GetFormattedMessage();
+ return false;
+ }
+
+ return true;
}
const ToggleInfo* InstanceBase::GetToggleInfo(const char* toggleName) {
@@ -387,10 +402,7 @@ MaybeError InstanceBase::DiscoverAdaptersInternal(const AdapterDiscoveryOptionsB
bool InstanceBase::ConsumedError(MaybeError maybeError) {
if (maybeError.IsError()) {
- std::unique_ptr<ErrorData> error = maybeError.AcquireError();
-
- ASSERT(error != nullptr);
- dawn::ErrorLog() << error->GetFormattedMessage();
+ ConsumeError(maybeError.AcquireError());
return true;
}
return false;
@@ -453,6 +465,11 @@ const std::vector<std::string>& InstanceBase::GetRuntimeSearchPaths() const {
return mRuntimeSearchPaths;
}
+void InstanceBase::ConsumeError(std::unique_ptr<ErrorData> error) {
+ ASSERT(error != nullptr);
+ dawn::ErrorLog() << error->GetFormattedMessage();
+}
+
const XlibXcbFunctions* InstanceBase::GetOrCreateXlibXcbFunctions() {
#if defined(DAWN_USE_X11)
if (mXlibXcbFunctions == nullptr) {
diff --git a/chromium/third_party/dawn/src/dawn/native/Instance.h b/chromium/third_party/dawn/src/dawn/native/Instance.h
index 581cb8519b8..df22f2750fc 100644
--- a/chromium/third_party/dawn/src/dawn/native/Instance.h
+++ b/chromium/third_party/dawn/src/dawn/native/Instance.h
@@ -61,6 +61,16 @@ class InstanceBase final : public RefCounted {
// Used to handle error that happen up to device creation.
bool ConsumedError(MaybeError maybeError);
+ template <typename T>
+ bool ConsumedError(ResultOrError<T> resultOrError, T* result) {
+ if (resultOrError.IsError()) {
+ ConsumeError(resultOrError.AcquireError());
+ return true;
+ }
+ *result = resultOrError.AcquireSuccess();
+ return false;
+ }
+
// Used to query the details of a toggle. Return nullptr if toggleName is not a valid name
// of a toggle supported in Dawn.
const ToggleInfo* GetToggleInfo(const char* toggleName);
@@ -112,6 +122,8 @@ class InstanceBase final : public RefCounted {
ResultOrError<Ref<AdapterBase>> RequestAdapterInternal(const RequestAdapterOptions* options);
+ void ConsumeError(std::unique_ptr<ErrorData> error);
+
std::vector<std::string> mRuntimeSearchPaths;
BackendsBitset mBackendsConnected;
diff --git a/chromium/third_party/dawn/src/dawn/native/InternalPipelineStore.h b/chromium/third_party/dawn/src/dawn/native/InternalPipelineStore.h
index 3defe672604..b8386d5d1df 100644
--- a/chromium/third_party/dawn/src/dawn/native/InternalPipelineStore.h
+++ b/chromium/third_party/dawn/src/dawn/native/InternalPipelineStore.h
@@ -17,6 +17,7 @@
#include <unordered_map>
+#include "dawn/native/ApplyClearColorValueWithDrawHelper.h"
#include "dawn/native/ObjectBase.h"
#include "dawn/native/ScratchBuffer.h"
#include "dawn/native/dawn_platform.h"
@@ -40,6 +41,8 @@ struct InternalPipelineStore {
Ref<ComputePipelineBase> timestampComputePipeline;
Ref<ShaderModuleBase> timestampCS;
+ ApplyClearColorValueWithDrawPipelinesCache applyClearColorValueWithDrawPipelines;
+
Ref<ShaderModuleBase> placeholderFragmentShader;
// A scratch buffer suitable for use as a copy destination and storage binding.
diff --git a/chromium/third_party/dawn/src/dawn/native/Limits.cpp b/chromium/third_party/dawn/src/dawn/native/Limits.cpp
index 65af8dfaaaa..ef285b2a4db 100644
--- a/chromium/third_party/dawn/src/dawn/native/Limits.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Limits.cpp
@@ -51,6 +51,8 @@
X(Maximum, maxVertexAttributes, 16, 16) \
X(Maximum, maxVertexBufferArrayStride, 2048, 2048) \
X(Maximum, maxInterStageShaderComponents, 60, 60) \
+ X(Maximum, maxInterStageShaderVariables, 16, 16) \
+ X(Maximum, maxColorAttachments, 8, 8) \
X(Maximum, maxComputeInvocationsPerWorkgroup, 256, 256) \
X(Maximum, maxComputeWorkgroupSizeX, 256, 256) \
X(Maximum, maxComputeWorkgroupSizeY, 256, 256) \
diff --git a/chromium/third_party/dawn/src/dawn/native/Pipeline.cpp b/chromium/third_party/dawn/src/dawn/native/Pipeline.cpp
index 6bee1eb5a5e..513bd2ac4cb 100644
--- a/chromium/third_party/dawn/src/dawn/native/Pipeline.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Pipeline.cpp
@@ -66,16 +66,16 @@ MaybeError ValidateProgrammableStage(DeviceBase* device,
// Validate if overridable constants exist in shader module
// pipelineBase is not yet constructed at this moment so iterate constants from descriptor
- size_t numUninitializedConstants = metadata.uninitializedOverridableConstants.size();
+ size_t numUninitializedConstants = metadata.uninitializedOverrides.size();
// Keep an initialized constants sets to handle duplicate initialization cases
std::unordered_set<std::string> stageInitializedConstantIdentifiers;
for (uint32_t i = 0; i < constantCount; i++) {
- DAWN_INVALID_IF(metadata.overridableConstants.count(constants[i].key) == 0,
+ DAWN_INVALID_IF(metadata.overrides.count(constants[i].key) == 0,
"Pipeline overridable constant \"%s\" not found in %s.", constants[i].key,
module);
if (stageInitializedConstantIdentifiers.count(constants[i].key) == 0) {
- if (metadata.uninitializedOverridableConstants.count(constants[i].key) > 0) {
+ if (metadata.uninitializedOverrides.count(constants[i].key) > 0) {
numUninitializedConstants--;
}
stageInitializedConstantIdentifiers.insert(constants[i].key);
@@ -91,7 +91,7 @@ MaybeError ValidateProgrammableStage(DeviceBase* device,
if (DAWN_UNLIKELY(numUninitializedConstants > 0)) {
std::string uninitializedConstantsArray;
bool isFirst = true;
- for (std::string identifier : metadata.uninitializedOverridableConstants) {
+ for (std::string identifier : metadata.uninitializedOverrides) {
if (stageInitializedConstantIdentifiers.count(identifier) > 0) {
continue;
}
diff --git a/chromium/third_party/dawn/src/dawn/native/QueryHelper.cpp b/chromium/third_party/dawn/src/dawn/native/QueryHelper.cpp
index e72dfed7a12..d8f64813f3c 100644
--- a/chromium/third_party/dawn/src/dawn/native/QueryHelper.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/QueryHelper.cpp
@@ -40,25 +40,25 @@ static_assert(offsetof(dawn::native::TimestampParams, rightShift) == 16);
static const char sConvertTimestampsToNanoseconds[] = R"(
struct Timestamp {
- low : u32;
- high : u32;
- };
+ low : u32,
+ high : u32,
+ }
struct TimestampArr {
- t : array<Timestamp>;
- };
+ t : array<Timestamp>
+ }
struct AvailabilityArr {
- v : array<u32>;
- };
+ v : array<u32>
+ }
struct TimestampParams {
- first : u32;
- count : u32;
- offset : u32;
- multiplier : u32;
- right_shift : u32;
- };
+ first : u32,
+ count : u32,
+ offset : u32,
+ multiplier : u32,
+ right_shift : u32,
+ }
@group(0) @binding(0) var<storage, read_write> timestamps : TimestampArr;
@group(0) @binding(1) var<storage, read> availability : AvailabilityArr;
@@ -199,7 +199,8 @@ MaybeError EncodeConvertTimestampsToNanoseconds(CommandEncoder* encoder,
Ref<BindGroupBase> bindGroup;
DAWN_TRY_ASSIGN(
bindGroup,
- utils::MakeBindGroup(device, layout, {{0, timestamps}, {1, availability}, {2, params}}));
+ utils::MakeBindGroup(device, layout, {{0, timestamps}, {1, availability}, {2, params}},
+ UsageValidationMode::Internal));
// Create compute encoder and issue dispatch.
Ref<ComputePassEncoder> pass = encoder->BeginComputePass();
diff --git a/chromium/third_party/dawn/src/dawn/native/Queue.cpp b/chromium/third_party/dawn/src/dawn/native/Queue.cpp
index c17ed8f4d9b..9881d65897b 100644
--- a/chromium/third_party/dawn/src/dawn/native/Queue.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Queue.cpp
@@ -97,11 +97,11 @@ ResultOrError<UploadHandle> UploadTextureDataAligningBytesPerRowAndOffset(
// since both of them are powers of two, we only need to align to the max value.
uint64_t offsetAlignment = std::max(optimalOffsetAlignment, uint64_t(blockInfo.byteSize));
- // For depth-stencil texture, buffer offset must be a multiple of 4, which is required
- // by WebGPU and Vulkan SPEC.
+ // Buffer offset alignments must follow additional restrictions when we copy with depth stencil
+ // formats.
if (hasDepthOrStencil) {
- constexpr uint64_t kOffsetAlignmentForDepthStencil = 4;
- offsetAlignment = std::max(offsetAlignment, kOffsetAlignmentForDepthStencil);
+ offsetAlignment =
+ std::max(offsetAlignment, device->GetBufferCopyOffsetAlignmentForDepthStencil());
}
UploadHandle uploadHandle;
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderBundle.cpp b/chromium/third_party/dawn/src/dawn/native/RenderBundle.cpp
index 2781983d823..d2e3d6939ca 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderBundle.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/RenderBundle.cpp
@@ -37,6 +37,7 @@ RenderBundleBase::RenderBundleBase(RenderBundleEncoder* encoder,
mAttachmentState(std::move(attachmentState)),
mDepthReadOnly(depthReadOnly),
mStencilReadOnly(stencilReadOnly),
+ mDrawCount(encoder->GetDrawCount()),
mResourceUsage(std::move(resourceUsage)) {
TrackInDevice();
}
@@ -80,6 +81,11 @@ bool RenderBundleBase::IsStencilReadOnly() const {
return mStencilReadOnly;
}
+uint64_t RenderBundleBase::GetDrawCount() const {
+ ASSERT(!IsError());
+ return mDrawCount;
+}
+
const RenderPassResourceUsage& RenderBundleBase::GetResourceUsage() const {
ASSERT(!IsError());
return mResourceUsage;
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderBundle.h b/chromium/third_party/dawn/src/dawn/native/RenderBundle.h
index 9297e015276..f86eb5fbf1d 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderBundle.h
+++ b/chromium/third_party/dawn/src/dawn/native/RenderBundle.h
@@ -52,6 +52,7 @@ class RenderBundleBase final : public ApiObjectBase {
const AttachmentState* GetAttachmentState() const;
bool IsDepthReadOnly() const;
bool IsStencilReadOnly() const;
+ uint64_t GetDrawCount() const;
const RenderPassResourceUsage& GetResourceUsage() const;
const IndirectDrawMetadata& GetIndirectDrawMetadata();
@@ -65,6 +66,7 @@ class RenderBundleBase final : public ApiObjectBase {
Ref<AttachmentState> mAttachmentState;
bool mDepthReadOnly;
bool mStencilReadOnly;
+ uint64_t mDrawCount;
RenderPassResourceUsage mResourceUsage;
};
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderBundleEncoder.cpp b/chromium/third_party/dawn/src/dawn/native/RenderBundleEncoder.cpp
index 56a9d666ff7..02cc54c134f 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderBundleEncoder.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/RenderBundleEncoder.cpp
@@ -62,9 +62,10 @@ MaybeError ValidateRenderBundleEncoderDescriptor(const DeviceBase* device,
DAWN_INVALID_IF(!IsValidSampleCount(descriptor->sampleCount),
"Sample count (%u) is not supported.", descriptor->sampleCount);
- DAWN_INVALID_IF(descriptor->colorFormatsCount > kMaxColorAttachments,
+ uint32_t maxColorAttachments = device->GetLimits().v1.maxColorAttachments;
+ DAWN_INVALID_IF(descriptor->colorFormatsCount > maxColorAttachments,
"Color formats count (%u) exceeds maximum number of color attachements (%u).",
- descriptor->colorFormatsCount, kMaxColorAttachments);
+ descriptor->colorFormatsCount, maxColorAttachments);
bool allColorFormatsUndefined = true;
for (uint32_t i = 0; i < descriptor->colorFormatsCount; ++i) {
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.cpp b/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.cpp
index 242e47be839..36aa9e12b78 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.cpp
@@ -75,6 +75,11 @@ bool RenderEncoderBase::IsStencilReadOnly() const {
return mStencilReadOnly;
}
+uint64_t RenderEncoderBase::GetDrawCount() const {
+ ASSERT(!IsError());
+ return mDrawCount;
+}
+
Ref<AttachmentState> RenderEncoderBase::AcquireAttachmentState() {
return std::move(mAttachmentState);
}
@@ -104,6 +109,8 @@ void RenderEncoderBase::APIDraw(uint32_t vertexCount,
draw->firstVertex = firstVertex;
draw->firstInstance = firstInstance;
+ mDrawCount++;
+
return {};
},
"encoding %s.Draw(%u, %u, %u, %u).", this, vertexCount, instanceCount, firstVertex,
@@ -141,6 +148,8 @@ void RenderEncoderBase::APIDrawIndexed(uint32_t indexCount,
draw->baseVertex = baseVertex;
draw->firstInstance = firstInstance;
+ mDrawCount++;
+
return {};
},
"encoding %s.DrawIndexed(%u, %u, %u, %i, %u).", this, indexCount, instanceCount, firstIndex,
@@ -191,6 +200,8 @@ void RenderEncoderBase::APIDrawIndirect(BufferBase* indirectBuffer, uint64_t ind
// backend.
mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
+ mDrawCount++;
+
return {};
},
"encoding %s.DrawIndirect(%s, %u).", this, indirectBuffer, indirectOffset);
@@ -243,6 +254,8 @@ void RenderEncoderBase::APIDrawIndexedIndirect(BufferBase* indirectBuffer,
// backend.
mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
+ mDrawCount++;
+
return {};
},
"encoding %s.DrawIndexedIndirect(%s, %u).", this, indirectBuffer, indirectOffset);
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.h b/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.h
index 0bdcc4d16ab..0cb675a7198 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.h
+++ b/chromium/third_party/dawn/src/dawn/native/RenderEncoderBase.h
@@ -62,6 +62,7 @@ class RenderEncoderBase : public ProgrammableEncoder {
const AttachmentState* GetAttachmentState() const;
bool IsDepthReadOnly() const;
bool IsStencilReadOnly() const;
+ uint64_t GetDrawCount() const;
Ref<AttachmentState> AcquireAttachmentState();
protected:
@@ -74,6 +75,8 @@ class RenderEncoderBase : public ProgrammableEncoder {
RenderPassResourceUsageTracker mUsageTracker;
IndirectDrawMetadata mIndirectDrawMetadata;
+ uint64_t mDrawCount = 0;
+
private:
Ref<AttachmentState> mAttachmentState;
const bool mDisableBaseVertex;
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.cpp b/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.cpp
index 716ce97bad4..b066655f370 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.cpp
@@ -20,6 +20,7 @@
#include "dawn/common/Constants.h"
#include "dawn/native/Buffer.h"
+#include "dawn/native/ChainUtils_autogen.h"
#include "dawn/native/CommandEncoder.h"
#include "dawn/native/CommandValidation.h"
#include "dawn/native/Commands.h"
@@ -55,7 +56,6 @@ RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
EncodingContext* encodingContext,
RenderPassResourceUsageTracker usageTracker,
Ref<AttachmentState> attachmentState,
- std::vector<TimestampWrite> timestampWritesAtEnd,
uint32_t renderTargetWidth,
uint32_t renderTargetHeight,
bool depthReadOnly,
@@ -69,9 +69,13 @@ RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
mCommandEncoder(commandEncoder),
mRenderTargetWidth(renderTargetWidth),
mRenderTargetHeight(renderTargetHeight),
- mOcclusionQuerySet(descriptor->occlusionQuerySet),
- mTimestampWritesAtEnd(std::move(timestampWritesAtEnd)) {
+ mOcclusionQuerySet(descriptor->occlusionQuerySet) {
mUsageTracker = std::move(usageTracker);
+ const RenderPassDescriptorMaxDrawCount* maxDrawCountInfo = nullptr;
+ FindInChain(descriptor->nextInChain, &maxDrawCountInfo);
+ if (maxDrawCountInfo) {
+ mMaxDrawCount = maxDrawCountInfo->maxDrawCount;
+ }
TrackInDevice();
}
@@ -82,15 +86,14 @@ Ref<RenderPassEncoder> RenderPassEncoder::Create(DeviceBase* device,
EncodingContext* encodingContext,
RenderPassResourceUsageTracker usageTracker,
Ref<AttachmentState> attachmentState,
- std::vector<TimestampWrite> timestampWritesAtEnd,
uint32_t renderTargetWidth,
uint32_t renderTargetHeight,
bool depthReadOnly,
bool stencilReadOnly) {
return AcquireRef(new RenderPassEncoder(device, descriptor, commandEncoder, encodingContext,
std::move(usageTracker), std::move(attachmentState),
- std::move(timestampWritesAtEnd), renderTargetWidth,
- renderTargetHeight, depthReadOnly, stencilReadOnly));
+ renderTargetWidth, renderTargetHeight, depthReadOnly,
+ stencilReadOnly));
}
RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
@@ -140,12 +143,13 @@ void RenderPassEncoder::APIEnd() {
mOcclusionQueryActive,
"Render pass %s ended with incomplete occlusion query index %u of %s.", this,
mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
+
+ DAWN_INVALID_IF(mDrawCount > mMaxDrawCount,
+ "The drawCount (%u) of %s is greater than the maxDrawCount (%u).",
+ mDrawCount, this, mMaxDrawCount);
}
- EndRenderPassCmd* cmd = allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
- // The query availability has already been updated at the beginning of render
- // pass, and no need to do update here.
- cmd->timestampWrites = std::move(mTimestampWritesAtEnd);
+ allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
DAWN_TRY(mEncodingContext->ExitRenderPass(this, std::move(mUsageTracker),
mCommandEncoder.Get(),
@@ -320,6 +324,8 @@ void RenderPassEncoder::APIExecuteBundles(uint32_t count, RenderBundleBase* cons
if (IsValidationEnabled()) {
mIndirectDrawMetadata.AddBundle(renderBundles[i]);
}
+
+ mDrawCount += bundles[i]->GetDrawCount();
}
return {};
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.h b/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.h
index ad4c1300aa5..32199f16547 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.h
+++ b/chromium/third_party/dawn/src/dawn/native/RenderPassEncoder.h
@@ -33,7 +33,6 @@ class RenderPassEncoder final : public RenderEncoderBase {
EncodingContext* encodingContext,
RenderPassResourceUsageTracker usageTracker,
Ref<AttachmentState> attachmentState,
- std::vector<TimestampWrite> timestampWritesAtEnd,
uint32_t renderTargetWidth,
uint32_t renderTargetHeight,
bool depthReadOnly,
@@ -70,7 +69,6 @@ class RenderPassEncoder final : public RenderEncoderBase {
EncodingContext* encodingContext,
RenderPassResourceUsageTracker usageTracker,
Ref<AttachmentState> attachmentState,
- std::vector<TimestampWrite> timestampWritesAtEnd,
uint32_t renderTargetWidth,
uint32_t renderTargetHeight,
bool depthReadOnly,
@@ -97,7 +95,8 @@ class RenderPassEncoder final : public RenderEncoderBase {
uint32_t mCurrentOcclusionQueryIndex = 0;
bool mOcclusionQueryActive = false;
- std::vector<TimestampWrite> mTimestampWritesAtEnd;
+ // This is the hardcoded value in the WebGPU spec.
+ uint64_t mMaxDrawCount = 50000000;
};
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderPipeline.cpp b/chromium/third_party/dawn/src/dawn/native/RenderPipeline.cpp
index 3ec6bdcd3ec..5c24d00ba81 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderPipeline.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/RenderPipeline.cpp
@@ -99,6 +99,11 @@ MaybeError ValidateVertexBufferLayout(
DAWN_INVALID_IF(buffer->arrayStride % 4 != 0,
"Vertex buffer arrayStride (%u) is not a multiple of 4.", buffer->arrayStride);
+ DAWN_INVALID_IF(
+ buffer->stepMode == wgpu::VertexStepMode::VertexBufferNotUsed && buffer->attributeCount > 0,
+ "attributeCount (%u) is not zero although vertex buffer stepMode is %s.",
+ buffer->attributeCount, wgpu::VertexStepMode::VertexBufferNotUsed);
+
for (uint32_t i = 0; i < buffer->attributeCount; ++i) {
DAWN_TRY_CONTEXT(ValidateVertexAttribute(device, &buffer->attributes[i], metadata,
buffer->arrayStride, attributesSetMask),
@@ -148,13 +153,11 @@ MaybeError ValidateVertexState(DeviceBase* device,
}
MaybeError ValidatePrimitiveState(const DeviceBase* device, const PrimitiveState* descriptor) {
- DAWN_TRY(
- ValidateSingleSType(descriptor->nextInChain, wgpu::SType::PrimitiveDepthClampingState));
- const PrimitiveDepthClampingState* clampInfo = nullptr;
- FindInChain(descriptor->nextInChain, &clampInfo);
- if (clampInfo && !device->IsFeatureEnabled(Feature::DepthClamping)) {
- return DAWN_VALIDATION_ERROR("The depth clamping feature is not supported");
- }
+ DAWN_TRY(ValidateSingleSType(descriptor->nextInChain, wgpu::SType::PrimitiveDepthClipControl));
+ const PrimitiveDepthClipControl* depthClipControl = nullptr;
+ FindInChain(descriptor->nextInChain, &depthClipControl);
+ DAWN_INVALID_IF(depthClipControl && !device->IsFeatureEnabled(Feature::DepthClipControl),
+ "%s is not supported", wgpu::FeatureName::DepthClipControl);
DAWN_TRY(ValidatePrimitiveTopology(descriptor->topology));
DAWN_TRY(ValidateIndexFormat(descriptor->stripIndexFormat));
DAWN_TRY(ValidateFrontFace(descriptor->frontFace));
@@ -321,7 +324,8 @@ MaybeError ValidateColorTargetState(
MaybeError ValidateFragmentState(DeviceBase* device,
const FragmentState* descriptor,
- const PipelineLayoutBase* layout) {
+ const PipelineLayoutBase* layout,
+ bool alphaToCoverageEnabled) {
DAWN_INVALID_IF(descriptor->nextInChain != nullptr, "nextInChain must be nullptr.");
DAWN_TRY_CONTEXT(ValidateProgrammableStage(device, descriptor->module, descriptor->entryPoint,
@@ -330,9 +334,10 @@ MaybeError ValidateFragmentState(DeviceBase* device,
"validating fragment stage (module: %s, entryPoint: %s).", descriptor->module,
descriptor->entryPoint);
- DAWN_INVALID_IF(descriptor->targetCount > kMaxColorAttachments,
+ uint32_t maxColorAttachments = device->GetLimits().v1.maxColorAttachments;
+ DAWN_INVALID_IF(descriptor->targetCount > maxColorAttachments,
"Number of targets (%u) exceeds the maximum (%u).", descriptor->targetCount,
- kMaxColorAttachments);
+ maxColorAttachments);
const EntryPointMetadata& fragmentMetadata =
descriptor->module->GetEntryPoint(descriptor->entryPoint);
@@ -351,6 +356,11 @@ MaybeError ValidateFragmentState(DeviceBase* device,
}
}
+ DAWN_INVALID_IF(fragmentMetadata.usesSampleMaskOutput && alphaToCoverageEnabled,
+ "alphaToCoverageEnabled is true when the sample_mask builtin is a "
+ "pipeline output of fragment stage of %s.",
+ descriptor->module);
+
return {};
}
@@ -441,7 +451,8 @@ MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
"validating multisample state.");
if (descriptor->fragment != nullptr) {
- DAWN_TRY_CONTEXT(ValidateFragmentState(device, descriptor->fragment, descriptor->layout),
+ DAWN_TRY_CONTEXT(ValidateFragmentState(device, descriptor->fragment, descriptor->layout,
+ descriptor->multisample.alphaToCoverageEnabled),
"validating fragment state.");
DAWN_INVALID_IF(descriptor->fragment->targetCount == 0 && !descriptor->depthStencil,
@@ -548,11 +559,12 @@ RenderPipelineBase::RenderPipelineBase(DeviceBase* device,
}
mPrimitive = descriptor->primitive;
- const PrimitiveDepthClampingState* clampInfo = nullptr;
- FindInChain(mPrimitive.nextInChain, &clampInfo);
- if (clampInfo) {
- mClampDepth = clampInfo->clampDepth;
+ const PrimitiveDepthClipControl* depthClipControl = nullptr;
+ FindInChain(mPrimitive.nextInChain, &depthClipControl);
+ if (depthClipControl) {
+ mUnclippedDepth = depthClipControl->unclippedDepth;
}
+
mMultisample = descriptor->multisample;
if (mAttachmentState->HasDepthStencilAttachment()) {
@@ -610,7 +622,7 @@ RenderPipelineBase::RenderPipelineBase(DeviceBase* device,
TrackInDevice();
// Initialize the cache key to include the cache type and device information.
- mCacheKey.Record(CacheKey::Type::RenderPipeline, device->GetCacheKey());
+ StreamIn(&mCacheKey, CacheKey::Type::RenderPipeline, device->GetCacheKey());
}
RenderPipelineBase::RenderPipelineBase(DeviceBase* device) : PipelineBase(device) {
@@ -747,9 +759,9 @@ float RenderPipelineBase::GetDepthBiasClamp() const {
return mDepthStencil.depthBiasClamp;
}
-bool RenderPipelineBase::ShouldClampDepth() const {
+bool RenderPipelineBase::HasUnclippedDepth() const {
ASSERT(!IsError());
- return mClampDepth;
+ return mUnclippedDepth;
}
ityp::bitset<ColorAttachmentIndex, kMaxColorAttachments>
@@ -856,7 +868,7 @@ size_t RenderPipelineBase::ComputeContentHash() {
// Record primitive state
recorder.Record(mPrimitive.topology, mPrimitive.stripIndexFormat, mPrimitive.frontFace,
- mPrimitive.cullMode, mClampDepth);
+ mPrimitive.cullMode, mUnclippedDepth);
// Record multisample state
// Sample count hashed as part of the attachment state
@@ -973,7 +985,7 @@ bool RenderPipelineBase::EqualityFunc::operator()(const RenderPipelineBase* a,
if (stateA.topology != stateB.topology ||
stateA.stripIndexFormat != stateB.stripIndexFormat ||
stateA.frontFace != stateB.frontFace || stateA.cullMode != stateB.cullMode ||
- a->mClampDepth != b->mClampDepth) {
+ a->mUnclippedDepth != b->mUnclippedDepth) {
return false;
}
}
diff --git a/chromium/third_party/dawn/src/dawn/native/RenderPipeline.h b/chromium/third_party/dawn/src/dawn/native/RenderPipeline.h
index f904f8a8931..afba4a7590d 100644
--- a/chromium/third_party/dawn/src/dawn/native/RenderPipeline.h
+++ b/chromium/third_party/dawn/src/dawn/native/RenderPipeline.h
@@ -90,7 +90,7 @@ class RenderPipelineBase : public PipelineBase {
int32_t GetDepthBias() const;
float GetDepthBiasSlopeScale() const;
float GetDepthBiasClamp() const;
- bool ShouldClampDepth() const;
+ bool HasUnclippedDepth() const;
ityp::bitset<ColorAttachmentIndex, kMaxColorAttachments> GetColorAttachmentsMask() const;
bool HasDepthStencilAttachment() const;
@@ -137,7 +137,7 @@ class RenderPipelineBase : public PipelineBase {
PrimitiveState mPrimitive;
DepthStencilState mDepthStencil;
MultisampleState mMultisample;
- bool mClampDepth = false;
+ bool mUnclippedDepth = false;
bool mWritesDepth = false;
bool mWritesStencil = false;
};
diff --git a/chromium/third_party/dawn/src/dawn/native/Serializable.h b/chromium/third_party/dawn/src/dawn/native/Serializable.h
new file mode 100644
index 00000000000..80d8339e2da
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/Serializable.h
@@ -0,0 +1,74 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_SERIALIZABLE_H_
+#define SRC_DAWN_NATIVE_SERIALIZABLE_H_
+
+#include <utility>
+
+#include "dawn/native/VisitableMembers.h"
+#include "dawn/native/stream/BlobSource.h"
+#include "dawn/native/stream/ByteVectorSink.h"
+#include "dawn/native/stream/Stream.h"
+
+namespace dawn::native {
+
+// Base CRTP for implementing StreamIn/StreamOut/FromBlob/ToBlob for Derived,
+// assuming Derived has VisitAll methods provided by DAWN_VISITABLE_MEMBERS.
+template <typename Derived>
+class Serializable {
+ public:
+ friend void StreamIn(stream::Sink* s, const Derived& in) {
+ in.VisitAll([&](const auto&... members) { StreamIn(s, members...); });
+ }
+
+ friend MaybeError StreamOut(stream::Source* s, Derived* out) {
+ return out->VisitAll([&](auto&... members) { return StreamOut(s, &members...); });
+ }
+
+ static ResultOrError<Derived> FromBlob(Blob blob) {
+ stream::BlobSource source(std::move(blob));
+ Derived out;
+ DAWN_TRY(StreamOut(&source, &out));
+ return out;
+ }
+
+ Blob ToBlob() const {
+ stream::ByteVectorSink sink;
+ StreamIn(&sink, static_cast<const Derived&>(*this));
+ return CreateBlob(std::move(sink));
+ }
+};
+} // namespace dawn::native
+
+// Helper macro to define a struct or class along with VisitAll methods to call
+// a functor on all members. Derives from Visitable which provides
+// implementations of StreamIn/StreamOut/FromBlob/ToBlob.
+// Example usage:
+// #define MEMBERS(X) \
+// X(int, a) \
+// X(float, b) \
+// X(Foo, foo) \
+// X(Bar, bar)
+// DAWN_SERIALIZABLE(struct, MyStruct, MEMBERS) {
+// void SomeAdditionalMethod();
+// };
+// #undef MEMBERS
+#define DAWN_SERIALIZABLE(qualifier, Name, MEMBERS) \
+ struct Name##__Contents { \
+ DAWN_VISITABLE_MEMBERS(MEMBERS) \
+ }; \
+ qualifier Name : Name##__Contents, public ::dawn::native::Serializable<Name>
+
+#endif // SRC_DAWN_NATIVE_SERIALIZABLE_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/ShaderModule.cpp b/chromium/third_party/dawn/src/dawn/native/ShaderModule.cpp
index 21edca997fa..c9871e8c772 100644
--- a/chromium/third_party/dawn/src/dawn/native/ShaderModule.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/ShaderModule.cpp
@@ -37,96 +37,15 @@ namespace dawn::native {
namespace {
-tint::transform::VertexFormat ToTintVertexFormat(wgpu::VertexFormat format) {
- switch (format) {
- case wgpu::VertexFormat::Uint8x2:
- return tint::transform::VertexFormat::kUint8x2;
- case wgpu::VertexFormat::Uint8x4:
- return tint::transform::VertexFormat::kUint8x4;
- case wgpu::VertexFormat::Sint8x2:
- return tint::transform::VertexFormat::kSint8x2;
- case wgpu::VertexFormat::Sint8x4:
- return tint::transform::VertexFormat::kSint8x4;
- case wgpu::VertexFormat::Unorm8x2:
- return tint::transform::VertexFormat::kUnorm8x2;
- case wgpu::VertexFormat::Unorm8x4:
- return tint::transform::VertexFormat::kUnorm8x4;
- case wgpu::VertexFormat::Snorm8x2:
- return tint::transform::VertexFormat::kSnorm8x2;
- case wgpu::VertexFormat::Snorm8x4:
- return tint::transform::VertexFormat::kSnorm8x4;
- case wgpu::VertexFormat::Uint16x2:
- return tint::transform::VertexFormat::kUint16x2;
- case wgpu::VertexFormat::Uint16x4:
- return tint::transform::VertexFormat::kUint16x4;
- case wgpu::VertexFormat::Sint16x2:
- return tint::transform::VertexFormat::kSint16x2;
- case wgpu::VertexFormat::Sint16x4:
- return tint::transform::VertexFormat::kSint16x4;
- case wgpu::VertexFormat::Unorm16x2:
- return tint::transform::VertexFormat::kUnorm16x2;
- case wgpu::VertexFormat::Unorm16x4:
- return tint::transform::VertexFormat::kUnorm16x4;
- case wgpu::VertexFormat::Snorm16x2:
- return tint::transform::VertexFormat::kSnorm16x2;
- case wgpu::VertexFormat::Snorm16x4:
- return tint::transform::VertexFormat::kSnorm16x4;
- case wgpu::VertexFormat::Float16x2:
- return tint::transform::VertexFormat::kFloat16x2;
- case wgpu::VertexFormat::Float16x4:
- return tint::transform::VertexFormat::kFloat16x4;
- case wgpu::VertexFormat::Float32:
- return tint::transform::VertexFormat::kFloat32;
- case wgpu::VertexFormat::Float32x2:
- return tint::transform::VertexFormat::kFloat32x2;
- case wgpu::VertexFormat::Float32x3:
- return tint::transform::VertexFormat::kFloat32x3;
- case wgpu::VertexFormat::Float32x4:
- return tint::transform::VertexFormat::kFloat32x4;
- case wgpu::VertexFormat::Uint32:
- return tint::transform::VertexFormat::kUint32;
- case wgpu::VertexFormat::Uint32x2:
- return tint::transform::VertexFormat::kUint32x2;
- case wgpu::VertexFormat::Uint32x3:
- return tint::transform::VertexFormat::kUint32x3;
- case wgpu::VertexFormat::Uint32x4:
- return tint::transform::VertexFormat::kUint32x4;
- case wgpu::VertexFormat::Sint32:
- return tint::transform::VertexFormat::kSint32;
- case wgpu::VertexFormat::Sint32x2:
- return tint::transform::VertexFormat::kSint32x2;
- case wgpu::VertexFormat::Sint32x3:
- return tint::transform::VertexFormat::kSint32x3;
- case wgpu::VertexFormat::Sint32x4:
- return tint::transform::VertexFormat::kSint32x4;
-
- case wgpu::VertexFormat::Undefined:
- break;
- }
- UNREACHABLE();
-}
-
-tint::transform::VertexStepMode ToTintVertexStepMode(wgpu::VertexStepMode mode) {
- switch (mode) {
- case wgpu::VertexStepMode::Vertex:
- return tint::transform::VertexStepMode::kVertex;
- case wgpu::VertexStepMode::Instance:
- return tint::transform::VertexStepMode::kInstance;
- case wgpu::VertexStepMode::VertexBufferNotUsed:
- UNREACHABLE();
- }
-}
-
-ResultOrError<SingleShaderStage> TintPipelineStageToShaderStage(tint::ast::PipelineStage stage) {
+ResultOrError<SingleShaderStage> TintPipelineStageToShaderStage(
+ tint::inspector::PipelineStage stage) {
switch (stage) {
- case tint::ast::PipelineStage::kVertex:
+ case tint::inspector::PipelineStage::kVertex:
return SingleShaderStage::Vertex;
- case tint::ast::PipelineStage::kFragment:
+ case tint::inspector::PipelineStage::kFragment:
return SingleShaderStage::Fragment;
- case tint::ast::PipelineStage::kCompute:
+ case tint::inspector::PipelineStage::kCompute:
return SingleShaderStage::Compute;
- case tint::ast::PipelineStage::kNone:
- break;
}
UNREACHABLE();
}
@@ -358,17 +277,16 @@ ResultOrError<InterpolationSampling> TintInterpolationSamplingToInterpolationSam
UNREACHABLE();
}
-EntryPointMetadata::OverridableConstant::Type FromTintOverridableConstantType(
- tint::inspector::OverridableConstant::Type type) {
+EntryPointMetadata::Override::Type FromTintOverrideType(tint::inspector::Override::Type type) {
switch (type) {
- case tint::inspector::OverridableConstant::Type::kBool:
- return EntryPointMetadata::OverridableConstant::Type::Boolean;
- case tint::inspector::OverridableConstant::Type::kFloat32:
- return EntryPointMetadata::OverridableConstant::Type::Float32;
- case tint::inspector::OverridableConstant::Type::kInt32:
- return EntryPointMetadata::OverridableConstant::Type::Int32;
- case tint::inspector::OverridableConstant::Type::kUint32:
- return EntryPointMetadata::OverridableConstant::Type::Uint32;
+ case tint::inspector::Override::Type::kBool:
+ return EntryPointMetadata::Override::Type::Boolean;
+ case tint::inspector::Override::Type::kFloat32:
+ return EntryPointMetadata::Override::Type::Float32;
+ case tint::inspector::Override::Type::kInt32:
+ return EntryPointMetadata::Override::Type::Int32;
+ case tint::inspector::Override::Type::kUint32:
+ return EntryPointMetadata::Override::Type::Uint32;
}
UNREACHABLE();
}
@@ -610,17 +528,17 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
return invalid; \
})()
- if (!entryPoint.overridable_constants.empty()) {
+ if (!entryPoint.overrides.empty()) {
DAWN_INVALID_IF(device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs),
"Pipeline overridable constants are disallowed because they "
"are partially implemented.");
- const auto& name2Id = inspector->GetConstantNameToIdMap();
- const auto& id2Scalar = inspector->GetConstantIDs();
+ const auto& name2Id = inspector->GetNamedOverrideIds();
+ const auto& id2Scalar = inspector->GetOverrideDefaultValues();
- for (auto& c : entryPoint.overridable_constants) {
- uint32_t id = name2Id.at(c.name);
- OverridableConstantScalar defaultValue;
+ for (auto& c : entryPoint.overrides) {
+ auto id = name2Id.at(c.name);
+ OverrideScalar defaultValue;
if (c.is_initialized) {
// if it is initialized, the scalar must exist
const auto& scalar = id2Scalar.at(id);
@@ -636,21 +554,19 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
UNREACHABLE();
}
}
- EntryPointMetadata::OverridableConstant constant = {
- id, FromTintOverridableConstantType(c.type), c.is_initialized, defaultValue};
+ EntryPointMetadata::Override override = {id.value, FromTintOverrideType(c.type),
+ c.is_initialized, defaultValue};
- std::string identifier =
- c.is_numeric_id_specified ? std::to_string(constant.id) : c.name;
- metadata->overridableConstants[identifier] = constant;
+ std::string identifier = c.is_id_specified ? std::to_string(override.id) : c.name;
+ metadata->overrides[identifier] = override;
if (!c.is_initialized) {
auto [_, inserted] =
- metadata->uninitializedOverridableConstants.emplace(std::move(identifier));
+ metadata->uninitializedOverrides.emplace(std::move(identifier));
// The insertion should have taken place
ASSERT(inserted);
} else {
- auto [_, inserted] =
- metadata->initializedOverridableConstants.emplace(std::move(identifier));
+ auto [_, inserted] = metadata->initializedOverrides.emplace(std::move(identifier));
// The insertion should have taken place
ASSERT(inserted);
}
@@ -660,19 +576,24 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
DAWN_TRY_ASSIGN(metadata->stage, TintPipelineStageToShaderStage(entryPoint.stage));
if (metadata->stage == SingleShaderStage::Compute) {
- DelayedInvalidIf(entryPoint.workgroup_size_x > limits.v1.maxComputeWorkgroupSizeX ||
- entryPoint.workgroup_size_y > limits.v1.maxComputeWorkgroupSizeY ||
- entryPoint.workgroup_size_z > limits.v1.maxComputeWorkgroupSizeZ,
+ auto workgroup_size = entryPoint.workgroup_size;
+ DAWN_INVALID_IF(
+ !workgroup_size.has_value(),
+ "TODO(crbug.com/dawn/1504): Dawn does not currently support @workgroup_size "
+ "attributes using override-expressions");
+ DelayedInvalidIf(workgroup_size->x > limits.v1.maxComputeWorkgroupSizeX ||
+ workgroup_size->y > limits.v1.maxComputeWorkgroupSizeY ||
+ workgroup_size->z > limits.v1.maxComputeWorkgroupSizeZ,
"Entry-point uses workgroup_size(%u, %u, %u) that exceeds the "
"maximum allowed (%u, %u, %u).",
- entryPoint.workgroup_size_x, entryPoint.workgroup_size_y,
- entryPoint.workgroup_size_z, limits.v1.maxComputeWorkgroupSizeX,
- limits.v1.maxComputeWorkgroupSizeY, limits.v1.maxComputeWorkgroupSizeZ);
+ workgroup_size->x, workgroup_size->y, workgroup_size->z,
+ limits.v1.maxComputeWorkgroupSizeX, limits.v1.maxComputeWorkgroupSizeY,
+ limits.v1.maxComputeWorkgroupSizeZ);
// Dimensions have already been validated against their individual limits above.
// Cast to uint64_t to avoid overflow in this multiplication.
- uint64_t numInvocations = static_cast<uint64_t>(entryPoint.workgroup_size_x) *
- entryPoint.workgroup_size_y * entryPoint.workgroup_size_z;
+ uint64_t numInvocations =
+ static_cast<uint64_t>(workgroup_size->x) * workgroup_size->y * workgroup_size->z;
DelayedInvalidIf(numInvocations > limits.v1.maxComputeInvocationsPerWorkgroup,
"The total number of workgroup invocations (%u) exceeds the "
"maximum allowed (%u).",
@@ -684,9 +605,9 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
"the maximum allowed (%u bytes).",
workgroupStorageSize, limits.v1.maxComputeWorkgroupStorageSize);
- metadata->localWorkgroupSize.x = entryPoint.workgroup_size_x;
- metadata->localWorkgroupSize.y = entryPoint.workgroup_size_y;
- metadata->localWorkgroupSize.z = entryPoint.workgroup_size_z;
+ metadata->localWorkgroupSize.x = workgroup_size->x;
+ metadata->localWorkgroupSize.y = workgroup_size->y;
+ metadata->localWorkgroupSize.z = workgroup_size->z;
metadata->usesNumWorkgroups = entryPoint.num_workgroups_used;
}
@@ -773,6 +694,7 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
if (entryPoint.input_sample_mask_used) {
totalInterStageShaderComponents += 1;
}
+ metadata->usesSampleMaskOutput = entryPoint.output_sample_mask_used;
if (entryPoint.sample_index_used) {
totalInterStageShaderComponents += 1;
}
@@ -784,6 +706,7 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
"Total fragment input components count (%u) exceeds the maximum (%u).",
totalInterStageShaderComponents, kMaxInterStageShaderComponents);
+ uint32_t maxColorAttachments = device->GetLimits().v1.maxColorAttachments;
for (const auto& outputVar : entryPoint.output_variables) {
EntryPointMetadata::FragmentOutputVariableInfo variable;
DAWN_TRY_ASSIGN(variable.baseType,
@@ -793,10 +716,10 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
ASSERT(variable.componentCount <= 4);
uint32_t unsanitizedAttachment = outputVar.location_decoration;
- if (DelayedInvalidIf(unsanitizedAttachment >= kMaxColorAttachments,
+ if (DelayedInvalidIf(unsanitizedAttachment >= maxColorAttachments,
"Fragment output variable \"%s\" has a location (%u) that "
"exceeds the maximum (%u).",
- outputVar.name, unsanitizedAttachment, kMaxColorAttachments)) {
+ outputVar.name, unsanitizedAttachment, maxColorAttachments)) {
continue;
}
@@ -883,9 +806,8 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
resource.binding, resource.bind_group);
}
- std::vector<tint::inspector::SamplerTexturePair> samplerTextureUses =
- inspector->GetSamplerTextureUses(entryPoint.name);
- metadata->samplerTexturePairs.reserve(samplerTextureUses.size());
+ auto samplerTextureUses = inspector->GetSamplerTextureUses(entryPoint.name);
+ metadata->samplerTexturePairs.reserve(samplerTextureUses.Length());
std::transform(samplerTextureUses.begin(), samplerTextureUses.end(),
std::back_inserter(metadata->samplerTexturePairs),
[](const tint::inspector::SamplerTexturePair& pair) {
@@ -1084,39 +1006,6 @@ ResultOrError<tint::Program> RunTransforms(tint::transform::Transform* transform
return std::move(output.program);
}
-void AddVertexPullingTransformConfig(const RenderPipelineBase& renderPipeline,
- const std::string& entryPoint,
- BindGroupIndex pullingBufferBindingSet,
- tint::transform::DataMap* transformInputs) {
- tint::transform::VertexPulling::Config cfg;
- cfg.entry_point_name = entryPoint;
- cfg.pulling_group = static_cast<uint32_t>(pullingBufferBindingSet);
-
- cfg.vertex_state.resize(renderPipeline.GetVertexBufferCount());
- for (VertexBufferSlot slot : IterateBitSet(renderPipeline.GetVertexBufferSlotsUsed())) {
- const VertexBufferInfo& dawnInfo = renderPipeline.GetVertexBuffer(slot);
- tint::transform::VertexBufferLayoutDescriptor* tintInfo =
- &cfg.vertex_state[static_cast<uint8_t>(slot)];
-
- tintInfo->array_stride = dawnInfo.arrayStride;
- tintInfo->step_mode = ToTintVertexStepMode(dawnInfo.stepMode);
- }
-
- for (VertexAttributeLocation location :
- IterateBitSet(renderPipeline.GetAttributeLocationsUsed())) {
- const VertexAttributeInfo& dawnInfo = renderPipeline.GetAttribute(location);
- tint::transform::VertexAttributeDescriptor tintInfo;
- tintInfo.format = ToTintVertexFormat(dawnInfo.format);
- tintInfo.offset = dawnInfo.offset;
- tintInfo.shader_location = static_cast<uint32_t>(static_cast<uint8_t>(location));
-
- uint8_t vertexBufferSlot = static_cast<uint8_t>(dawnInfo.vertexBufferSlot);
- cfg.vertex_state[vertexBufferSlot].attributes.push_back(tintInfo);
- }
-
- transformInputs->Add<tint::transform::VertexPulling::Config>(cfg);
-}
-
MaybeError ValidateCompatibilityWithPipelineLayout(DeviceBase* device,
const EntryPointMetadata& entryPoint,
const PipelineLayoutBase* layout) {
@@ -1302,29 +1191,6 @@ OwnedCompilationMessages* ShaderModuleBase::GetCompilationMessages() const {
return mCompilationMessages.get();
}
-// static
-void ShaderModuleBase::AddExternalTextureTransform(const PipelineLayoutBase* layout,
- tint::transform::Manager* transformManager,
- tint::transform::DataMap* transformInputs) {
- tint::transform::MultiplanarExternalTexture::BindingsMap newBindingsMap;
- for (BindGroupIndex i : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
- const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(i);
-
- for (const auto& expansion : bgl->GetExternalTextureBindingExpansionMap()) {
- newBindingsMap[{static_cast<uint32_t>(i),
- static_cast<uint32_t>(expansion.second.plane0)}] = {
- {static_cast<uint32_t>(i), static_cast<uint32_t>(expansion.second.plane1)},
- {static_cast<uint32_t>(i), static_cast<uint32_t>(expansion.second.params)}};
- }
- }
-
- if (!newBindingsMap.empty()) {
- transformManager->Add<tint::transform::MultiplanarExternalTexture>();
- transformInputs->Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
- newBindingsMap);
- }
-}
-
MaybeError ShaderModuleBase::InitializeBase(ShaderModuleParseResult* parseResult,
OwnedCompilationMessages* compilationMessages) {
mTintProgram = std::move(parseResult->tintProgram);
diff --git a/chromium/third_party/dawn/src/dawn/native/ShaderModule.h b/chromium/third_party/dawn/src/dawn/native/ShaderModule.h
index 1df775cfbae..170b3880007 100644
--- a/chromium/third_party/dawn/src/dawn/native/ShaderModule.h
+++ b/chromium/third_party/dawn/src/dawn/native/ShaderModule.h
@@ -116,12 +116,6 @@ ResultOrError<tint::Program> RunTransforms(tint::transform::Transform* transform
tint::transform::DataMap* outputs,
OwnedCompilationMessages* messages);
-/// Creates and adds the tint::transform::VertexPulling::Config to transformInputs.
-void AddVertexPullingTransformConfig(const RenderPipelineBase& renderPipeline,
- const std::string& entryPoint,
- BindGroupIndex pullingBufferBindingSet,
- tint::transform::DataMap* transformInputs);
-
// Mirrors wgpu::SamplerBindingLayout but instead stores a single boolean
// for isComparison instead of a wgpu::SamplerBindingType enum.
struct ShaderSamplerBindingInfo {
@@ -155,8 +149,8 @@ struct ShaderBindingInfo {
using BindingGroupInfoMap = std::map<BindingNumber, ShaderBindingInfo>;
using BindingInfoArray = ityp::array<BindGroupIndex, BindingGroupInfoMap, kMaxBindGroups>;
-// The WebGPU overridable constants only support these scalar types
-union OverridableConstantScalar {
+// The WebGPU override variables only support these scalar types
+union OverrideScalar {
// Use int32_t for boolean to initialize the full 32bit
int32_t b;
float f32;
@@ -216,9 +210,9 @@ struct EntryPointMetadata {
// The shader stage for this binding.
SingleShaderStage stage;
- struct OverridableConstant {
+ struct Override {
uint32_t id;
- // Match tint::inspector::OverridableConstant::Type
+ // Match tint::inspector::Override::Type
// Bool is defined as a macro on linux X11 and cannot compile
enum class Type { Boolean, Float32, Uint32, Int32 } type;
@@ -230,25 +224,27 @@ struct EntryPointMetadata {
// Store the default initialized value in shader
// This is used by metal backend as the function_constant does not have dafault values
// Initialized when isInitialized == true
- OverridableConstantScalar defaultValue;
+ OverrideScalar defaultValue;
};
- using OverridableConstantsMap = std::unordered_map<std::string, OverridableConstant>;
+ using OverridesMap = std::unordered_map<std::string, Override>;
- // Map identifier to overridable constant
+ // Map identifier to override variable
// Identifier is unique: either the variable name or the numeric ID if specified
- OverridableConstantsMap overridableConstants;
+ OverridesMap overrides;
- // Overridable constants that are not initialized in shaders
+ // Override variables that are not initialized in shaders
// They need value initialization from pipeline stage or it is a validation error
- std::unordered_set<std::string> uninitializedOverridableConstants;
+ std::unordered_set<std::string> uninitializedOverrides;
// Store constants with shader initialized values as well
// This is used by metal backend to set values with default initializers that are not
// overridden
- std::unordered_set<std::string> initializedOverridableConstants;
+ std::unordered_set<std::string> initializedOverrides;
bool usesNumWorkgroups = false;
+ // Used at render pipeline validation.
+ bool usesSampleMaskOutput = false;
};
class ShaderModuleBase : public ApiObjectBase, public CachedObject {
@@ -293,10 +289,6 @@ class ShaderModuleBase : public ApiObjectBase, public CachedObject {
MaybeError InitializeBase(ShaderModuleParseResult* parseResult,
OwnedCompilationMessages* compilationMessages);
- static void AddExternalTextureTransform(const PipelineLayoutBase* layout,
- tint::transform::Manager* transformManager,
- tint::transform::DataMap* transformInputs);
-
private:
ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag);
diff --git a/chromium/third_party/dawn/src/dawn/native/SpirvValidation.cpp b/chromium/third_party/dawn/src/dawn/native/SpirvValidation.cpp
index b40a80390e3..235fdbb346e 100644
--- a/chromium/third_party/dawn/src/dawn/native/SpirvValidation.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/SpirvValidation.cpp
@@ -23,7 +23,10 @@
namespace dawn::native {
-MaybeError ValidateSpirv(DeviceBase* device, const std::vector<uint32_t>& spirv, bool dumpSpirv) {
+MaybeError ValidateSpirv(DeviceBase* device,
+ const uint32_t* spirv,
+ size_t wordCount,
+ bool dumpSpirv) {
spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
spirvTools.SetMessageConsumer([device](spv_message_level_t level, const char*,
const spv_position_t& position, const char* message) {
@@ -50,12 +53,12 @@ MaybeError ValidateSpirv(DeviceBase* device, const std::vector<uint32_t>& spirv,
device->EmitLog(wgpuLogLevel, ss.str().c_str());
});
- const bool valid = spirvTools.Validate(spirv);
+ const bool valid = spirvTools.Validate(spirv, wordCount);
if (dumpSpirv || !valid) {
std::ostringstream dumpedMsg;
std::string disassembly;
if (spirvTools.Disassemble(
- spirv, &disassembly,
+ spirv, wordCount, &disassembly,
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT)) {
dumpedMsg << "/* Dumped generated SPIRV disassembly */" << std::endl << disassembly;
} else {
diff --git a/chromium/third_party/dawn/src/dawn/native/SpirvValidation.h b/chromium/third_party/dawn/src/dawn/native/SpirvValidation.h
index b50d38af777..b73d5f06adb 100644
--- a/chromium/third_party/dawn/src/dawn/native/SpirvValidation.h
+++ b/chromium/third_party/dawn/src/dawn/native/SpirvValidation.h
@@ -15,15 +15,16 @@
#ifndef SRC_DAWN_NATIVE_SPIRVVALIDATION_H_
#define SRC_DAWN_NATIVE_SPIRVVALIDATION_H_
-#include <vector>
-
#include "dawn/native/Error.h"
namespace dawn::native {
class DeviceBase;
-MaybeError ValidateSpirv(DeviceBase* device, const std::vector<uint32_t>& spirv, bool dumpSpirv);
+MaybeError ValidateSpirv(DeviceBase* device,
+ const uint32_t* spirv,
+ size_t wordCount,
+ bool dumpSpirv);
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/StreamImplTint.cpp b/chromium/third_party/dawn/src/dawn/native/StreamImplTint.cpp
new file mode 100644
index 00000000000..13a70cabb53
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/StreamImplTint.cpp
@@ -0,0 +1,117 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/native/stream/Stream.h"
+
+#include "dawn/native/TintUtils.h"
+#include "tint/writer/array_length_from_uniform_options.h"
+
+namespace dawn::native {
+
+// static
+template <>
+void stream::Stream<tint::Program>::Write(stream::Sink* sink, const tint::Program& p) {
+#if TINT_BUILD_WGSL_WRITER
+ tint::writer::wgsl::Options options{};
+ StreamIn(sink, tint::writer::wgsl::Generate(&p, options).wgsl);
+#else
+ // TODO(crbug.com/dawn/1481): We shouldn't need to write back to WGSL if we have a CacheKey
+ // built from the initial shader module input. Then, we would never need to parse the program
+ // and write back out to WGSL.
+ UNREACHABLE();
+#endif
+}
+
+// static
+template <>
+void stream::Stream<tint::sem::BindingPoint>::Write(stream::Sink* sink,
+ const tint::sem::BindingPoint& p) {
+ static_assert(offsetof(tint::sem::BindingPoint, group) == 0,
+ "Please update serialization for tint::sem::BindingPoint");
+ static_assert(offsetof(tint::sem::BindingPoint, binding) == 4,
+ "Please update serialization for tint::sem::BindingPoint");
+ static_assert(sizeof(tint::sem::BindingPoint) == 8,
+ "Please update serialization for tint::sem::BindingPoint");
+ StreamIn(sink, p.group, p.binding);
+}
+
+// static
+template <>
+void stream::Stream<tint::transform::BindingPoints>::Write(
+ stream::Sink* sink,
+ const tint::transform::BindingPoints& points) {
+ static_assert(offsetof(tint::transform::BindingPoints, plane_1) == 0,
+ "Please update serialization for tint::transform::BindingPoints");
+ static_assert(offsetof(tint::transform::BindingPoints, params) == 8,
+ "Please update serialization for tint::transform::BindingPoints");
+ static_assert(sizeof(tint::transform::BindingPoints) == 16,
+ "Please update serialization for tint::transform::BindingPoints");
+ StreamIn(sink, points.plane_1, points.params);
+}
+
+template <>
+void stream::Stream<tint::transform::VertexPulling::Config>::Write(
+ stream::Sink* sink,
+ const tint::transform::VertexPulling::Config& cfg) {
+ StreamIn(sink, cfg.entry_point_name, cfg.vertex_state, cfg.pulling_group);
+}
+
+template <>
+void stream::Stream<tint::transform::VertexBufferLayoutDescriptor>::Write(
+ stream::Sink* sink,
+ const tint::transform::VertexBufferLayoutDescriptor& layout) {
+ using Layout = tint::transform::VertexBufferLayoutDescriptor;
+ static_assert(offsetof(Layout, array_stride) == 0,
+ "Please update serialization for tint::transform::VertexBufferLayoutDescriptor");
+ static_assert(offsetof(Layout, step_mode) == 4,
+ "Please update serialization for tint::transform::VertexBufferLayoutDescriptor");
+ static_assert(offsetof(Layout, attributes) == 8,
+ "Please update serialization for tint::transform::VertexBufferLayoutDescriptor");
+ StreamIn(sink, layout.array_stride, layout.step_mode, layout.attributes);
+}
+
+template <>
+void stream::Stream<tint::transform::VertexAttributeDescriptor>::Write(
+ stream::Sink* sink,
+ const tint::transform::VertexAttributeDescriptor& attrib) {
+ using Attrib = tint::transform::VertexAttributeDescriptor;
+ static_assert(offsetof(Attrib, format) == 0,
+ "Please update serialization for tint::transform::VertexAttributeDescriptor");
+ static_assert(offsetof(Attrib, offset) == 4,
+ "Please update serialization for tint::transform::VertexAttributeDescriptor");
+ static_assert(offsetof(Attrib, shader_location) == 8,
+ "Please update serialization for tint::transform::VertexAttributeDescriptor");
+ static_assert(sizeof(Attrib) == 12,
+ "Please update serialization for tint::transform::VertexAttributeDescriptor");
+ StreamIn(sink, attrib.format, attrib.offset, attrib.shader_location);
+}
+
+// static
+template <>
+void stream::Stream<tint::writer::ArrayLengthFromUniformOptions>::Write(
+ stream::Sink* sink,
+ const tint::writer::ArrayLengthFromUniformOptions& o) {
+ static_assert(offsetof(tint::writer::ArrayLengthFromUniformOptions, ubo_binding) == 0,
+ "Please update serialization for tint::writer::ArrayLengthFromUniformOptions");
+ static_assert(
+ offsetof(tint::writer::ArrayLengthFromUniformOptions, bindpoint_to_size_index) == 8,
+ "Please update serialization for tint::writer::ArrayLengthFromUniformOptions");
+ static_assert(
+ sizeof(tint::writer::ArrayLengthFromUniformOptions) ==
+ 8 + sizeof(tint::writer::ArrayLengthFromUniformOptions::bindpoint_to_size_index),
+ "Please update serialization for tint::writer::ArrayLengthFromUniformOptions");
+ StreamIn(sink, o.ubo_binding, o.bindpoint_to_size_index);
+}
+
+} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/Texture.cpp b/chromium/third_party/dawn/src/dawn/native/Texture.cpp
index 7b1526a04a5..d170bff2b64 100644
--- a/chromium/third_party/dawn/src/dawn/native/Texture.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Texture.cpp
@@ -340,7 +340,7 @@ MaybeError ValidateTextureDescriptor(const DeviceBase* device,
DAWN_INVALID_IF(
internalUsageDesc != nullptr && !device->IsFeatureEnabled(Feature::DawnInternalUsages),
- "The dawn-internal-usages feature is not enabled");
+ "The internalUsageDesc is not empty while the dawn-internal-usages feature is not enabled");
const Format* format;
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
@@ -650,6 +650,10 @@ wgpu::TextureUsage TextureBase::GetInternalUsage() const {
ASSERT(!IsError());
return mInternalUsage;
}
+void TextureBase::AddInternalUsage(wgpu::TextureUsage usage) {
+ ASSERT(!IsError());
+ mInternalUsage |= usage;
+}
TextureBase::TextureState TextureBase::GetTextureState() const {
ASSERT(!IsError());
diff --git a/chromium/third_party/dawn/src/dawn/native/Texture.h b/chromium/third_party/dawn/src/dawn/native/Texture.h
index 595809442bc..84faa6914de 100644
--- a/chromium/third_party/dawn/src/dawn/native/Texture.h
+++ b/chromium/third_party/dawn/src/dawn/native/Texture.h
@@ -112,6 +112,7 @@ class TextureBase : public ApiObjectBase {
~TextureBase() override;
void DestroyImpl() override;
+ void AddInternalUsage(wgpu::TextureUsage usage);
private:
TextureBase(DeviceBase* device, const TextureDescriptor* descriptor, ObjectBase::ErrorTag tag);
diff --git a/chromium/third_party/dawn/src/dawn/native/TintUtils.cpp b/chromium/third_party/dawn/src/dawn/native/TintUtils.cpp
index ca4aea40e4a..f59e6e5cd15 100644
--- a/chromium/third_party/dawn/src/dawn/native/TintUtils.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/TintUtils.cpp
@@ -14,7 +14,10 @@
#include "dawn/native/TintUtils.h"
+#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/Device.h"
+#include "dawn/native/PipelineLayout.h"
+#include "dawn/native/RenderPipeline.h"
#include "tint/tint.h"
@@ -35,6 +38,87 @@ bool InitializeTintErrorReporter() {
return true;
}
+tint::transform::VertexFormat ToTintVertexFormat(wgpu::VertexFormat format) {
+ switch (format) {
+ case wgpu::VertexFormat::Uint8x2:
+ return tint::transform::VertexFormat::kUint8x2;
+ case wgpu::VertexFormat::Uint8x4:
+ return tint::transform::VertexFormat::kUint8x4;
+ case wgpu::VertexFormat::Sint8x2:
+ return tint::transform::VertexFormat::kSint8x2;
+ case wgpu::VertexFormat::Sint8x4:
+ return tint::transform::VertexFormat::kSint8x4;
+ case wgpu::VertexFormat::Unorm8x2:
+ return tint::transform::VertexFormat::kUnorm8x2;
+ case wgpu::VertexFormat::Unorm8x4:
+ return tint::transform::VertexFormat::kUnorm8x4;
+ case wgpu::VertexFormat::Snorm8x2:
+ return tint::transform::VertexFormat::kSnorm8x2;
+ case wgpu::VertexFormat::Snorm8x4:
+ return tint::transform::VertexFormat::kSnorm8x4;
+ case wgpu::VertexFormat::Uint16x2:
+ return tint::transform::VertexFormat::kUint16x2;
+ case wgpu::VertexFormat::Uint16x4:
+ return tint::transform::VertexFormat::kUint16x4;
+ case wgpu::VertexFormat::Sint16x2:
+ return tint::transform::VertexFormat::kSint16x2;
+ case wgpu::VertexFormat::Sint16x4:
+ return tint::transform::VertexFormat::kSint16x4;
+ case wgpu::VertexFormat::Unorm16x2:
+ return tint::transform::VertexFormat::kUnorm16x2;
+ case wgpu::VertexFormat::Unorm16x4:
+ return tint::transform::VertexFormat::kUnorm16x4;
+ case wgpu::VertexFormat::Snorm16x2:
+ return tint::transform::VertexFormat::kSnorm16x2;
+ case wgpu::VertexFormat::Snorm16x4:
+ return tint::transform::VertexFormat::kSnorm16x4;
+ case wgpu::VertexFormat::Float16x2:
+ return tint::transform::VertexFormat::kFloat16x2;
+ case wgpu::VertexFormat::Float16x4:
+ return tint::transform::VertexFormat::kFloat16x4;
+ case wgpu::VertexFormat::Float32:
+ return tint::transform::VertexFormat::kFloat32;
+ case wgpu::VertexFormat::Float32x2:
+ return tint::transform::VertexFormat::kFloat32x2;
+ case wgpu::VertexFormat::Float32x3:
+ return tint::transform::VertexFormat::kFloat32x3;
+ case wgpu::VertexFormat::Float32x4:
+ return tint::transform::VertexFormat::kFloat32x4;
+ case wgpu::VertexFormat::Uint32:
+ return tint::transform::VertexFormat::kUint32;
+ case wgpu::VertexFormat::Uint32x2:
+ return tint::transform::VertexFormat::kUint32x2;
+ case wgpu::VertexFormat::Uint32x3:
+ return tint::transform::VertexFormat::kUint32x3;
+ case wgpu::VertexFormat::Uint32x4:
+ return tint::transform::VertexFormat::kUint32x4;
+ case wgpu::VertexFormat::Sint32:
+ return tint::transform::VertexFormat::kSint32;
+ case wgpu::VertexFormat::Sint32x2:
+ return tint::transform::VertexFormat::kSint32x2;
+ case wgpu::VertexFormat::Sint32x3:
+ return tint::transform::VertexFormat::kSint32x3;
+ case wgpu::VertexFormat::Sint32x4:
+ return tint::transform::VertexFormat::kSint32x4;
+
+ case wgpu::VertexFormat::Undefined:
+ break;
+ }
+ UNREACHABLE();
+}
+
+tint::transform::VertexStepMode ToTintVertexStepMode(wgpu::VertexStepMode mode) {
+ switch (mode) {
+ case wgpu::VertexStepMode::Vertex:
+ return tint::transform::VertexStepMode::kVertex;
+ case wgpu::VertexStepMode::Instance:
+ return tint::transform::VertexStepMode::kInstance;
+ case wgpu::VertexStepMode::VertexBufferNotUsed:
+ break;
+ }
+ UNREACHABLE();
+}
+
} // namespace
ScopedTintICEHandler::ScopedTintICEHandler(DeviceBase* device) {
@@ -53,4 +137,58 @@ ScopedTintICEHandler::~ScopedTintICEHandler() {
tlDevice = nullptr;
}
+tint::transform::MultiplanarExternalTexture::BindingsMap BuildExternalTextureTransformBindings(
+ const PipelineLayoutBase* layout) {
+ tint::transform::MultiplanarExternalTexture::BindingsMap newBindingsMap;
+ for (BindGroupIndex i : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
+ const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(i);
+ for (const auto& [_, expansion] : bgl->GetExternalTextureBindingExpansionMap()) {
+ newBindingsMap[{static_cast<uint32_t>(i), static_cast<uint32_t>(expansion.plane0)}] = {
+ {static_cast<uint32_t>(i), static_cast<uint32_t>(expansion.plane1)},
+ {static_cast<uint32_t>(i), static_cast<uint32_t>(expansion.params)}};
+ }
+ }
+ return newBindingsMap;
+}
+
+tint::transform::VertexPulling::Config BuildVertexPullingTransformConfig(
+ const RenderPipelineBase& renderPipeline,
+ const std::string_view& entryPoint,
+ BindGroupIndex pullingBufferBindingSet) {
+ tint::transform::VertexPulling::Config cfg;
+ cfg.entry_point_name = entryPoint;
+ cfg.pulling_group = static_cast<uint32_t>(pullingBufferBindingSet);
+
+ cfg.vertex_state.resize(renderPipeline.GetVertexBufferCount());
+ for (VertexBufferSlot slot : IterateBitSet(renderPipeline.GetVertexBufferSlotsUsed())) {
+ const VertexBufferInfo& dawnInfo = renderPipeline.GetVertexBuffer(slot);
+ tint::transform::VertexBufferLayoutDescriptor* tintInfo =
+ &cfg.vertex_state[static_cast<uint8_t>(slot)];
+
+ tintInfo->array_stride = dawnInfo.arrayStride;
+ tintInfo->step_mode = ToTintVertexStepMode(dawnInfo.stepMode);
+ }
+
+ for (VertexAttributeLocation location :
+ IterateBitSet(renderPipeline.GetAttributeLocationsUsed())) {
+ const VertexAttributeInfo& dawnInfo = renderPipeline.GetAttribute(location);
+ tint::transform::VertexAttributeDescriptor tintInfo;
+ tintInfo.format = ToTintVertexFormat(dawnInfo.format);
+ tintInfo.offset = dawnInfo.offset;
+ tintInfo.shader_location = static_cast<uint32_t>(static_cast<uint8_t>(location));
+
+ uint8_t vertexBufferSlot = static_cast<uint8_t>(dawnInfo.vertexBufferSlot);
+ cfg.vertex_state[vertexBufferSlot].attributes.push_back(tintInfo);
+ }
+ return cfg;
+}
+
} // namespace dawn::native
+
+namespace tint::sem {
+
+bool operator<(const BindingPoint& a, const BindingPoint& b) {
+ return std::tie(a.group, a.binding) < std::tie(b.group, b.binding);
+}
+
+} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/dawn/native/TintUtils.h b/chromium/third_party/dawn/src/dawn/native/TintUtils.h
index 4a2df60d75f..7c038815022 100644
--- a/chromium/third_party/dawn/src/dawn/native/TintUtils.h
+++ b/chromium/third_party/dawn/src/dawn/native/TintUtils.h
@@ -15,11 +15,18 @@
#ifndef SRC_DAWN_NATIVE_TINTUTILS_H_
#define SRC_DAWN_NATIVE_TINTUTILS_H_
+#include <functional>
+
#include "dawn/common/NonCopyable.h"
+#include "dawn/native/IntegerTypes.h"
+
+#include "tint/tint.h"
namespace dawn::native {
class DeviceBase;
+class PipelineLayoutBase;
+class RenderPipelineBase;
// Indicates that for the lifetime of this object tint internal compiler errors should be
// reported to the given device.
@@ -32,6 +39,21 @@ class ScopedTintICEHandler : public NonCopyable {
ScopedTintICEHandler(ScopedTintICEHandler&&) = delete;
};
+tint::transform::MultiplanarExternalTexture::BindingsMap BuildExternalTextureTransformBindings(
+ const PipelineLayoutBase* layout);
+
+tint::transform::VertexPulling::Config BuildVertexPullingTransformConfig(
+ const RenderPipelineBase& renderPipeline,
+ const std::string_view& entryPoint,
+ BindGroupIndex pullingBufferBindingSet);
+
} // namespace dawn::native
+namespace tint::sem {
+
+// Defin operator< for std::map containing BindingPoint
+bool operator<(const BindingPoint& a, const BindingPoint& b);
+
+} // namespace tint::sem
+
#endif // SRC_DAWN_NATIVE_TINTUTILS_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/Toggles.cpp b/chromium/third_party/dawn/src/dawn/native/Toggles.cpp
index f98c94dbdfb..8fbf0e3e818 100644
--- a/chromium/third_party/dawn/src/dawn/native/Toggles.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/Toggles.cpp
@@ -182,9 +182,8 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
"Split texture-to-texture copy into two copies: copy from source texture into a temporary "
"buffer, and copy from the temporary buffer into the destination texture under specific "
"situations. This workaround is by default enabled on some Intel GPUs which have a driver "
- "bug "
- "in the execution of CopyTextureRegion() when we copy with the formats whose texel block "
- "sizes are less than 4 bytes from a greater mip level to a smaller mip level on D3D12 "
+ "bug in the execution of CopyTextureRegion() when we copy with the formats whose texel "
+ "block sizes are less than 4 bytes from a greater mip level to a smaller mip level on D3D12 "
"backends.",
"https://crbug.com/1161355"}},
{Toggle::EmitHLSLDebugSymbols,
@@ -203,8 +202,6 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
"Dump shaders for debugging purposes. Dumped shaders will be log via EmitLog, thus printed "
"in Chrome console or consumed by user-defined callback function.",
"https://crbug.com/dawn/792"}},
- {Toggle::DEPRECATED_DumpTranslatedShaders,
- {"dump_translated_shaders", "Deprecated. Use dump_shaders", "https://crbug.com/dawn/792"}},
{Toggle::ForceWGSLStep,
{"force_wgsl_step",
"When ingesting SPIR-V shaders, force a first conversion to WGSL. This allows testing Tint's "
@@ -268,24 +265,57 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
"Enables usage of the blob cache (backed by the platform cache if set/passed). Necessary for "
"any persistent caching capabilities, i.e. pipeline caching.",
"https://crbug.com/dawn/549"}},
+ {Toggle::D3D12ForceClearCopyableDepthStencilTextureOnCreation,
+ {"d3d12_force_clear_copyable_depth_stencil_texture_on_creation",
+ "Always clearing copyable depth stencil textures when creating them instead of skipping the "
+ "initialization when the entire subresource is the copy destination as a workaround on Intel "
+ "D3D12 drivers.",
+ "https://crbug.com/dawn/1487"}},
+ {Toggle::D3D12DontSetClearValueOnDepthTextureCreation,
+ {"d3d12_dont_set_clear_value_on_depth_texture_creation",
+ "Don't set D3D12_CLEAR_VALUE when creating depth textures with CreatePlacedResource() or "
+ "CreateCommittedResource() as a workaround on Intel Gen12 D3D12 drivers.",
+ "https://crbug.com/dawn/1487"}},
+ {Toggle::D3D12AlwaysUseTypelessFormatsForCastableTexture,
+ {"d3d12_always_use_typeless_formats_for_castable_texture",
+ "Always use the typeless DXGI format when we create a texture with valid viewFormat. This "
+ "Toggle is enabled by default on the D3D12 platforms where CastingFullyTypedFormatSupported "
+ "is false.",
+ "https://crbug.com/dawn/1276"}},
+ {Toggle::D3D12AllocateExtraMemoryFor2DArrayTexture,
+ {"d3d12_allocate_extra_memory_for_2d_array_texture",
+ "Memory allocation for 2D array texture may be smaller than it should be on D3D12 on some "
+ "Intel devices. So texture access can be out-of-bound, which may cause critical security "
+ "issue. We can workaround this security issue via allocating extra memory and limiting its "
+ "access in itself.",
+ "https://crbug.com/dawn/949"}},
+ {Toggle::D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset,
+ {"d3d12_use_temp_buffer_in_depth_stencil_texture_and_buffer_copy_with_non_zero_buffer_offset",
+ "Split buffer-texture copy into two copies: do first copy with a temporary buffer at offset "
+ "0, then copy from the temporary buffer to the destination. Now this toggle must be enabled "
+ "on the D3D12 platforms where programmable MSAA is not supported.",
+ "https://crbug.com/dawn/727"}},
+ {Toggle::ApplyClearBigIntegerColorValueWithDraw,
+ {"apply_clear_big_integer_color_value_with_draw",
+ "Apply the clear value of the color attachment with a draw call when load op is 'clear'. "
+ "This toggle is enabled by default on D3D12 backends when we set large integer values "
+ "(> 2^24 or < -2^24 for signed integer formats) as the clear value of a color attachment "
+ "with 32-bit integer or unsigned integer formats because D3D12 APIs only support using "
+ "float numbers as clear values, while a float number cannot always precisely represent an "
+ "integer that is greater than 2^24 or smaller than -2^24). This toggle is also enabled on "
+ "Intel GPUs on Metal backend due to a driver issue on Intel Metal driver.",
+ "https://crbug.com/dawn/537"}},
// Comment to separate the }} so it is clearer what to copy-paste to add a toggle.
}};
} // anonymous namespace
void TogglesSet::Set(Toggle toggle, bool enabled) {
- if (toggle == Toggle::DEPRECATED_DumpTranslatedShaders) {
- Set(Toggle::DumpShaders, enabled);
- return;
- }
ASSERT(toggle != Toggle::InvalidEnum);
const size_t toggleIndex = static_cast<size_t>(toggle);
toggleBitset.set(toggleIndex, enabled);
}
bool TogglesSet::Has(Toggle toggle) const {
- if (toggle == Toggle::DEPRECATED_DumpTranslatedShaders) {
- return Has(Toggle::DumpShaders);
- }
ASSERT(toggle != Toggle::InvalidEnum);
const size_t toggleIndex = static_cast<size_t>(toggle);
return toggleBitset.test(toggleIndex);
diff --git a/chromium/third_party/dawn/src/dawn/native/Toggles.h b/chromium/third_party/dawn/src/dawn/native/Toggles.h
index 341db798fe6..5e000f9f6ec 100644
--- a/chromium/third_party/dawn/src/dawn/native/Toggles.h
+++ b/chromium/third_party/dawn/src/dawn/native/Toggles.h
@@ -59,7 +59,6 @@ enum class Toggle {
EmitHLSLDebugSymbols,
DisallowSpirv,
DumpShaders,
- DEPRECATED_DumpTranslatedShaders, // Use DumpShaders
ForceWGSLStep,
DisableWorkgroupInit,
DisableSymbolRenaming,
@@ -72,6 +71,12 @@ enum class Toggle {
D3D12SplitBufferTextureCopyForRowsPerImagePaddings,
MetalRenderR8RG8UnormSmallMipToTempTexture,
EnableBlobCache,
+ D3D12ForceClearCopyableDepthStencilTextureOnCreation,
+ D3D12DontSetClearValueOnDepthTextureCreation,
+ D3D12AlwaysUseTypelessFormatsForCastableTexture,
+ D3D12AllocateExtraMemoryFor2DArrayTexture,
+ D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset,
+ ApplyClearBigIntegerColorValueWithDraw,
EnumCount,
InvalidEnum = EnumCount,
diff --git a/chromium/third_party/dawn/src/include/dawn/dawn_proc.h b/chromium/third_party/dawn/src/dawn/native/UsageValidationMode.h
index 2bea48b5eac..2228bb46e39 100644
--- a/chromium/third_party/dawn/src/include/dawn/dawn_proc.h
+++ b/chromium/third_party/dawn/src/dawn/native/UsageValidationMode.h
@@ -12,9 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_INCLUDE_DAWN_DAWN_PROC_H_
-#define SRC_INCLUDE_DAWN_DAWN_PROC_H_
+#ifndef SRC_DAWN_NATIVE_USAGEVALIDATIONMODE_H_
+#define SRC_DAWN_NATIVE_USAGEVALIDATIONMODE_H_
-#include "dawn/dawn_proc.h"
+namespace dawn::native {
-#endif // SRC_INCLUDE_DAWN_DAWN_PROC_H_
+enum class UsageValidationMode {
+ Default,
+ Internal,
+};
+
+} // namespace dawn::native
+
+#endif // SRC_DAWN_NATIVE_USAGEVALIDATIONMODE_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/VisitableMembers.h b/chromium/third_party/dawn/src/dawn/native/VisitableMembers.h
new file mode 100644
index 00000000000..82fb58d535f
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/VisitableMembers.h
@@ -0,0 +1,65 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_VISITABLE_H_
+#define SRC_DAWN_NATIVE_VISITABLE_H_
+
+#include <utility>
+
+#include "dawn/native/stream/BlobSource.h"
+#include "dawn/native/stream/ByteVectorSink.h"
+#include "dawn/native/stream/Stream.h"
+
+// Helper for X macro to declare a visitable member.
+#define DAWN_INTERNAL_VISITABLE_MEMBER_DECL(type, name) type name{};
+
+// Helper for X macro for visiting a visitable member.
+#define DAWN_INTERNAL_VISITABLE_MEMBER_ARG(type, name) , name
+
+namespace dawn::native::detail {
+constexpr int kInternalVisitableUnusedForComma = 0;
+} // namespace dawn::native::detail
+
+// Helper X macro to declare members of a class or struct, along with VisitAll
+// methods to call a functor on all members.
+// Example usage:
+// #define MEMBERS(X) \
+// X(int, a) \
+// X(float, b) \
+// X(Foo, foo) \
+// X(Bar, bar)
+// struct MyStruct {
+// DAWN_VISITABLE_MEMBERS(MEMBERS)
+// };
+// #undef MEMBERS
+#define DAWN_VISITABLE_MEMBERS(MEMBERS) \
+ MEMBERS(DAWN_INTERNAL_VISITABLE_MEMBER_DECL) \
+ \
+ template <typename V> \
+ constexpr auto VisitAll(V&& visit) const { \
+ return [&](int, const auto&... ms) { \
+ return visit(ms...); \
+ }(::dawn::native::detail::kInternalVisitableUnusedForComma MEMBERS( \
+ DAWN_INTERNAL_VISITABLE_MEMBER_ARG)); \
+ } \
+ \
+ template <typename V> \
+ constexpr auto VisitAll(V&& visit) { \
+ return [&](int, auto&... ms) { \
+ return visit(ms...); \
+ }(::dawn::native::detail::kInternalVisitableUnusedForComma MEMBERS( \
+ DAWN_INTERNAL_VISITABLE_MEMBER_ARG)); \
+ }
+
+#endif // SRC_DAWN_NATIVE_VISITABLE_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/AdapterD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/AdapterD3D12.cpp
index f9a8a93caa3..e23830e8993 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/AdapterD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/AdapterD3D12.cpp
@@ -67,7 +67,7 @@ MaybeError Adapter::InitializeImpl() {
// rendering.
const PlatformFunctions* functions = GetBackend()->GetFunctions();
if (FAILED(functions->d3d12CreateDevice(GetHardwareAdapter(), D3D_FEATURE_LEVEL_11_0,
- _uuidof(ID3D12Device), &mD3d12Device))) {
+ __uuidof(ID3D12Device), &mD3d12Device))) {
return DAWN_INTERNAL_ERROR("D3D12CreateDevice failed");
}
@@ -135,7 +135,6 @@ MaybeError Adapter::InitializeSupportedFeaturesImpl() {
mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery);
mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats);
- mSupportedFeatures.EnableFeature(Feature::Depth24UnormStencil8);
mSupportedFeatures.EnableFeature(Feature::Depth32FloatStencil8);
mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance);
@@ -241,6 +240,8 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
limits->v1.maxSampledTexturesPerShaderStage = maxSRVsPerStage;
limits->v1.maxSamplersPerShaderStage = maxSamplersPerStage;
+ limits->v1.maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT;
+
// https://docs.microsoft.com/en-us/windows/win32/direct3d12/root-signature-limits
// In DWORDS. Descriptor tables cost 1, Root constants cost 1, Root descriptors cost 2.
static constexpr uint32_t kMaxRootSignatureSize = 64u;
@@ -300,11 +301,14 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
// D3D12 has no documented limit on the size of a storage buffer binding.
limits->v1.maxStorageBufferBindingSize = 4294967295;
+ // Using base limits for:
// TODO(crbug.com/dawn/685):
- // LIMITS NOT SET:
// - maxInterStageShaderComponents
// - maxVertexBufferArrayStride
+ // TODO(crbug.com/dawn/1448):
+ // - maxInterStageShaderVariables
+
return {};
}
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.cpp
index ef9bbb99054..3b5965758d4 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.cpp
@@ -28,4 +28,16 @@ Blob CreateBlob(ComPtr<ID3DBlob> blob) {
});
}
+Blob CreateBlob(ComPtr<IDxcBlob> blob) {
+ // Detach so the deleter callback can "own" the reference
+ IDxcBlob* ptr = blob.Detach();
+ return Blob::UnsafeCreateWithDeleter(reinterpret_cast<uint8_t*>(ptr->GetBufferPointer()),
+ ptr->GetBufferSize(), [=]() {
+ // Reattach and drop to delete it.
+ ComPtr<IDxcBlob> b;
+ b.Attach(ptr);
+ b = nullptr;
+ });
+}
+
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.h b/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.h
index 563ac7341c0..cc8c99c902e 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/BlobD3D12.h
@@ -18,5 +18,6 @@
namespace dawn::native {
Blob CreateBlob(ComPtr<ID3DBlob> blob);
+Blob CreateBlob(ComPtr<IDxcBlob> blob);
} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/CacheKeyD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/CacheKeyD3D12.cpp
deleted file mode 100644
index 0daf5264dd7..00000000000
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/CacheKeyD3D12.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn/common/Assert.h"
-#include "dawn/common/Constants.h"
-#include "dawn/native/CacheKey.h"
-#include "dawn/native/d3d12/d3d12_platform.h"
-
-namespace dawn::native {
-
-template <>
-void CacheKeySerializer<D3D12_COMPUTE_PIPELINE_STATE_DESC>::Serialize(
- CacheKey* key,
- const D3D12_COMPUTE_PIPELINE_STATE_DESC& t) {
- // Don't record pRootSignature as we already record the signature blob in pipline layout.
- key->Record(t.CS).Record(t.NodeMask).Record(t.Flags);
-}
-
-template <>
-void CacheKeySerializer<D3D12_RENDER_TARGET_BLEND_DESC>::Serialize(
- CacheKey* key,
- const D3D12_RENDER_TARGET_BLEND_DESC& t) {
- key->Record(t.BlendEnable, t.LogicOpEnable, t.SrcBlend, t.DestBlend, t.BlendOp, t.SrcBlendAlpha,
- t.DestBlendAlpha, t.BlendOpAlpha, t.LogicOp, t.RenderTargetWriteMask);
-}
-
-template <>
-void CacheKeySerializer<D3D12_BLEND_DESC>::Serialize(CacheKey* key, const D3D12_BLEND_DESC& t) {
- key->Record(t.AlphaToCoverageEnable, t.IndependentBlendEnable).Record(t.RenderTarget);
-}
-
-template <>
-void CacheKeySerializer<D3D12_DEPTH_STENCILOP_DESC>::Serialize(
- CacheKey* key,
- const D3D12_DEPTH_STENCILOP_DESC& t) {
- key->Record(t.StencilFailOp, t.StencilDepthFailOp, t.StencilPassOp, t.StencilFunc);
-}
-
-template <>
-void CacheKeySerializer<D3D12_DEPTH_STENCIL_DESC>::Serialize(CacheKey* key,
- const D3D12_DEPTH_STENCIL_DESC& t) {
- key->Record(t.DepthEnable, t.DepthWriteMask, t.DepthFunc, t.StencilEnable, t.StencilReadMask,
- t.StencilWriteMask, t.FrontFace, t.BackFace);
-}
-
-template <>
-void CacheKeySerializer<D3D12_RASTERIZER_DESC>::Serialize(CacheKey* key,
- const D3D12_RASTERIZER_DESC& t) {
- key->Record(t.FillMode, t.CullMode, t.FrontCounterClockwise, t.DepthBias, t.DepthBiasClamp,
- t.SlopeScaledDepthBias, t.DepthClipEnable, t.MultisampleEnable,
- t.AntialiasedLineEnable, t.ForcedSampleCount, t.ConservativeRaster);
-}
-
-template <>
-void CacheKeySerializer<D3D12_INPUT_ELEMENT_DESC>::Serialize(CacheKey* key,
- const D3D12_INPUT_ELEMENT_DESC& t) {
- key->Record(t.SemanticName, t.SemanticIndex, t.Format, t.InputSlot, t.AlignedByteOffset,
- t.InputSlotClass, t.InstanceDataStepRate);
-}
-
-template <>
-void CacheKeySerializer<D3D12_INPUT_LAYOUT_DESC>::Serialize(CacheKey* key,
- const D3D12_INPUT_LAYOUT_DESC& t) {
- key->RecordIterable(t.pInputElementDescs, t.NumElements);
-}
-
-template <>
-void CacheKeySerializer<D3D12_SO_DECLARATION_ENTRY>::Serialize(
- CacheKey* key,
- const D3D12_SO_DECLARATION_ENTRY& t) {
- key->Record(t.Stream, t.SemanticName, t.SemanticIndex, t.StartComponent, t.ComponentCount,
- t.OutputSlot);
-}
-
-template <>
-void CacheKeySerializer<D3D12_STREAM_OUTPUT_DESC>::Serialize(CacheKey* key,
- const D3D12_STREAM_OUTPUT_DESC& t) {
- key->RecordIterable(t.pSODeclaration, t.NumEntries)
- .RecordIterable(t.pBufferStrides, t.NumStrides)
- .Record(t.RasterizedStream);
-}
-
-template <>
-void CacheKeySerializer<DXGI_SAMPLE_DESC>::Serialize(CacheKey* key, const DXGI_SAMPLE_DESC& t) {
- key->Record(t.Count, t.Quality);
-}
-
-template <>
-void CacheKeySerializer<D3D12_SHADER_BYTECODE>::Serialize(CacheKey* key,
- const D3D12_SHADER_BYTECODE& t) {
- key->RecordIterable(reinterpret_cast<const uint8_t*>(t.pShaderBytecode), t.BytecodeLength);
-}
-
-template <>
-void CacheKeySerializer<D3D12_GRAPHICS_PIPELINE_STATE_DESC>::Serialize(
- CacheKey* key,
- const D3D12_GRAPHICS_PIPELINE_STATE_DESC& t) {
- // Don't record pRootSignature as we already record the signature blob in pipline layout.
- // Don't record CachedPSO as it is in the cached blob.
- key->Record(t.VS)
- .Record(t.PS)
- .Record(t.DS)
- .Record(t.HS)
- .Record(t.GS)
- .Record(t.StreamOutput)
- .Record(t.BlendState)
- .Record(t.SampleMask)
- .Record(t.RasterizerState)
- .Record(t.DepthStencilState)
- .Record(t.InputLayout)
- .Record(t.IBStripCutValue)
- .Record(t.PrimitiveTopologyType)
- .RecordIterable(t.RTVFormats, t.NumRenderTargets)
- .Record(t.DSVFormat)
- .Record(t.SampleDesc)
- .Record(t.NodeMask)
- .Record(t.Flags);
-}
-
-template <>
-void CacheKeySerializer<ID3DBlob>::Serialize(CacheKey* key, const ID3DBlob& t) {
- // Workaround: GetBufferPointer and GetbufferSize are not marked as const
- ID3DBlob* pBlob = const_cast<ID3DBlob*>(&t);
- key->RecordIterable(reinterpret_cast<uint8_t*>(pBlob->GetBufferPointer()),
- pBlob->GetBufferSize());
-}
-
-} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.cpp
index 77c7ba3ca78..08aad3418e2 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.cpp
@@ -90,10 +90,12 @@ bool CanUseCopyResource(const TextureCopy& src, const TextureCopy& dst, const Ex
copySize.depthOrArrayLayers == srcSize.depthOrArrayLayers;
}
-void RecordWriteTimestampCmd(ID3D12GraphicsCommandList* commandList, WriteTimestampCmd* cmd) {
- QuerySet* querySet = ToBackend(cmd->querySet.Get());
- ASSERT(D3D12QueryType(querySet->GetQueryType()) == D3D12_QUERY_TYPE_TIMESTAMP);
- commandList->EndQuery(querySet->GetQueryHeap(), D3D12_QUERY_TYPE_TIMESTAMP, cmd->queryIndex);
+void RecordWriteTimestampCmd(ID3D12GraphicsCommandList* commandList,
+ QuerySetBase* querySet,
+ uint32_t queryIndex) {
+ ASSERT(D3D12QueryType(ToBackend(querySet)->GetQueryType()) == D3D12_QUERY_TYPE_TIMESTAMP);
+ commandList->EndQuery(ToBackend(querySet)->GetQueryHeap(), D3D12_QUERY_TYPE_TIMESTAMP,
+ queryIndex);
}
void RecordResolveQuerySetCmd(ID3D12GraphicsCommandList* commandList,
@@ -223,6 +225,87 @@ MaybeError RecordCopyTextureWithTemporaryBuffer(CommandRecordingContext* recordi
return {};
}
+bool ShouldCopyUsingTemporaryBuffer(DeviceBase* device,
+ const BufferCopy& bufferCopy,
+ const TextureCopy& textureCopy) {
+ // Currently we only need the workaround for some D3D12 platforms.
+ if (device->IsToggleEnabled(
+ Toggle::D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset)) {
+ if ((ToBackend(textureCopy.texture)->GetD3D12ResourceFlags() &
+ D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) &&
+ bufferCopy.offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT > 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+MaybeError RecordBufferTextureCopyWithTemporaryBuffer(CommandRecordingContext* recordingContext,
+ BufferTextureCopyDirection copyDirection,
+ const BufferCopy& bufferCopy,
+ const TextureCopy& textureCopy,
+ const Extent3D& copySize) {
+ dawn::native::Format format = textureCopy.texture->GetFormat();
+ const TexelBlockInfo& blockInfo = format.GetAspectInfo(textureCopy.aspect).block;
+
+ // Create tempBuffer
+ // The size of temporary buffer isn't needed to be a multiple of 4 because we don't
+ // need to set mappedAtCreation to be true.
+ auto tempBufferSize = ComputeRequiredBytesInCopy(blockInfo, copySize, bufferCopy.bytesPerRow,
+ bufferCopy.rowsPerImage);
+
+ BufferDescriptor tempBufferDescriptor;
+ tempBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
+ tempBufferDescriptor.size = tempBufferSize.AcquireSuccess();
+ Device* device = ToBackend(textureCopy.texture->GetDevice());
+ Ref<BufferBase> tempBufferBase;
+ DAWN_TRY_ASSIGN(tempBufferBase, device->CreateBuffer(&tempBufferDescriptor));
+ // D3D12 aligns the entire buffer to at least 64KB, so the virtual address of tempBuffer will
+ // always be aligned to D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512).
+ Ref<Buffer> tempBuffer = ToBackend(std::move(tempBufferBase));
+ ASSERT(tempBuffer->GetVA() % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT == 0);
+
+ BufferCopy tempBufferCopy;
+ tempBufferCopy.buffer = tempBuffer;
+ tempBufferCopy.offset = 0;
+ tempBufferCopy.bytesPerRow = bufferCopy.bytesPerRow;
+ tempBufferCopy.rowsPerImage = bufferCopy.rowsPerImage;
+
+ tempBuffer->TrackUsageAndTransitionNow(recordingContext, wgpu::BufferUsage::CopyDst);
+
+ ID3D12GraphicsCommandList* commandList = recordingContext->GetCommandList();
+ switch (copyDirection) {
+ case BufferTextureCopyDirection::B2T: {
+ commandList->CopyBufferRegion(tempBuffer->GetD3D12Resource(), 0,
+ ToBackend(bufferCopy.buffer)->GetD3D12Resource(),
+ bufferCopy.offset, tempBufferDescriptor.size);
+ tempBuffer->TrackUsageAndTransitionNow(recordingContext, wgpu::BufferUsage::CopySrc);
+ RecordBufferTextureCopy(BufferTextureCopyDirection::B2T,
+ recordingContext->GetCommandList(), tempBufferCopy, textureCopy,
+ copySize);
+ break;
+ }
+ case BufferTextureCopyDirection::T2B: {
+ RecordBufferTextureCopy(BufferTextureCopyDirection::T2B,
+ recordingContext->GetCommandList(), tempBufferCopy, textureCopy,
+ copySize);
+ tempBuffer->TrackUsageAndTransitionNow(recordingContext, wgpu::BufferUsage::CopySrc);
+ commandList->CopyBufferRegion(ToBackend(bufferCopy.buffer)->GetD3D12Resource(),
+ bufferCopy.offset, tempBuffer->GetD3D12Resource(), 0,
+ tempBufferDescriptor.size);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ // Save tempBuffer into recordingContext
+ recordingContext->AddToTempBuffers(std::move(tempBuffer));
+
+ return {};
+}
+
void RecordNumWorkgroupsForDispatch(ID3D12GraphicsCommandList* commandList,
ComputePipeline* pipeline,
DispatchCmd* dispatch) {
@@ -653,11 +736,12 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
- mCommands.NextCommand<BeginComputePassCmd>();
+ BeginComputePassCmd* cmd = mCommands.NextCommand<BeginComputePassCmd>();
bindingTracker.SetInComputePass(true);
+
DAWN_TRY(
- RecordComputePass(commandContext, &bindingTracker,
+ RecordComputePass(commandContext, &bindingTracker, cmd,
GetResourceUsages().computePasses[nextComputePassNumber]));
nextComputePassNumber++;
@@ -730,6 +814,12 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopyDst,
subresources);
+ if (ShouldCopyUsingTemporaryBuffer(GetDevice(), copy->source, copy->destination)) {
+ DAWN_TRY(RecordBufferTextureCopyWithTemporaryBuffer(
+ commandContext, BufferTextureCopyDirection::B2T, copy->source,
+ copy->destination, copy->copySize));
+ break;
+ }
RecordBufferTextureCopy(BufferTextureCopyDirection::B2T, commandList, copy->source,
copy->destination, copy->copySize);
@@ -757,6 +847,12 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
subresources);
buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopyDst);
+ if (ShouldCopyUsingTemporaryBuffer(GetDevice(), copy->destination, copy->source)) {
+ DAWN_TRY(RecordBufferTextureCopyWithTemporaryBuffer(
+ commandContext, BufferTextureCopyDirection::T2B, copy->destination,
+ copy->source, copy->copySize));
+ break;
+ }
RecordBufferTextureCopy(BufferTextureCopyDirection::T2B, commandList,
copy->destination, copy->source, copy->copySize);
@@ -942,7 +1038,7 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
case Command::WriteTimestamp: {
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
- RecordWriteTimestampCmd(commandList, cmd);
+ RecordWriteTimestampCmd(commandList, cmd->querySet.Get(), cmd->queryIndex);
break;
}
@@ -1023,10 +1119,17 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandContext,
BindGroupStateTracker* bindingTracker,
+ BeginComputePassCmd* computePass,
const ComputePassResourceUsage& resourceUsages) {
uint64_t currentDispatch = 0;
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
+ // Write timestamp at the beginning of compute pass if it's set.
+ if (computePass->beginTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(commandList, computePass->beginTimestamp.querySet.Get(),
+ computePass->beginTimestamp.queryIndex);
+ }
+
Command type;
ComputePipeline* lastPipeline = nullptr;
while (mCommands.NextCommandId(&type)) {
@@ -1068,6 +1171,12 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandCont
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
+
+ // Write timestamp at the end of compute pass if it's set.
+ if (computePass->endTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(commandList, computePass->endTimestamp.querySet.Get(),
+ computePass->endTimestamp.queryIndex);
+ }
return {};
}
@@ -1136,7 +1245,7 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandCont
case Command::WriteTimestamp: {
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
- RecordWriteTimestampCmd(commandList, cmd);
+ RecordWriteTimestampCmd(commandList, cmd->querySet.Get(), cmd->queryIndex);
break;
}
@@ -1339,6 +1448,12 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandConte
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
+ // Write timestamp at the beginning of render pass if it's set.
+ if (renderPass->beginTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(commandList, renderPass->beginTimestamp.querySet.Get(),
+ renderPass->beginTimestamp.queryIndex);
+ }
+
// Set up default dynamic state
{
uint32_t width = renderPass->width;
@@ -1511,6 +1626,13 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandConte
switch (type) {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
+
+ // Write timestamp at the end of render pass if it's set.
+ if (renderPass->endTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(commandList, renderPass->endTimestamp.querySet.Get(),
+ renderPass->endTimestamp.queryIndex);
+ }
+
if (useRenderPass) {
commandContext->GetCommandList4()->EndRenderPass();
} else if (renderPass->attachmentState->GetSampleCount() > 1) {
@@ -1596,7 +1718,7 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandConte
case Command::WriteTimestamp: {
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
- RecordWriteTimestampCmd(commandList, cmd);
+ RecordWriteTimestampCmd(commandList, cmd->querySet.Get(), cmd->queryIndex);
break;
}
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.h b/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.h
index ea0bb704ac5..10523950a86 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/CommandBufferD3D12.h
@@ -19,6 +19,7 @@
#include "dawn/native/Error.h"
namespace dawn::native {
+struct BeginComputePassCmd;
struct BeginRenderPassCmd;
} // namespace dawn::native
@@ -40,6 +41,7 @@ class CommandBuffer final : public CommandBufferBase {
MaybeError RecordComputePass(CommandRecordingContext* commandContext,
BindGroupStateTracker* bindingTracker,
+ BeginComputePassCmd* computePass,
const ComputePassResourceUsage& resourceUsages);
MaybeError RecordRenderPass(CommandRecordingContext* commandContext,
BindGroupStateTracker* bindingTracker,
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/CommandRecordingContext.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/CommandRecordingContext.cpp
index d4fa04d525f..1f7e2766f57 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/CommandRecordingContext.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/CommandRecordingContext.cpp
@@ -71,7 +71,7 @@ MaybeError CommandRecordingContext::ExecuteCommandList(Device* device) {
// common state right before command list submission. TransitionUsageNow itself ensures
// no unnecessary transitions happen if the resources is already in the common state.
for (Texture* texture : mSharedTextures) {
- DAWN_TRY(texture->AcquireKeyedMutex());
+ DAWN_TRY(texture->SynchronizeImportedTextureBeforeUse());
texture->TrackAllUsageAndTransitionNow(this, D3D12_RESOURCE_STATE_COMMON);
}
@@ -124,12 +124,13 @@ MaybeError CommandRecordingContext::ExecuteCommandList(Device* device) {
device->GetCommandQueue()->ExecuteCommandLists(1, &d3d12CommandList);
for (Texture* texture : mSharedTextures) {
- texture->ReleaseKeyedMutex();
+ texture->SynchronizeImportedTextureAfterUse();
}
mIsOpen = false;
mSharedTextures.clear();
mHeapsPendingUsage.clear();
+ mTempBuffers.clear();
}
return {};
}
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/ComputePipelineD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/ComputePipelineD3D12.cpp
index 5ba8b7604dd..8dc05fce3b6 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/ComputePipelineD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/ComputePipelineD3D12.cpp
@@ -62,7 +62,7 @@ MaybeError ComputePipeline::Initialize() {
ToBackend(GetLayout()), compileFlags));
d3dDesc.CS = compiledShader.GetD3D12ShaderBytecode();
- mCacheKey.Record(d3dDesc, ToBackend(GetLayout())->GetRootSignatureBlob());
+ StreamIn(&mCacheKey, d3dDesc, ToBackend(GetLayout())->GetRootSignatureBlob());
// Try to see if we have anything in the blob cache.
Blob blob = device->LoadCachedBlob(GetCacheKey());
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Backend.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Backend.cpp
index 0e5a76f3617..05ddd6b4c08 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Backend.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Backend.cpp
@@ -67,12 +67,12 @@ bool ExternalImageDXGI::IsValid() const {
WGPUTexture ExternalImageDXGI::ProduceTexture(
WGPUDevice device,
- const ExternalImageAccessDescriptorDXGIKeyedMutex* descriptor) {
+ const ExternalImageAccessDescriptorDXGISharedHandle* descriptor) {
return ProduceTexture(descriptor);
}
WGPUTexture ExternalImageDXGI::ProduceTexture(
- const ExternalImageAccessDescriptorDXGIKeyedMutex* descriptor) {
+ const ExternalImageAccessDescriptorDXGISharedHandle* descriptor) {
if (!IsValid()) {
dawn::ErrorLog() << "Cannot produce texture from external image after device destruction";
return nullptr;
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.cpp
index 6a4c4356488..3d3470c1732 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.cpp
@@ -38,27 +38,22 @@ ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter) {
info.isUMA = arch.UMA;
- D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
- DAWN_TRY(CheckHRESULT(adapter.GetDevice()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS,
- &options, sizeof(options)),
+ D3D12_FEATURE_DATA_D3D12_OPTIONS featureOptions = {};
+ DAWN_TRY(CheckHRESULT(adapter.GetDevice()->CheckFeatureSupport(
+ D3D12_FEATURE_D3D12_OPTIONS, &featureOptions, sizeof(featureOptions)),
"ID3D12Device::CheckFeatureSupport"));
+ info.resourceHeapTier = featureOptions.ResourceHeapTier;
- info.resourceHeapTier = options.ResourceHeapTier;
+ D3D12_FEATURE_DATA_D3D12_OPTIONS2 featureOptions2 = {};
+ if (SUCCEEDED(adapter.GetDevice()->CheckFeatureSupport(
+ D3D12_FEATURE_D3D12_OPTIONS2, &featureOptions2, sizeof(featureOptions2)))) {
+ info.programmableSamplePositionsTier = featureOptions2.ProgrammableSamplePositionsTier;
+ }
- // Windows builds 1809 and above can use the D3D12 render pass API. If we query
- // CheckFeatureSupport for D3D12_FEATURE_D3D12_OPTIONS5 successfully, then we can use
- // the render pass API.
- info.supportsRenderPass = false;
- D3D12_FEATURE_DATA_D3D12_OPTIONS5 featureOptions5 = {};
+ D3D12_FEATURE_DATA_D3D12_OPTIONS3 featureOptions3 = {};
if (SUCCEEDED(adapter.GetDevice()->CheckFeatureSupport(
- D3D12_FEATURE_D3D12_OPTIONS5, &featureOptions5, sizeof(featureOptions5)))) {
- // Performance regressions been observed when using a render pass on Intel graphics
- // with RENDER_PASS_TIER_1 available, so fall back to a software emulated render
- // pass on these platforms.
- if (featureOptions5.RenderPassesTier < D3D12_RENDER_PASS_TIER_1 ||
- !gpu_info::IsIntel(adapter.GetVendorId())) {
- info.supportsRenderPass = true;
- }
+ D3D12_FEATURE_D3D12_OPTIONS3, &featureOptions3, sizeof(featureOptions3)))) {
+ info.supportsCastingFullyTypedFormat = featureOptions3.CastingFullyTypedFormatSupported;
}
// Used to share resources cross-API. If we query CheckFeatureSupport for
@@ -75,6 +70,22 @@ ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter) {
}
}
+ // Windows builds 1809 and above can use the D3D12 render pass API. If we query
+ // CheckFeatureSupport for D3D12_FEATURE_D3D12_OPTIONS5 successfully, then we can use
+ // the render pass API.
+ info.supportsRenderPass = false;
+ D3D12_FEATURE_DATA_D3D12_OPTIONS5 featureOptions5 = {};
+ if (SUCCEEDED(adapter.GetDevice()->CheckFeatureSupport(
+ D3D12_FEATURE_D3D12_OPTIONS5, &featureOptions5, sizeof(featureOptions5)))) {
+ // Performance regressions been observed when using a render pass on Intel graphics
+ // with RENDER_PASS_TIER_1 available, so fall back to a software emulated render
+ // pass on these platforms.
+ if (featureOptions5.RenderPassesTier < D3D12_RENDER_PASS_TIER_1 ||
+ !gpu_info::IsIntel(adapter.GetVendorId())) {
+ info.supportsRenderPass = true;
+ }
+ }
+
D3D12_FEATURE_DATA_SHADER_MODEL knownShaderModels[] = {
{D3D_SHADER_MODEL_6_4}, {D3D_SHADER_MODEL_6_3}, {D3D_SHADER_MODEL_6_2},
{D3D_SHADER_MODEL_6_1}, {D3D_SHADER_MODEL_6_0}, {D3D_SHADER_MODEL_5_1}};
@@ -110,12 +121,8 @@ ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter) {
info.shaderProfiles[SingleShaderStage::Fragment] = L"p" + profileSuffix;
info.shaderProfiles[SingleShaderStage::Compute] = L"c" + profileSuffix;
- D3D12_FEATURE_DATA_D3D12_OPTIONS4 featureData4 = {};
- if (SUCCEEDED(adapter.GetDevice()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4,
- &featureData4, sizeof(featureData4)))) {
- info.supportsShaderFloat16 =
- driverShaderModel >= D3D_SHADER_MODEL_6_2 && featureData4.Native16BitShaderOpsSupported;
- }
+ info.supportsShaderFloat16 =
+ driverShaderModel >= D3D_SHADER_MODEL_6_2 && featureOptions4.Native16BitShaderOpsSupported;
info.supportsDP4a = driverShaderModel >= D3D_SHADER_MODEL_6_4;
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.h b/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.h
index e0f2a669ecc..f81e28de111 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/D3D12Info.h
@@ -34,6 +34,8 @@ struct D3D12DeviceInfo {
PerStage<std::wstring> shaderProfiles;
bool supportsSharedResourceCapabilityTier1;
bool supportsDP4a;
+ bool supportsCastingFullyTypedFormat;
+ uint32_t programmableSamplePositionsTier;
};
ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter);
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.cpp
index 1cb342bd361..214fa67f845 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.cpp
@@ -536,12 +536,32 @@ ResultOrError<ResourceHeapAllocation> Device::AllocateMemory(
std::unique_ptr<ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl(
const ExternalImageDescriptorDXGISharedHandle* descriptor) {
+ // ExternalImageDXGIImpl holds a weak reference to the device. If the device is destroyed before
+ // the image is created, the image will have a dangling reference to the device which can cause
+ // a use-after-free.
+ if (ConsumedError(ValidateIsAlive())) {
+ return nullptr;
+ }
+
+ // Use sharedHandle as a fallback until Chromium code is changed to set textureSharedHandle.
+ HANDLE textureSharedHandle = descriptor->textureSharedHandle;
+ if (!textureSharedHandle) {
+ textureSharedHandle = descriptor->sharedHandle;
+ }
+
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource;
- if (FAILED(GetD3D12Device()->OpenSharedHandle(descriptor->sharedHandle,
+ if (FAILED(GetD3D12Device()->OpenSharedHandle(textureSharedHandle,
IID_PPV_ARGS(&d3d12Resource)))) {
return nullptr;
}
+ Microsoft::WRL::ComPtr<ID3D12Fence> d3d12Fence;
+ if (descriptor->fenceSharedHandle &&
+ FAILED(GetD3D12Device()->OpenSharedHandle(descriptor->fenceSharedHandle,
+ IID_PPV_ARGS(&d3d12Fence)))) {
+ return nullptr;
+ }
+
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
@@ -568,8 +588,8 @@ std::unique_ptr<ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl(
}
}
- auto impl = std::make_unique<ExternalImageDXGIImpl>(this, std::move(d3d12Resource),
- descriptor->cTextureDescriptor);
+ auto impl = std::make_unique<ExternalImageDXGIImpl>(
+ this, std::move(d3d12Resource), std::move(d3d12Fence), descriptor->cTextureDescriptor);
mExternalImageList.Append(impl.get());
return impl;
}
@@ -577,13 +597,17 @@ std::unique_ptr<ExternalImageDXGIImpl> Device::CreateExternalImageDXGIImpl(
Ref<TextureBase> Device::CreateD3D12ExternalTexture(
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
+ ComPtr<ID3D12Fence> d3d12Fence,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
+ uint64_t fenceWaitValue,
+ uint64_t fenceSignalValue,
bool isSwapChainTexture,
bool isInitialized) {
Ref<Texture> dawnTexture;
- if (ConsumedError(Texture::CreateExternalImage(this, descriptor, std::move(d3d12Texture),
- std::move(d3d11on12Resource), isSwapChainTexture,
- isInitialized),
+ if (ConsumedError(Texture::CreateExternalImage(
+ this, descriptor, std::move(d3d12Texture), std::move(d3d12Fence),
+ std::move(d3d11on12Resource), fenceWaitValue, fenceSignalValue,
+ isSwapChainTexture, isInitialized),
&dawnTexture)) {
return nullptr;
}
@@ -620,6 +644,15 @@ void Device::InitTogglesFromDriver() {
SetToggle(Toggle::UseD3D12RenderPass, GetDeviceInfo().supportsRenderPass);
SetToggle(Toggle::UseD3D12ResidencyManagement, true);
SetToggle(Toggle::UseDXC, false);
+ SetToggle(Toggle::D3D12AlwaysUseTypelessFormatsForCastableTexture,
+ !GetDeviceInfo().supportsCastingFullyTypedFormat);
+ SetToggle(Toggle::ApplyClearBigIntegerColorValueWithDraw, true);
+
+ // The restriction on the source box specifying a portion of the depth stencil texture in
+ // CopyTextureRegion() is only available on the D3D12 platforms which doesn't support
+ // programmable sample positions.
+ SetToggle(Toggle::D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset,
+ GetDeviceInfo().programmableSamplePositionsTier == 0);
// Disable optimizations when using FXC
// See https://crbug.com/dawn/1203
@@ -631,22 +664,42 @@ void Device::InitTogglesFromDriver() {
uint32_t deviceId = GetAdapter()->GetDeviceId();
uint32_t vendorId = GetAdapter()->GetVendorId();
- // Currently this workaround is only needed on Intel Gen9 and Gen9.5 GPUs.
+ // Currently this workaround is only needed on Intel Gen9, Gen9.5 and Gen11 GPUs.
// See http://crbug.com/1161355 for more information.
- if (gpu_info::IsIntelGen9(vendorId, deviceId)) {
- constexpr gpu_info::D3DDriverVersion kFirstDriverVersionWithFix = {30, 0, 100, 9864};
- if (gpu_info::CompareD3DDriverVersion(vendorId, ToBackend(GetAdapter())->GetDriverVersion(),
- kFirstDriverVersionWithFix) < 0) {
- SetToggle(
- Toggle::UseTempBufferInSmallFormatTextureToTextureCopyFromGreaterToLessMipLevel,
- true);
- }
+ if (gpu_info::IsIntelGen9(vendorId, deviceId) || gpu_info::IsIntelGen11(vendorId, deviceId)) {
+ SetToggle(Toggle::UseTempBufferInSmallFormatTextureToTextureCopyFromGreaterToLessMipLevel,
+ true);
+ }
+
+ // Currently this workaround is only needed on Intel GPUs.
+ // See http://crbug.com/dawn/1487 for more information.
+ if (gpu_info::IsIntel(vendorId)) {
+ SetToggle(Toggle::D3D12ForceClearCopyableDepthStencilTextureOnCreation, true);
+ }
+
+ // Currently this workaround is only needed on Intel Gen12 GPUs.
+ // See http://crbug.com/dawn/1487 for more information.
+ if (gpu_info::IsIntelGen12LP(vendorId, deviceId) ||
+ gpu_info::IsIntelGen12HP(vendorId, deviceId)) {
+ SetToggle(Toggle::D3D12DontSetClearValueOnDepthTextureCreation, true);
}
// Currently this workaround is needed on any D3D12 backend for some particular situations.
// But we may need to limit it if D3D12 runtime fixes the bug on its new release. See
// https://crbug.com/dawn/1289 for more information.
+ // TODO(dawn:1289): Unset this toggle when we skip the split on the buffer-texture copy
+ // on the platforms where UnrestrictedBufferTextureCopyPitchSupported is true.
SetToggle(Toggle::D3D12SplitBufferTextureCopyForRowsPerImagePaddings, true);
+
+ // This workaround is only needed on Intel Gen12LP with driver prior to 30.0.101.1960.
+ // See http://crbug.com/dawn/949 for more information.
+ if (gpu_info::IsIntelGen12LP(vendorId, deviceId)) {
+ const gpu_info::D3DDriverVersion version = {30, 0, 101, 1960};
+ if (gpu_info::CompareD3DDriverVersion(vendorId, ToBackend(GetAdapter())->GetDriverVersion(),
+ version) == -1) {
+ SetToggle(Toggle::D3D12AllocateExtraMemoryFor2DArrayTexture, true);
+ }
+ }
}
MaybeError Device::WaitForIdleForDestruction() {
@@ -853,4 +906,17 @@ bool Device::ShouldDuplicateParametersForDrawIndirect(
return ToBackend(renderPipelineBase)->UsesVertexOrInstanceIndex();
}
+uint64_t Device::GetBufferCopyOffsetAlignmentForDepthStencil() const {
+ // On the D3D12 platforms where programmable MSAA is not supported, the source box specifying a
+ // portion of the depth texture must all be 0, or an error and a device lost will occur, so on
+ // these platforms the buffer copy offset must be a multiple of 512 when the texture is created
+ // with D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL. See https://crbug.com/dawn/727 for more
+ // details.
+ if (IsToggleEnabled(
+ Toggle::D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset)) {
+ return D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
+ }
+ return DeviceBase::GetBufferCopyOffsetAlignmentForDepthStencil();
+}
+
} // namespace dawn::native::d3d12
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.h b/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.h
index 5371e5b0ce8..0373cf9d828 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/DeviceD3D12.h
@@ -136,7 +136,10 @@ class Device final : public DeviceBase {
Ref<TextureBase> CreateD3D12ExternalTexture(const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
+ ComPtr<ID3D12Fence> d3d12Fence,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
+ uint64_t fenceWaitValue,
+ uint64_t fenceSignalValue,
bool isSwapChainTexture,
bool isInitialized);
@@ -159,6 +162,8 @@ class Device final : public DeviceBase {
bool IsFeatureEnabled(Feature feature) const override;
+ uint64_t GetBufferCopyOffsetAlignmentForDepthStencil() const override;
+
// Dawn APIs
void SetLabelImpl() override;
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp
index 8df2d306ab4..1fdf7d6c491 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.cpp
@@ -28,9 +28,11 @@ namespace dawn::native::d3d12 {
ExternalImageDXGIImpl::ExternalImageDXGIImpl(Device* backendDevice,
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
+ Microsoft::WRL::ComPtr<ID3D12Fence> d3d12Fence,
const WGPUTextureDescriptor* descriptor)
: mBackendDevice(backendDevice),
mD3D12Resource(std::move(d3d12Resource)),
+ mD3D12Fence(std::move(d3d12Fence)),
mD3D11on12ResourceCache(std::make_unique<D3D11on12ResourceCache>()),
mUsage(descriptor->usage),
mDimension(descriptor->dimension),
@@ -60,14 +62,20 @@ bool ExternalImageDXGIImpl::IsValid() const {
void ExternalImageDXGIImpl::Destroy() {
if (IsInList()) {
RemoveFromList();
+
+ // Keep fence alive until any pending signal calls are done on the GPU.
+ mBackendDevice->ConsumedError(mBackendDevice->NextSerial());
+ mBackendDevice->ReferenceUntilUnused(mD3D12Fence.Get());
mBackendDevice = nullptr;
+
mD3D12Resource.Reset();
+ mD3D12Fence.Reset();
mD3D11on12ResourceCache.reset();
}
}
WGPUTexture ExternalImageDXGIImpl::ProduceTexture(
- const ExternalImageAccessDescriptorDXGIKeyedMutex* descriptor) {
+ const ExternalImageAccessDescriptorDXGISharedHandle* descriptor) {
ASSERT(mBackendDevice != nullptr);
// Ensure the texture usage is allowed
if (!IsSubset(descriptor->usage, mUsage)) {
@@ -90,16 +98,20 @@ WGPUTexture ExternalImageDXGIImpl::ProduceTexture(
internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor;
}
- Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource =
- mD3D11on12ResourceCache->GetOrCreateD3D11on12Resource(mBackendDevice, mD3D12Resource.Get());
- if (d3d11on12Resource == nullptr) {
- dawn::ErrorLog() << "Unable to create 11on12 resource for external image";
- return nullptr;
+ Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource;
+ if (!mD3D12Fence) {
+ d3d11on12Resource = mD3D11on12ResourceCache->GetOrCreateD3D11on12Resource(
+ mBackendDevice, mD3D12Resource.Get());
+ if (d3d11on12Resource == nullptr) {
+ dawn::ErrorLog() << "Unable to create 11on12 resource for external image";
+ return nullptr;
+ }
}
Ref<TextureBase> texture = mBackendDevice->CreateD3D12ExternalTexture(
- &textureDescriptor, mD3D12Resource, std::move(d3d11on12Resource),
- descriptor->isSwapChainTexture, descriptor->isInitialized);
+ &textureDescriptor, mD3D12Resource, mD3D12Fence, std::move(d3d11on12Resource),
+ descriptor->fenceWaitValue, descriptor->fenceSignalValue, descriptor->isSwapChainTexture,
+ descriptor->isInitialized);
return ToAPI(texture.Detach());
}
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.h b/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.h
index ca6acefc87f..016ce4a0e57 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/ExternalImageDXGIImpl.h
@@ -30,13 +30,14 @@ namespace dawn::native::d3d12 {
class D3D11on12ResourceCache;
class Device;
-struct ExternalImageAccessDescriptorDXGIKeyedMutex;
+struct ExternalImageAccessDescriptorDXGISharedHandle;
struct ExternalImageDescriptorDXGISharedHandle;
class ExternalImageDXGIImpl : public LinkNode<ExternalImageDXGIImpl> {
public:
ExternalImageDXGIImpl(Device* backendDevice,
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
+ Microsoft::WRL::ComPtr<ID3D12Fence> d3d12Fence,
const WGPUTextureDescriptor* descriptor);
~ExternalImageDXGIImpl();
@@ -47,11 +48,12 @@ class ExternalImageDXGIImpl : public LinkNode<ExternalImageDXGIImpl> {
bool IsValid() const;
- WGPUTexture ProduceTexture(const ExternalImageAccessDescriptorDXGIKeyedMutex* descriptor);
+ WGPUTexture ProduceTexture(const ExternalImageAccessDescriptorDXGISharedHandle* descriptor);
private:
Device* mBackendDevice;
Microsoft::WRL::ComPtr<ID3D12Resource> mD3D12Resource;
+ Microsoft::WRL::ComPtr<ID3D12Fence> mD3D12Fence;
std::unique_ptr<D3D11on12ResourceCache> mD3D11on12ResourceCache;
// Contents of WGPUTextureDescriptor are stored individually since the descriptor
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp
index 636fae233d0..aca85e83f88 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp
@@ -271,7 +271,7 @@ MaybeError PipelineLayout::Initialize() {
0, mRootSignatureBlob->GetBufferPointer(),
mRootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&mRootSignature)),
"D3D12 create root signature"));
- mCacheKey.Record(mRootSignatureBlob.Get());
+ StreamIn(&mCacheKey, mRootSignatureBlob.Get());
return {};
}
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/RenderPipelineD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
index 00fc77b2ddf..b1da7266918 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
@@ -235,7 +235,7 @@ uint8_t D3D12RenderTargetWriteMask(wgpu::ColorWriteMask writeMask) {
}
D3D12_RENDER_TARGET_BLEND_DESC ComputeColorDesc(const ColorTargetState* state) {
- D3D12_RENDER_TARGET_BLEND_DESC blendDesc;
+ D3D12_RENDER_TARGET_BLEND_DESC blendDesc = {};
blendDesc.BlendEnable = state->blend != nullptr;
if (blendDesc.BlendEnable) {
blendDesc.SrcBlend = D3D12Blend(state->blend->color.srcFactor);
@@ -273,7 +273,7 @@ D3D12_STENCIL_OP StencilOp(wgpu::StencilOperation op) {
}
D3D12_DEPTH_STENCILOP_DESC StencilOpDesc(const StencilFaceState& descriptor) {
- D3D12_DEPTH_STENCILOP_DESC desc;
+ D3D12_DEPTH_STENCILOP_DESC desc = {};
desc.StencilFailOp = StencilOp(descriptor.failOp);
desc.StencilDepthFailOp = StencilOp(descriptor.depthFailOp);
@@ -284,23 +284,23 @@ D3D12_DEPTH_STENCILOP_DESC StencilOpDesc(const StencilFaceState& descriptor) {
}
D3D12_DEPTH_STENCIL_DESC ComputeDepthStencilDesc(const DepthStencilState* descriptor) {
- D3D12_DEPTH_STENCIL_DESC mDepthStencilDescriptor;
- mDepthStencilDescriptor.DepthEnable =
+ D3D12_DEPTH_STENCIL_DESC depthStencilDescriptor = {};
+ depthStencilDescriptor.DepthEnable =
(descriptor->depthCompare == wgpu::CompareFunction::Always &&
!descriptor->depthWriteEnabled)
? FALSE
: TRUE;
- mDepthStencilDescriptor.DepthWriteMask =
+ depthStencilDescriptor.DepthWriteMask =
descriptor->depthWriteEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
- mDepthStencilDescriptor.DepthFunc = ToD3D12ComparisonFunc(descriptor->depthCompare);
+ depthStencilDescriptor.DepthFunc = ToD3D12ComparisonFunc(descriptor->depthCompare);
- mDepthStencilDescriptor.StencilEnable = StencilTestEnabled(descriptor) ? TRUE : FALSE;
- mDepthStencilDescriptor.StencilReadMask = static_cast<UINT8>(descriptor->stencilReadMask);
- mDepthStencilDescriptor.StencilWriteMask = static_cast<UINT8>(descriptor->stencilWriteMask);
+ depthStencilDescriptor.StencilEnable = StencilTestEnabled(descriptor) ? TRUE : FALSE;
+ depthStencilDescriptor.StencilReadMask = static_cast<UINT8>(descriptor->stencilReadMask);
+ depthStencilDescriptor.StencilWriteMask = static_cast<UINT8>(descriptor->stencilWriteMask);
- mDepthStencilDescriptor.FrontFace = StencilOpDesc(descriptor->stencilFront);
- mDepthStencilDescriptor.BackFace = StencilOpDesc(descriptor->stencilBack);
- return mDepthStencilDescriptor;
+ depthStencilDescriptor.FrontFace = StencilOpDesc(descriptor->stencilFront);
+ depthStencilDescriptor.BackFace = StencilOpDesc(descriptor->stencilBack);
+ return depthStencilDescriptor;
}
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE ComputeIndexBufferStripCutValue(
@@ -389,7 +389,7 @@ MaybeError RenderPipeline::Initialize() {
descriptorD3D12.RasterizerState.DepthBias = GetDepthBias();
descriptorD3D12.RasterizerState.DepthBiasClamp = GetDepthBiasClamp();
descriptorD3D12.RasterizerState.SlopeScaledDepthBias = GetDepthBiasSlopeScale();
- descriptorD3D12.RasterizerState.DepthClipEnable = TRUE;
+ descriptorD3D12.RasterizerState.DepthClipEnable = !HasUnclippedDepth();
descriptorD3D12.RasterizerState.MultisampleEnable = (GetSampleCount() > 1) ? TRUE : FALSE;
descriptorD3D12.RasterizerState.AntialiasedLineEnable = FALSE;
descriptorD3D12.RasterizerState.ForcedSampleCount = 0;
@@ -402,9 +402,6 @@ MaybeError RenderPipeline::Initialize() {
static_assert(kMaxColorAttachments == 8);
for (uint8_t i = 0; i < kMaxColorAttachments; i++) {
descriptorD3D12.RTVFormats[i] = DXGI_FORMAT_UNKNOWN;
- descriptorD3D12.BlendState.RenderTarget[i].BlendEnable = false;
- descriptorD3D12.BlendState.RenderTarget[i].RenderTargetWriteMask = 0;
- descriptorD3D12.BlendState.RenderTarget[i].LogicOpEnable = false;
descriptorD3D12.BlendState.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_NOOP;
}
ColorAttachmentIndex highestColorAttachmentIndexPlusOne =
@@ -430,7 +427,7 @@ MaybeError RenderPipeline::Initialize() {
mD3d12PrimitiveTopology = D3D12PrimitiveTopology(GetPrimitiveTopology());
- mCacheKey.Record(descriptorD3D12, *layout->GetRootSignatureBlob());
+ StreamIn(&mCacheKey, descriptorD3D12, *layout->GetRootSignatureBlob());
// Try to see if we have anything in the blob cache.
Blob blob = device->LoadCachedBlob(GetCacheKey());
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
index dbcea824cd9..d1f8b2640d7 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
@@ -24,6 +24,8 @@
#include "dawn/native/d3d12/ResidencyManagerD3D12.h"
#include "dawn/native/d3d12/UtilsD3D12.h"
+static constexpr uint32_t kExtraMemoryToMitigateTextureCorruption = 24576u;
+
namespace dawn::native::d3d12 {
namespace {
MemorySegment GetMemorySegment(Device* device, D3D12_HEAP_TYPE heapType) {
@@ -152,7 +154,19 @@ uint64_t GetResourcePlacementAlignment(ResourceHeapKind resourceHeapKind,
}
}
-bool IsClearValueOptimizable(const D3D12_RESOURCE_DESC& resourceDescriptor) {
+bool IsClearValueOptimizable(DeviceBase* device, const D3D12_RESOURCE_DESC& resourceDescriptor) {
+ if (device->IsToggleEnabled(Toggle::D3D12DontSetClearValueOnDepthTextureCreation)) {
+ switch (resourceDescriptor.Format) {
+ case DXGI_FORMAT_D16_UNORM:
+ case DXGI_FORMAT_D32_FLOAT:
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ return false;
+ default:
+ break;
+ }
+ }
+
// Optimized clear color cannot be set on buffers, non-render-target/depth-stencil
// textures, or typeless resources
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createcommittedresource
@@ -192,7 +206,7 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::AllocateMemory(
// some architectures.
D3D12_CLEAR_VALUE zero{};
D3D12_CLEAR_VALUE* optimizedClearValue = nullptr;
- if (IsClearValueOptimizable(resourceDescriptor)) {
+ if (IsClearValueOptimizable(mDevice, resourceDescriptor)) {
zero.Format = resourceDescriptor.Format;
optimizedClearValue = &zero;
}
@@ -299,6 +313,8 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
}
+ resourceInfo.SizeInBytes += GetResourcePadding(resourceDescriptor);
+
// If d3d tells us the resource size is invalid, treat the error as OOM.
// Otherwise, creating the resource could cause a device loss (too large).
// This is because NextPowerOfTwo(UINT64_MAX) overflows and proceeds to
@@ -321,6 +337,21 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
Heap* heap = ToBackend(allocation.GetResourceHeap());
+ ComPtr<ID3D12Resource> placedResource;
+ DAWN_TRY_ASSIGN(placedResource,
+ CreatePlacedResourceInHeap(heap, allocation.GetOffset(), resourceDescriptor,
+ optimizedClearValue, initialUsage));
+ return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(),
+ std::move(placedResource), heap};
+}
+
+ResultOrError<ComPtr<ID3D12Resource>> ResourceAllocatorManager::CreatePlacedResourceInHeap(
+ Heap* heap,
+ const uint64_t offset,
+ const D3D12_RESOURCE_DESC& resourceDescriptor,
+ const D3D12_CLEAR_VALUE* optimizedClearValue,
+ D3D12_RESOURCE_STATES initialUsage) {
+ ComPtr<ID3D12Resource> placedResource;
// Before calling CreatePlacedResource, we must ensure the target heap is resident.
// CreatePlacedResource will fail if it is not.
DAWN_TRY(mDevice->GetResidencyManager()->LockAllocation(heap));
@@ -332,19 +363,16 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedReso
// within the same command-list and does not require additional synchronization (aliasing
// barrier).
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource
- ComPtr<ID3D12Resource> placedResource;
- DAWN_TRY(CheckOutOfMemoryHRESULT(
- mDevice->GetD3D12Device()->CreatePlacedResource(
- heap->GetD3D12Heap(), allocation.GetOffset(), &resourceDescriptor, initialUsage,
- optimizedClearValue, IID_PPV_ARGS(&placedResource)),
- "ID3D12Device::CreatePlacedResource"));
+ DAWN_TRY(
+ CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreatePlacedResource(
+ heap->GetD3D12Heap(), offset, &resourceDescriptor, initialUsage,
+ optimizedClearValue, IID_PPV_ARGS(&placedResource)),
+ "ID3D12Device::CreatePlacedResource"));
// After CreatePlacedResource has finished, the heap can be unlocked from residency. This
// will insert it into the residency LRU.
mDevice->GetResidencyManager()->UnlockAllocation(heap);
-
- return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(),
- std::move(placedResource), heap};
+ return std::move(placedResource);
}
ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedResource(
@@ -365,6 +393,10 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
// incorrectly allocate a mismatched size.
D3D12_RESOURCE_ALLOCATION_INFO resourceInfo =
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
+
+ uint64_t extraMemory = GetResourcePadding(resourceDescriptor);
+ resourceInfo.SizeInBytes += extraMemory;
+
if (resourceInfo.SizeInBytes == 0 ||
resourceInfo.SizeInBytes == std::numeric_limits<uint64_t>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Resource allocation size was invalid.");
@@ -383,11 +415,23 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
// Note: Heap flags are inferred by the resource descriptor and do not need to be explicitly
// provided to CreateCommittedResource.
ComPtr<ID3D12Resource> committedResource;
- DAWN_TRY(CheckOutOfMemoryHRESULT(
- mDevice->GetD3D12Device()->CreateCommittedResource(
- &heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDescriptor, initialUsage,
- optimizedClearValue, IID_PPV_ARGS(&committedResource)),
- "ID3D12Device::CreateCommittedResource"));
+ if (extraMemory > 0) {
+ const ResourceHeapKind resourceHeapKind = GetResourceHeapKind(
+ resourceDescriptor.Dimension, heapType, resourceDescriptor.Flags, mResourceHeapTier);
+ std::unique_ptr<ResourceHeapBase> heapBase;
+ DAWN_TRY_ASSIGN(heapBase, mPooledHeapAllocators[resourceHeapKind]->AllocateResourceHeap(
+ resourceInfo.SizeInBytes));
+ Heap* heap = ToBackend(heapBase.get());
+ DAWN_TRY_ASSIGN(committedResource,
+ CreatePlacedResourceInHeap(heap, 0, resourceDescriptor, optimizedClearValue,
+ initialUsage));
+ } else {
+ DAWN_TRY(CheckOutOfMemoryHRESULT(
+ mDevice->GetD3D12Device()->CreateCommittedResource(
+ &heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDescriptor, initialUsage,
+ optimizedClearValue, IID_PPV_ARGS(&committedResource)),
+ "ID3D12Device::CreateCommittedResource"));
+ }
// When using CreateCommittedResource, D3D12 creates an implicit heap that contains the
// resource allocation. Because Dawn's memory residency management occurs at the resource
@@ -408,6 +452,17 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedR
/*offset*/ 0, std::move(committedResource), heap};
}
+uint64_t ResourceAllocatorManager::GetResourcePadding(
+ const D3D12_RESOURCE_DESC& resourceDescriptor) const {
+ // If we are allocating memory for a 2D array texture on D3D12 backend, we need to allocate
+ // extra memory on some devices, see crbug.com/dawn/949 for details.
+ if (mDevice->IsToggleEnabled(Toggle::D3D12AllocateExtraMemoryFor2DArrayTexture) &&
+ resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
+ resourceDescriptor.DepthOrArraySize > 1) {
+ return kExtraMemoryToMitigateTextureCorruption;
+ }
+ return 0;
+}
void ResourceAllocatorManager::DestroyPool() {
for (auto& alloc : mPooledHeapAllocators) {
alloc->DestroyPool();
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h b/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h
index 5b6dfd84600..7bb454d9cf4 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.h
@@ -86,6 +86,15 @@ class ResourceAllocatorManager {
const D3D12_CLEAR_VALUE* optimizedClearValue,
D3D12_RESOURCE_STATES initialUsage);
+ ResultOrError<ComPtr<ID3D12Resource>> CreatePlacedResourceInHeap(
+ Heap* heap,
+ const uint64_t offset,
+ const D3D12_RESOURCE_DESC& resourceDescriptor,
+ const D3D12_CLEAR_VALUE* optimizedClearValue,
+ D3D12_RESOURCE_STATES initialUsage);
+
+ uint64_t GetResourcePadding(const D3D12_RESOURCE_DESC& resourceDescriptor) const;
+
Device* mDevice;
uint32_t mResourceHeapTier;
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index 7a23be5e7fd..ce83dbefeed 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -29,79 +29,41 @@
#include "dawn/common/Log.h"
#include "dawn/common/WindowsUtils.h"
#include "dawn/native/CacheKey.h"
+#include "dawn/native/CacheRequest.h"
#include "dawn/native/Pipeline.h"
#include "dawn/native/TintUtils.h"
#include "dawn/native/d3d12/AdapterD3D12.h"
#include "dawn/native/d3d12/BackendD3D12.h"
#include "dawn/native/d3d12/BindGroupLayoutD3D12.h"
+#include "dawn/native/d3d12/BlobD3D12.h"
#include "dawn/native/d3d12/D3D12Error.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
#include "dawn/native/d3d12/PipelineLayoutD3D12.h"
#include "dawn/native/d3d12/PlatformFunctions.h"
#include "dawn/native/d3d12/UtilsD3D12.h"
+#include "dawn/native/stream/BlobSource.h"
+#include "dawn/native/stream/ByteVectorSink.h"
#include "dawn/platform/DawnPlatform.h"
#include "dawn/platform/tracing/TraceEvent.h"
#include "tint/tint.h"
-namespace dawn::native::d3d12 {
-
-namespace {
-uint64_t GetD3DCompilerVersion() {
- return D3D_COMPILER_VERSION;
-}
-
-struct CompareBindingPoint {
- constexpr bool operator()(const tint::transform::BindingPoint& lhs,
- const tint::transform::BindingPoint& rhs) const {
- if (lhs.group != rhs.group) {
- return lhs.group < rhs.group;
- } else {
- return lhs.binding < rhs.binding;
- }
- }
-};
+namespace dawn::native::stream {
-void Serialize(std::stringstream& output, const tint::ast::Access& access) {
- output << access;
-}
+// Define no-op serializations for pD3DCompile, IDxcLibrary, and IDxcCompiler.
+// These are output-only interfaces used to generate bytecode.
+template <>
+void Stream<IDxcLibrary*>::Write(Sink*, IDxcLibrary* const&) {}
+template <>
+void Stream<IDxcCompiler*>::Write(Sink*, IDxcCompiler* const&) {}
+template <>
+void Stream<pD3DCompile>::Write(Sink*, pD3DCompile const&) {}
-void Serialize(std::stringstream& output, const tint::transform::BindingPoint& binding_point) {
- output << "(BindingPoint";
- output << " group=" << binding_point.group;
- output << " binding=" << binding_point.binding;
- output << ")";
-}
+} // namespace dawn::native::stream
-template <typename T, typename = typename std::enable_if<std::is_fundamental<T>::value>::type>
-void Serialize(std::stringstream& output, const T& val) {
- output << val;
-}
-
-template <typename T>
-void Serialize(std::stringstream& output,
- const std::unordered_map<tint::transform::BindingPoint, T>& map) {
- output << "(map";
-
- std::map<tint::transform::BindingPoint, T, CompareBindingPoint> sorted(map.begin(), map.end());
- for (auto& [bindingPoint, value] : sorted) {
- output << " ";
- Serialize(output, bindingPoint);
- output << "=";
- Serialize(output, value);
- }
- output << ")";
-}
+namespace dawn::native::d3d12 {
-void Serialize(std::stringstream& output,
- const tint::writer::ArrayLengthFromUniformOptions& arrayLengthFromUniform) {
- output << "(ArrayLengthFromUniformOptions";
- output << " ubo_binding=";
- Serialize(output, arrayLengthFromUniform.ubo_binding);
- output << " bindpoint_to_size_index=";
- Serialize(output, arrayLengthFromUniform.bindpoint_to_size_index);
- output << ")";
-}
+namespace {
// 32 bit float has 7 decimal digits of precision so setting n to 8 should be enough
std::string FloatToStringWithPrecision(float v, std::streamsize n = 8) {
@@ -111,17 +73,17 @@ std::string FloatToStringWithPrecision(float v, std::streamsize n = 8) {
return out.str();
}
-std::string GetHLSLValueString(EntryPointMetadata::OverridableConstant::Type dawnType,
- const OverridableConstantScalar* entry,
+std::string GetHLSLValueString(EntryPointMetadata::Override::Type dawnType,
+ const OverrideScalar* entry,
double value = 0) {
switch (dawnType) {
- case EntryPointMetadata::OverridableConstant::Type::Boolean:
+ case EntryPointMetadata::Override::Type::Boolean:
return std::to_string(entry ? entry->b : static_cast<int32_t>(value));
- case EntryPointMetadata::OverridableConstant::Type::Float32:
+ case EntryPointMetadata::Override::Type::Float32:
return FloatToStringWithPrecision(entry ? entry->f32 : static_cast<float>(value));
- case EntryPointMetadata::OverridableConstant::Type::Int32:
+ case EntryPointMetadata::Override::Type::Int32:
return std::to_string(entry ? entry->i32 : static_cast<int32_t>(value));
- case EntryPointMetadata::OverridableConstant::Type::Uint32:
+ case EntryPointMetadata::Override::Type::Uint32:
return std::to_string(entry ? entry->u32 : static_cast<uint32_t>(value));
default:
UNREACHABLE();
@@ -130,253 +92,102 @@ std::string GetHLSLValueString(EntryPointMetadata::OverridableConstant::Type daw
constexpr char kSpecConstantPrefix[] = "WGSL_SPEC_CONSTANT_";
-void GetOverridableConstantsDefines(
- std::vector<std::pair<std::string, std::string>>* defineStrings,
- const PipelineConstantEntries* pipelineConstantEntries,
- const EntryPointMetadata::OverridableConstantsMap* shaderEntryPointConstants) {
+using DefineStrings = std::vector<std::pair<std::string, std::string>>;
+
+DefineStrings GetOverridableConstantsDefines(
+ const PipelineConstantEntries& pipelineConstantEntries,
+ const EntryPointMetadata::OverridesMap& shaderEntryPointConstants) {
+ DefineStrings defineStrings;
std::unordered_set<std::string> overriddenConstants;
// Set pipeline overridden values
- for (const auto& [name, value] : *pipelineConstantEntries) {
+ for (const auto& [name, value] : pipelineConstantEntries) {
overriddenConstants.insert(name);
// This is already validated so `name` must exist
- const auto& moduleConstant = shaderEntryPointConstants->at(name);
+ const auto& moduleConstant = shaderEntryPointConstants.at(name);
- defineStrings->emplace_back(
+ defineStrings.emplace_back(
kSpecConstantPrefix + std::to_string(static_cast<int32_t>(moduleConstant.id)),
GetHLSLValueString(moduleConstant.type, nullptr, value));
}
// Set shader initialized default values
- for (const auto& iter : *shaderEntryPointConstants) {
+ for (const auto& iter : shaderEntryPointConstants) {
const std::string& name = iter.first;
if (overriddenConstants.count(name) != 0) {
// This constant already has overridden value
continue;
}
- const auto& moduleConstant = shaderEntryPointConstants->at(name);
+ const auto& moduleConstant = shaderEntryPointConstants.at(name);
// Uninitialized default values are okay since they ar only defined to pass
// compilation but not used
- defineStrings->emplace_back(
+ defineStrings.emplace_back(
kSpecConstantPrefix + std::to_string(static_cast<int32_t>(moduleConstant.id)),
GetHLSLValueString(moduleConstant.type, &moduleConstant.defaultValue));
}
+ return defineStrings;
}
-// The inputs to a shader compilation. These have been intentionally isolated from the
-// device to help ensure that the pipeline cache key contains all inputs for compilation.
-struct ShaderCompilationRequest {
- enum Compiler { FXC, DXC };
-
- // Common inputs
- Compiler compiler;
- const tint::Program* program;
- const char* entryPointName;
- SingleShaderStage stage;
- uint32_t compileFlags;
- bool disableSymbolRenaming;
- tint::transform::BindingRemapper::BindingPoints remappedBindingPoints;
- tint::transform::BindingRemapper::AccessControls remappedAccessControls;
- bool isRobustnessEnabled;
- bool usesNumWorkgroups;
- uint32_t numWorkgroupsRegisterSpace;
- uint32_t numWorkgroupsShaderRegister;
- tint::writer::ArrayLengthFromUniformOptions arrayLengthFromUniform;
- std::vector<std::pair<std::string, std::string>> defineStrings;
-
- // FXC/DXC common inputs
- bool disableWorkgroupInit;
-
- // FXC inputs
- uint64_t fxcVersion;
-
- // DXC inputs
- uint64_t dxcVersion;
- const D3D12DeviceInfo* deviceInfo;
- bool hasShaderFloat16Feature;
-
- static ResultOrError<ShaderCompilationRequest> Create(
- const char* entryPointName,
- SingleShaderStage stage,
- const PipelineLayout* layout,
- uint32_t compileFlags,
- const Device* device,
- const tint::Program* program,
- const EntryPointMetadata& entryPoint,
- const ProgrammableStage& programmableStage) {
- Compiler compiler;
- uint64_t dxcVersion = 0;
- if (device->IsToggleEnabled(Toggle::UseDXC)) {
- compiler = Compiler::DXC;
- DAWN_TRY_ASSIGN(dxcVersion,
- ToBackend(device->GetAdapter())->GetBackend()->GetDXCompilerVersion());
- } else {
- compiler = Compiler::FXC;
- }
-
- using tint::transform::BindingPoint;
- using tint::transform::BindingRemapper;
-
- BindingRemapper::BindingPoints remappedBindingPoints;
- BindingRemapper::AccessControls remappedAccessControls;
-
- tint::writer::ArrayLengthFromUniformOptions arrayLengthFromUniform;
- arrayLengthFromUniform.ubo_binding = {
- layout->GetDynamicStorageBufferLengthsRegisterSpace(),
- layout->GetDynamicStorageBufferLengthsShaderRegister()};
-
- const BindingInfoArray& moduleBindingInfo = entryPoint.bindings;
- for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
- const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
- const auto& groupBindingInfo = moduleBindingInfo[group];
-
- // d3d12::BindGroupLayout packs the bindings per HLSL register-space. We modify
- // the Tint AST to make the "bindings" decoration match the offset chosen by
- // d3d12::BindGroupLayout so that Tint produces HLSL with the correct registers
- // assigned to each interface variable.
- for (const auto& [binding, bindingInfo] : groupBindingInfo) {
- BindingIndex bindingIndex = bgl->GetBindingIndex(binding);
- BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
- static_cast<uint32_t>(binding)};
- BindingPoint dstBindingPoint{static_cast<uint32_t>(group),
- bgl->GetShaderRegister(bindingIndex)};
- if (srcBindingPoint != dstBindingPoint) {
- remappedBindingPoints.emplace(srcBindingPoint, dstBindingPoint);
- }
-
- // Declaring a read-only storage buffer in HLSL but specifying a storage
- // buffer in the BGL produces the wrong output. Force read-only storage
- // buffer bindings to be treated as UAV instead of SRV. Internal storage
- // buffer is a storage buffer used in the internal pipeline.
- const bool forceStorageBufferAsUAV =
- (bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage &&
- (bgl->GetBindingInfo(bindingIndex).buffer.type ==
- wgpu::BufferBindingType::Storage ||
- bgl->GetBindingInfo(bindingIndex).buffer.type ==
- kInternalStorageBufferBinding));
- if (forceStorageBufferAsUAV) {
- remappedAccessControls.emplace(srcBindingPoint, tint::ast::Access::kReadWrite);
- }
- }
-
- // Add arrayLengthFromUniform options
- {
- for (const auto& bindingAndRegisterOffset :
- layout->GetDynamicStorageBufferLengthInfo()[group].bindingAndRegisterOffsets) {
- BindingNumber binding = bindingAndRegisterOffset.binding;
- uint32_t registerOffset = bindingAndRegisterOffset.registerOffset;
-
- BindingPoint bindingPoint{static_cast<uint32_t>(group),
- static_cast<uint32_t>(binding)};
- // Get the renamed binding point if it was remapped.
- auto it = remappedBindingPoints.find(bindingPoint);
- if (it != remappedBindingPoints.end()) {
- bindingPoint = it->second;
- }
-
- arrayLengthFromUniform.bindpoint_to_size_index.emplace(bindingPoint,
- registerOffset);
- }
- }
- }
-
- ShaderCompilationRequest request;
- request.compiler = compiler;
- request.program = program;
- request.entryPointName = entryPointName;
- request.stage = stage;
- request.compileFlags = compileFlags;
- request.disableSymbolRenaming = device->IsToggleEnabled(Toggle::DisableSymbolRenaming);
- request.remappedBindingPoints = std::move(remappedBindingPoints);
- request.remappedAccessControls = std::move(remappedAccessControls);
- request.isRobustnessEnabled = device->IsRobustnessEnabled();
- request.disableWorkgroupInit = device->IsToggleEnabled(Toggle::DisableWorkgroupInit);
- request.usesNumWorkgroups = entryPoint.usesNumWorkgroups;
- request.numWorkgroupsShaderRegister = layout->GetNumWorkgroupsShaderRegister();
- request.numWorkgroupsRegisterSpace = layout->GetNumWorkgroupsRegisterSpace();
- request.arrayLengthFromUniform = std::move(arrayLengthFromUniform);
- request.fxcVersion = compiler == Compiler::FXC ? GetD3DCompilerVersion() : 0;
- request.dxcVersion = compiler == Compiler::DXC ? dxcVersion : 0;
- request.deviceInfo = &device->GetDeviceInfo();
- request.hasShaderFloat16Feature = device->IsFeatureEnabled(Feature::ShaderFloat16);
-
- GetOverridableConstantsDefines(
- &request.defineStrings, &programmableStage.constants,
- &programmableStage.module->GetEntryPoint(programmableStage.entryPoint)
- .overridableConstants);
-
- return std::move(request);
- }
-
- // TODO(dawn:1341): Move to use CacheKey instead of the vector.
- ResultOrError<std::vector<uint8_t>> CreateCacheKey() const {
- // Generate the WGSL from the Tint program so it's normalized.
- // TODO(tint:1180): Consider using a binary serialization of the tint AST for a more
- // compact representation.
- auto result = tint::writer::wgsl::Generate(program, tint::writer::wgsl::Options{});
- if (!result.success) {
- std::ostringstream errorStream;
- errorStream << "Tint WGSL failure:" << std::endl;
- errorStream << "Generator: " << result.error << std::endl;
- return DAWN_INTERNAL_ERROR(errorStream.str().c_str());
- }
-
- std::stringstream stream;
-
- // Prefix the key with the type to avoid collisions from another type that could
- // have the same key.
- stream << static_cast<uint32_t>(CacheKey::Type::Shader);
- stream << "\n";
-
- stream << result.wgsl.length();
- stream << "\n";
-
- stream << result.wgsl;
- stream << "\n";
-
- stream << "(ShaderCompilationRequest";
- stream << " compiler=" << compiler;
- stream << " entryPointName=" << entryPointName;
- stream << " stage=" << uint32_t(stage);
- stream << " compileFlags=" << compileFlags;
- stream << " disableSymbolRenaming=" << disableSymbolRenaming;
-
- stream << " remappedBindingPoints=";
- Serialize(stream, remappedBindingPoints);
-
- stream << " remappedAccessControls=";
- Serialize(stream, remappedAccessControls);
-
- stream << " useNumWorkgroups=" << usesNumWorkgroups;
- stream << " numWorkgroupsRegisterSpace=" << numWorkgroupsRegisterSpace;
- stream << " numWorkgroupsShaderRegister=" << numWorkgroupsShaderRegister;
-
- stream << " arrayLengthFromUniform=";
- Serialize(stream, arrayLengthFromUniform);
-
- stream << " shaderModel=" << deviceInfo->shaderModel;
- stream << " disableWorkgroupInit=" << disableWorkgroupInit;
- stream << " isRobustnessEnabled=" << isRobustnessEnabled;
- stream << " fxcVersion=" << fxcVersion;
- stream << " dxcVersion=" << dxcVersion;
- stream << " hasShaderFloat16Feature=" << hasShaderFloat16Feature;
-
- stream << " defines={";
- for (const auto& [name, value] : defineStrings) {
- stream << " <" << name << "," << value << ">";
- }
- stream << " }";
-
- stream << ")";
- stream << "\n";
-
- return std::vector<uint8_t>(std::istreambuf_iterator<char>{stream},
- std::istreambuf_iterator<char>{});
- }
-};
+enum class Compiler { FXC, DXC };
+
+#define HLSL_COMPILATION_REQUEST_MEMBERS(X) \
+ X(const tint::Program*, inputProgram) \
+ X(std::string_view, entryPointName) \
+ X(SingleShaderStage, stage) \
+ X(uint32_t, shaderModel) \
+ X(uint32_t, compileFlags) \
+ X(Compiler, compiler) \
+ X(uint64_t, compilerVersion) \
+ X(std::wstring_view, dxcShaderProfile) \
+ X(std::string_view, fxcShaderProfile) \
+ X(pD3DCompile, d3dCompile) \
+ X(IDxcLibrary*, dxcLibrary) \
+ X(IDxcCompiler*, dxcCompiler) \
+ X(uint32_t, firstIndexOffsetShaderRegister) \
+ X(uint32_t, firstIndexOffsetRegisterSpace) \
+ X(bool, usesNumWorkgroups) \
+ X(uint32_t, numWorkgroupsShaderRegister) \
+ X(uint32_t, numWorkgroupsRegisterSpace) \
+ X(DefineStrings, defineStrings) \
+ X(tint::transform::MultiplanarExternalTexture::BindingsMap, newBindingsMap) \
+ X(tint::writer::ArrayLengthFromUniformOptions, arrayLengthFromUniform) \
+ X(tint::transform::BindingRemapper::BindingPoints, remappedBindingPoints) \
+ X(tint::transform::BindingRemapper::AccessControls, remappedAccessControls) \
+ X(bool, disableSymbolRenaming) \
+ X(bool, isRobustnessEnabled) \
+ X(bool, disableWorkgroupInit) \
+ X(bool, dumpShaders)
+
+#define D3D_BYTECODE_COMPILATION_REQUEST_MEMBERS(X) \
+ X(bool, hasShaderFloat16Feature) \
+ X(uint32_t, compileFlags) \
+ X(Compiler, compiler) \
+ X(uint64_t, compilerVersion) \
+ X(std::wstring_view, dxcShaderProfile) \
+ X(std::string_view, fxcShaderProfile) \
+ X(pD3DCompile, d3dCompile) \
+ X(IDxcLibrary*, dxcLibrary) \
+ X(IDxcCompiler*, dxcCompiler) \
+ X(DefineStrings, defineStrings)
+
+DAWN_SERIALIZABLE(struct, HlslCompilationRequest, HLSL_COMPILATION_REQUEST_MEMBERS){};
+#undef HLSL_COMPILATION_REQUEST_MEMBERS
+
+DAWN_SERIALIZABLE(struct,
+ D3DBytecodeCompilationRequest,
+ D3D_BYTECODE_COMPILATION_REQUEST_MEMBERS){};
+#undef D3D_BYTECODE_COMPILATION_REQUEST_MEMBERS
+
+#define D3D_COMPILATION_REQUEST_MEMBERS(X) \
+ X(HlslCompilationRequest, hlsl) \
+ X(D3DBytecodeCompilationRequest, bytecode) \
+ X(CacheKey::UnsafeUnkeyedValue<dawn::platform::Platform*>, tracePlatform)
+
+DAWN_MAKE_CACHE_REQUEST(D3DCompilationRequest, D3D_COMPILATION_REQUEST_MEMBERS);
+#undef D3D_COMPILATION_REQUEST_MEMBERS
std::vector<const wchar_t*> GetDXCArguments(uint32_t compileFlags, bool enable16BitTypes) {
std::vector<const wchar_t*> arguments;
@@ -430,25 +241,24 @@ std::vector<const wchar_t*> GetDXCArguments(uint32_t compileFlags, bool enable16
return arguments;
}
-ResultOrError<ComPtr<IDxcBlob>> CompileShaderDXC(IDxcLibrary* dxcLibrary,
- IDxcCompiler* dxcCompiler,
- const ShaderCompilationRequest& request,
+ResultOrError<ComPtr<IDxcBlob>> CompileShaderDXC(const D3DBytecodeCompilationRequest& r,
+ const std::string& entryPointName,
const std::string& hlslSource) {
ComPtr<IDxcBlobEncoding> sourceBlob;
- DAWN_TRY(CheckHRESULT(dxcLibrary->CreateBlobWithEncodingOnHeapCopy(
+ DAWN_TRY(CheckHRESULT(r.dxcLibrary->CreateBlobWithEncodingFromPinned(
hlslSource.c_str(), hlslSource.length(), CP_UTF8, &sourceBlob),
"DXC create blob"));
std::wstring entryPointW;
- DAWN_TRY_ASSIGN(entryPointW, ConvertStringToWstring(request.entryPointName));
+ DAWN_TRY_ASSIGN(entryPointW, ConvertStringToWstring(entryPointName));
std::vector<const wchar_t*> arguments =
- GetDXCArguments(request.compileFlags, request.hasShaderFloat16Feature);
+ GetDXCArguments(r.compileFlags, r.hasShaderFloat16Feature);
// Build defines for overridable constants
std::vector<std::pair<std::wstring, std::wstring>> defineStrings;
- defineStrings.reserve(request.defineStrings.size());
- for (const auto& [name, value] : request.defineStrings) {
+ defineStrings.reserve(r.defineStrings.size());
+ for (const auto& [name, value] : r.defineStrings) {
defineStrings.emplace_back(UTF8ToWStr(name.c_str()), UTF8ToWStr(value.c_str()));
}
@@ -459,12 +269,11 @@ ResultOrError<ComPtr<IDxcBlob>> CompileShaderDXC(IDxcLibrary* dxcLibrary,
}
ComPtr<IDxcOperationResult> result;
- DAWN_TRY(
- CheckHRESULT(dxcCompiler->Compile(sourceBlob.Get(), nullptr, entryPointW.c_str(),
- request.deviceInfo->shaderProfiles[request.stage].c_str(),
- arguments.data(), arguments.size(), dxcDefines.data(),
- dxcDefines.size(), nullptr, &result),
- "DXC compile"));
+ DAWN_TRY(CheckHRESULT(
+ r.dxcCompiler->Compile(sourceBlob.Get(), nullptr, entryPointW.c_str(),
+ r.dxcShaderProfile.data(), arguments.data(), arguments.size(),
+ dxcDefines.data(), dxcDefines.size(), nullptr, &result),
+ "DXC compile"));
HRESULT hr;
DAWN_TRY(CheckHRESULT(result->GetStatus(&hr), "DXC get status"));
@@ -544,31 +353,18 @@ std::string CompileFlagsToStringFXC(uint32_t compileFlags) {
return result;
}
-ResultOrError<ComPtr<ID3DBlob>> CompileShaderFXC(const PlatformFunctions* functions,
- const ShaderCompilationRequest& request,
+ResultOrError<ComPtr<ID3DBlob>> CompileShaderFXC(const D3DBytecodeCompilationRequest& r,
+ const std::string& entryPointName,
const std::string& hlslSource) {
- const char* targetProfile = nullptr;
- switch (request.stage) {
- case SingleShaderStage::Vertex:
- targetProfile = "vs_5_1";
- break;
- case SingleShaderStage::Fragment:
- targetProfile = "ps_5_1";
- break;
- case SingleShaderStage::Compute:
- targetProfile = "cs_5_1";
- break;
- }
-
ComPtr<ID3DBlob> compiledShader;
ComPtr<ID3DBlob> errors;
// Build defines for overridable constants
const D3D_SHADER_MACRO* pDefines = nullptr;
std::vector<D3D_SHADER_MACRO> fxcDefines;
- if (request.defineStrings.size() > 0) {
- fxcDefines.reserve(request.defineStrings.size() + 1);
- for (const auto& [name, value] : request.defineStrings) {
+ if (r.defineStrings.size() > 0) {
+ fxcDefines.reserve(r.defineStrings.size() + 1);
+ for (const auto& [name, value] : r.defineStrings) {
fxcDefines.push_back({name.c_str(), value.c_str()});
}
// d3dCompile D3D_SHADER_MACRO* pDefines is a nullptr terminated array
@@ -576,36 +372,49 @@ ResultOrError<ComPtr<ID3DBlob>> CompileShaderFXC(const PlatformFunctions* functi
pDefines = fxcDefines.data();
}
- DAWN_INVALID_IF(
- FAILED(functions->d3dCompile(hlslSource.c_str(), hlslSource.length(), nullptr, pDefines,
- nullptr, request.entryPointName, targetProfile,
- request.compileFlags, 0, &compiledShader, &errors)),
- "D3D compile failed with: %s", static_cast<char*>(errors->GetBufferPointer()));
+ DAWN_INVALID_IF(FAILED(r.d3dCompile(hlslSource.c_str(), hlslSource.length(), nullptr, pDefines,
+ nullptr, entryPointName.c_str(), r.fxcShaderProfile.data(),
+ r.compileFlags, 0, &compiledShader, &errors)),
+ "D3D compile failed with: %s", static_cast<char*>(errors->GetBufferPointer()));
return std::move(compiledShader);
}
-ResultOrError<std::string> TranslateToHLSL(dawn::platform::Platform* platform,
- const ShaderCompilationRequest& request,
- std::string* remappedEntryPointName) {
+ResultOrError<std::string> TranslateToHLSL(
+ HlslCompilationRequest r,
+ CacheKey::UnsafeUnkeyedValue<dawn::platform::Platform*> tracePlatform,
+ std::string* remappedEntryPointName,
+ bool* usesVertexOrInstanceIndex) {
std::ostringstream errorStream;
errorStream << "Tint HLSL failure:" << std::endl;
tint::transform::Manager transformManager;
tint::transform::DataMap transformInputs;
- if (request.isRobustnessEnabled) {
+ if (!r.newBindingsMap.empty()) {
+ transformManager.Add<tint::transform::MultiplanarExternalTexture>();
+ transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
+ std::move(r.newBindingsMap));
+ }
+
+ if (r.stage == SingleShaderStage::Vertex) {
+ transformManager.Add<tint::transform::FirstIndexOffset>();
+ transformInputs.Add<tint::transform::FirstIndexOffset::BindingPoint>(
+ r.firstIndexOffsetShaderRegister, r.firstIndexOffsetRegisterSpace);
+ }
+
+ if (r.isRobustnessEnabled) {
transformManager.Add<tint::transform::Robustness>();
}
transformManager.Add<tint::transform::BindingRemapper>();
transformManager.Add<tint::transform::SingleEntryPoint>();
- transformInputs.Add<tint::transform::SingleEntryPoint::Config>(request.entryPointName);
+ transformInputs.Add<tint::transform::SingleEntryPoint::Config>(r.entryPointName.data());
transformManager.Add<tint::transform::Renamer>();
- if (request.disableSymbolRenaming) {
+ if (r.disableSymbolRenaming) {
// We still need to rename HLSL reserved keywords
transformInputs.Add<tint::transform::Renamer::Config>(
tint::transform::Renamer::Target::kHlslKeywords);
@@ -616,104 +425,92 @@ ResultOrError<std::string> TranslateToHLSL(dawn::platform::Platform* platform,
// different types.
const bool mayCollide = true;
transformInputs.Add<tint::transform::BindingRemapper::Remappings>(
- std::move(request.remappedBindingPoints), std::move(request.remappedAccessControls),
- mayCollide);
+ std::move(r.remappedBindingPoints), std::move(r.remappedAccessControls), mayCollide);
tint::Program transformedProgram;
tint::transform::DataMap transformOutputs;
{
- TRACE_EVENT0(platform, General, "RunTransforms");
+ TRACE_EVENT0(tracePlatform.UnsafeGetValue(), General, "RunTransforms");
DAWN_TRY_ASSIGN(transformedProgram,
- RunTransforms(&transformManager, request.program, transformInputs,
+ RunTransforms(&transformManager, r.inputProgram, transformInputs,
&transformOutputs, nullptr));
}
if (auto* data = transformOutputs.Get<tint::transform::Renamer::Data>()) {
- auto it = data->remappings.find(request.entryPointName);
+ auto it = data->remappings.find(r.entryPointName.data());
if (it != data->remappings.end()) {
*remappedEntryPointName = it->second;
} else {
- DAWN_INVALID_IF(!request.disableSymbolRenaming,
+ DAWN_INVALID_IF(!r.disableSymbolRenaming,
"Could not find remapped name for entry point.");
- *remappedEntryPointName = request.entryPointName;
+ *remappedEntryPointName = r.entryPointName;
}
} else {
return DAWN_FORMAT_VALIDATION_ERROR("Transform output missing renamer data.");
}
+ if (r.stage == SingleShaderStage::Vertex) {
+ if (auto* data = transformOutputs.Get<tint::transform::FirstIndexOffset::Data>()) {
+ *usesVertexOrInstanceIndex = data->has_vertex_or_instance_index;
+ } else {
+ return DAWN_FORMAT_VALIDATION_ERROR(
+ "Transform output missing first index offset data.");
+ }
+ }
+
tint::writer::hlsl::Options options;
- options.disable_workgroup_init = request.disableWorkgroupInit;
- if (request.usesNumWorkgroups) {
- options.root_constant_binding_point = tint::sem::BindingPoint{
- request.numWorkgroupsRegisterSpace, request.numWorkgroupsShaderRegister};
+ options.disable_workgroup_init = r.disableWorkgroupInit;
+ if (r.usesNumWorkgroups) {
+ options.root_constant_binding_point =
+ tint::sem::BindingPoint{r.numWorkgroupsRegisterSpace, r.numWorkgroupsShaderRegister};
}
// TODO(dawn:549): HLSL generation outputs the indices into the
// array_length_from_uniform buffer that were actually used. When the blob cache can
// store more than compiled shaders, we should reflect these used indices and store
// them as well. This would allow us to only upload root constants that are actually
// read by the shader.
- options.array_length_from_uniform = request.arrayLengthFromUniform;
- TRACE_EVENT0(platform, General, "tint::writer::hlsl::Generate");
+ options.array_length_from_uniform = r.arrayLengthFromUniform;
+ TRACE_EVENT0(tracePlatform.UnsafeGetValue(), General, "tint::writer::hlsl::Generate");
auto result = tint::writer::hlsl::Generate(&transformedProgram, options);
DAWN_INVALID_IF(!result.success, "An error occured while generating HLSL: %s", result.error);
return std::move(result.hlsl);
}
-template <typename F>
-MaybeError CompileShader(dawn::platform::Platform* platform,
- const PlatformFunctions* functions,
- IDxcLibrary* dxcLibrary,
- IDxcCompiler* dxcCompiler,
- ShaderCompilationRequest&& request,
- bool dumpShaders,
- F&& DumpShadersEmitLog,
- CompiledShader* compiledShader) {
+ResultOrError<CompiledShader> CompileShader(D3DCompilationRequest r) {
+ CompiledShader compiledShader;
// Compile the source shader to HLSL.
- std::string hlslSource;
std::string remappedEntryPoint;
- DAWN_TRY_ASSIGN(hlslSource, TranslateToHLSL(platform, request, &remappedEntryPoint));
- if (dumpShaders) {
- std::ostringstream dumpedMsg;
- dumpedMsg << "/* Dumped generated HLSL */" << std::endl << hlslSource;
- DumpShadersEmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
- }
- request.entryPointName = remappedEntryPoint.c_str();
- switch (request.compiler) {
- case ShaderCompilationRequest::Compiler::DXC: {
- TRACE_EVENT0(platform, General, "CompileShaderDXC");
- DAWN_TRY_ASSIGN(compiledShader->compiledDXCShader,
- CompileShaderDXC(dxcLibrary, dxcCompiler, request, hlslSource));
+ DAWN_TRY_ASSIGN(compiledShader.hlslSource,
+ TranslateToHLSL(std::move(r.hlsl), r.tracePlatform, &remappedEntryPoint,
+ &compiledShader.usesVertexOrInstanceIndex));
+
+ switch (r.bytecode.compiler) {
+ case Compiler::DXC: {
+ TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "CompileShaderDXC");
+ ComPtr<IDxcBlob> compiledDXCShader;
+ DAWN_TRY_ASSIGN(compiledDXCShader, CompileShaderDXC(r.bytecode, remappedEntryPoint,
+ compiledShader.hlslSource));
+ compiledShader.shaderBlob = CreateBlob(std::move(compiledDXCShader));
break;
}
- case ShaderCompilationRequest::Compiler::FXC: {
- TRACE_EVENT0(platform, General, "CompileShaderFXC");
- DAWN_TRY_ASSIGN(compiledShader->compiledFXCShader,
- CompileShaderFXC(functions, request, hlslSource));
+ case Compiler::FXC: {
+ TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "CompileShaderFXC");
+ ComPtr<ID3DBlob> compiledFXCShader;
+ DAWN_TRY_ASSIGN(compiledFXCShader, CompileShaderFXC(r.bytecode, remappedEntryPoint,
+ compiledShader.hlslSource));
+ compiledShader.shaderBlob = CreateBlob(std::move(compiledFXCShader));
break;
}
}
- if (dumpShaders && request.compiler == ShaderCompilationRequest::Compiler::FXC) {
- std::ostringstream dumpedMsg;
- dumpedMsg << "/* FXC compile flags */ " << std::endl
- << CompileFlagsToStringFXC(request.compileFlags) << std::endl;
-
- dumpedMsg << "/* Dumped disassembled DXBC */" << std::endl;
-
- ComPtr<ID3DBlob> disassembly;
- if (FAILED(functions->d3dDisassemble(compiledShader->compiledFXCShader->GetBufferPointer(),
- compiledShader->compiledFXCShader->GetBufferSize(), 0,
- nullptr, &disassembly))) {
- dumpedMsg << "D3D disassemble failed" << std::endl;
- } else {
- dumpedMsg << reinterpret_cast<const char*>(disassembly->GetBufferPointer());
- }
- DumpShadersEmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
+ // If dumpShaders is false, we don't need the HLSL for logging. Clear the contents so it
+ // isn't stored into the cache.
+ if (!r.hlsl.dumpShaders) {
+ compiledShader.hlslSource = "";
}
-
- return {};
+ return compiledShader;
}
} // anonymous namespace
@@ -742,69 +539,181 @@ ResultOrError<CompiledShader> ShaderModule::Compile(const ProgrammableStage& pro
SingleShaderStage stage,
const PipelineLayout* layout,
uint32_t compileFlags) {
- TRACE_EVENT0(GetDevice()->GetPlatform(), General, "ShaderModuleD3D12::Compile");
+ Device* device = ToBackend(GetDevice());
+ TRACE_EVENT0(device->GetPlatform(), General, "ShaderModuleD3D12::Compile");
ASSERT(!IsError());
- ScopedTintICEHandler scopedICEHandler(GetDevice());
+ ScopedTintICEHandler scopedICEHandler(device);
+ const EntryPointMetadata& entryPoint = GetEntryPoint(programmableStage.entryPoint);
+
+ D3DCompilationRequest req = {};
+ req.tracePlatform = UnsafeUnkeyedValue(device->GetPlatform());
+ req.hlsl.shaderModel = device->GetDeviceInfo().shaderModel;
+ req.hlsl.disableSymbolRenaming = device->IsToggleEnabled(Toggle::DisableSymbolRenaming);
+ req.hlsl.isRobustnessEnabled = device->IsRobustnessEnabled();
+ req.hlsl.disableWorkgroupInit = device->IsToggleEnabled(Toggle::DisableWorkgroupInit);
+ req.hlsl.dumpShaders = device->IsToggleEnabled(Toggle::DumpShaders);
+
+ req.bytecode.hasShaderFloat16Feature = device->IsFeatureEnabled(Feature::ShaderFloat16);
+ req.bytecode.compileFlags = compileFlags;
+ req.bytecode.defineStrings =
+ GetOverridableConstantsDefines(programmableStage.constants, entryPoint.overrides);
+ if (device->IsToggleEnabled(Toggle::UseDXC)) {
+ req.bytecode.compiler = Compiler::DXC;
+ req.bytecode.dxcLibrary = device->GetDxcLibrary().Get();
+ req.bytecode.dxcCompiler = device->GetDxcCompiler().Get();
+ DAWN_TRY_ASSIGN(req.bytecode.compilerVersion,
+ ToBackend(device->GetAdapter())->GetBackend()->GetDXCompilerVersion());
+ req.bytecode.dxcShaderProfile = device->GetDeviceInfo().shaderProfiles[stage];
+ } else {
+ req.bytecode.compiler = Compiler::FXC;
+ req.bytecode.d3dCompile = device->GetFunctions()->d3dCompile;
+ req.bytecode.compilerVersion = D3D_COMPILER_VERSION;
+ switch (stage) {
+ case SingleShaderStage::Vertex:
+ req.bytecode.fxcShaderProfile = "vs_5_1";
+ break;
+ case SingleShaderStage::Fragment:
+ req.bytecode.fxcShaderProfile = "ps_5_1";
+ break;
+ case SingleShaderStage::Compute:
+ req.bytecode.fxcShaderProfile = "cs_5_1";
+ break;
+ }
+ }
- Device* device = ToBackend(GetDevice());
+ using tint::transform::BindingPoint;
+ using tint::transform::BindingRemapper;
- CompiledShader compiledShader = {};
+ BindingRemapper::BindingPoints remappedBindingPoints;
+ BindingRemapper::AccessControls remappedAccessControls;
- tint::transform::Manager transformManager;
- tint::transform::DataMap transformInputs;
+ tint::writer::ArrayLengthFromUniformOptions arrayLengthFromUniform;
+ arrayLengthFromUniform.ubo_binding = {layout->GetDynamicStorageBufferLengthsRegisterSpace(),
+ layout->GetDynamicStorageBufferLengthsShaderRegister()};
+
+ const BindingInfoArray& moduleBindingInfo = entryPoint.bindings;
+ for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
+ const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
+ const auto& groupBindingInfo = moduleBindingInfo[group];
+
+ // d3d12::BindGroupLayout packs the bindings per HLSL register-space. We modify
+ // the Tint AST to make the "bindings" decoration match the offset chosen by
+ // d3d12::BindGroupLayout so that Tint produces HLSL with the correct registers
+ // assigned to each interface variable.
+ for (const auto& [binding, bindingInfo] : groupBindingInfo) {
+ BindingIndex bindingIndex = bgl->GetBindingIndex(binding);
+ BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
+ static_cast<uint32_t>(binding)};
+ BindingPoint dstBindingPoint{static_cast<uint32_t>(group),
+ bgl->GetShaderRegister(bindingIndex)};
+ if (srcBindingPoint != dstBindingPoint) {
+ remappedBindingPoints.emplace(srcBindingPoint, dstBindingPoint);
+ }
- const tint::Program* program = GetTintProgram();
- tint::Program programAsValue;
+ // Declaring a read-only storage buffer in HLSL but specifying a storage
+ // buffer in the BGL produces the wrong output. Force read-only storage
+ // buffer bindings to be treated as UAV instead of SRV. Internal storage
+ // buffer is a storage buffer used in the internal pipeline.
+ const bool forceStorageBufferAsUAV =
+ (bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage &&
+ (bgl->GetBindingInfo(bindingIndex).buffer.type ==
+ wgpu::BufferBindingType::Storage ||
+ bgl->GetBindingInfo(bindingIndex).buffer.type == kInternalStorageBufferBinding));
+ if (forceStorageBufferAsUAV) {
+ remappedAccessControls.emplace(srcBindingPoint, tint::ast::Access::kReadWrite);
+ }
+ }
- AddExternalTextureTransform(layout, &transformManager, &transformInputs);
+ // Add arrayLengthFromUniform options
+ {
+ for (const auto& bindingAndRegisterOffset :
+ layout->GetDynamicStorageBufferLengthInfo()[group].bindingAndRegisterOffsets) {
+ BindingNumber binding = bindingAndRegisterOffset.binding;
+ uint32_t registerOffset = bindingAndRegisterOffset.registerOffset;
+
+ BindingPoint bindingPoint{static_cast<uint32_t>(group),
+ static_cast<uint32_t>(binding)};
+ // Get the renamed binding point if it was remapped.
+ auto it = remappedBindingPoints.find(bindingPoint);
+ if (it != remappedBindingPoints.end()) {
+ bindingPoint = it->second;
+ }
- if (stage == SingleShaderStage::Vertex) {
- transformManager.Add<tint::transform::FirstIndexOffset>();
- transformInputs.Add<tint::transform::FirstIndexOffset::BindingPoint>(
- layout->GetFirstIndexOffsetShaderRegister(),
- layout->GetFirstIndexOffsetRegisterSpace());
+ arrayLengthFromUniform.bindpoint_to_size_index.emplace(bindingPoint,
+ registerOffset);
+ }
+ }
}
- tint::transform::DataMap transformOutputs;
- DAWN_TRY_ASSIGN(programAsValue, RunTransforms(&transformManager, program, transformInputs,
- &transformOutputs, nullptr));
- program = &programAsValue;
+ req.hlsl.inputProgram = GetTintProgram();
+ req.hlsl.entryPointName = programmableStage.entryPoint.c_str();
+ req.hlsl.stage = stage;
+ req.hlsl.firstIndexOffsetShaderRegister = layout->GetFirstIndexOffsetShaderRegister();
+ req.hlsl.firstIndexOffsetRegisterSpace = layout->GetFirstIndexOffsetRegisterSpace();
+ req.hlsl.usesNumWorkgroups = entryPoint.usesNumWorkgroups;
+ req.hlsl.numWorkgroupsShaderRegister = layout->GetNumWorkgroupsShaderRegister();
+ req.hlsl.numWorkgroupsRegisterSpace = layout->GetNumWorkgroupsRegisterSpace();
+ req.hlsl.remappedBindingPoints = std::move(remappedBindingPoints);
+ req.hlsl.remappedAccessControls = std::move(remappedAccessControls);
+ req.hlsl.newBindingsMap = BuildExternalTextureTransformBindings(layout);
+ req.hlsl.arrayLengthFromUniform = std::move(arrayLengthFromUniform);
+
+ CacheResult<CompiledShader> compiledShader;
+ DAWN_TRY_LOAD_OR_RUN(compiledShader, device, std::move(req), CompiledShader::FromBlob,
+ CompileShader);
+
+ if (device->IsToggleEnabled(Toggle::DumpShaders)) {
+ std::ostringstream dumpedMsg;
+ dumpedMsg << "/* Dumped generated HLSL */" << std::endl
+ << compiledShader->hlslSource << std::endl;
+ device->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
- if (stage == SingleShaderStage::Vertex) {
- if (auto* data = transformOutputs.Get<tint::transform::FirstIndexOffset::Data>()) {
- // TODO(dawn:549): Consider adding this information to the pipeline cache once we
- // can store more than the shader blob in it.
- compiledShader.usesVertexOrInstanceIndex = data->has_vertex_or_instance_index;
+ if (device->IsToggleEnabled(Toggle::UseDXC)) {
+ dumpedMsg << "/* Dumped disassembled DXIL */" << std::endl;
+ D3D12_SHADER_BYTECODE code = compiledShader->GetD3D12ShaderBytecode();
+ ComPtr<IDxcBlobEncoding> dxcBlob;
+ ComPtr<IDxcBlobEncoding> disassembly;
+ if (FAILED(device->GetDxcLibrary()->CreateBlobWithEncodingFromPinned(
+ code.pShaderBytecode, code.BytecodeLength, 0, &dxcBlob)) ||
+ FAILED(device->GetDxcCompiler()->Disassemble(dxcBlob.Get(), &disassembly))) {
+ dumpedMsg << "DXC disassemble failed" << std::endl;
+ } else {
+ dumpedMsg << std::string_view(
+ static_cast<const char*>(disassembly->GetBufferPointer()),
+ disassembly->GetBufferSize());
+ }
+ } else {
+ dumpedMsg << "/* FXC compile flags */ " << std::endl
+ << CompileFlagsToStringFXC(compileFlags) << std::endl;
+ dumpedMsg << "/* Dumped disassembled DXBC */" << std::endl;
+ ComPtr<ID3DBlob> disassembly;
+ D3D12_SHADER_BYTECODE code = compiledShader->GetD3D12ShaderBytecode();
+ if (FAILED(device->GetFunctions()->d3dDisassemble(
+ code.pShaderBytecode, code.BytecodeLength, 0, nullptr, &disassembly))) {
+ dumpedMsg << "D3D disassemble failed" << std::endl;
+ } else {
+ dumpedMsg << std::string_view(
+ static_cast<const char*>(disassembly->GetBufferPointer()),
+ disassembly->GetBufferSize());
+ }
}
+ device->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
}
- ShaderCompilationRequest request;
- DAWN_TRY_ASSIGN(request,
- ShaderCompilationRequest::Create(
- programmableStage.entryPoint.c_str(), stage, layout, compileFlags, device,
- program, GetEntryPoint(programmableStage.entryPoint), programmableStage));
-
- // TODO(dawn:1341): Add shader cache key generation and caching for the compiled shader.
- DAWN_TRY(CompileShader(
- device->GetPlatform(), device->GetFunctions(),
- device->IsToggleEnabled(Toggle::UseDXC) ? device->GetDxcLibrary().Get() : nullptr,
- device->IsToggleEnabled(Toggle::UseDXC) ? device->GetDxcCompiler().Get() : nullptr,
- std::move(request), device->IsToggleEnabled(Toggle::DumpShaders),
- [&](WGPULoggingType loggingType, const char* message) {
- GetDevice()->EmitLog(loggingType, message);
- },
- &compiledShader));
- return std::move(compiledShader);
+ if (BlobCache* cache = device->GetBlobCache()) {
+ cache->EnsureStored(compiledShader);
+ }
+
+ // Clear the hlslSource. It is only used for logging and should not be used
+ // outside of the compilation.
+ CompiledShader result = compiledShader.Acquire();
+ result.hlslSource = "";
+ return result;
}
D3D12_SHADER_BYTECODE CompiledShader::GetD3D12ShaderBytecode() const {
- if (compiledFXCShader != nullptr) {
- return {compiledFXCShader->GetBufferPointer(), compiledFXCShader->GetBufferSize()};
- } else if (compiledDXCShader != nullptr) {
- return {compiledDXCShader->GetBufferPointer(), compiledDXCShader->GetBufferSize()};
- }
- UNREACHABLE();
- return {};
+ return {shaderBlob.Data(), shaderBlob.Size()};
}
+
} // namespace dawn::native::d3d12
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.h b/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.h
index 7f68b10221b..8c70bb45a4d 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/ShaderModuleD3D12.h
@@ -15,8 +15,11 @@
#ifndef SRC_DAWN_NATIVE_D3D12_SHADERMODULED3D12_H_
#define SRC_DAWN_NATIVE_D3D12_SHADERMODULED3D12_H_
-#include "dawn/native/ShaderModule.h"
+#include <string>
+#include "dawn/native/Blob.h"
+#include "dawn/native/Serializable.h"
+#include "dawn/native/ShaderModule.h"
#include "dawn/native/d3d12/d3d12_platform.h"
namespace dawn::native {
@@ -28,15 +31,19 @@ namespace dawn::native::d3d12 {
class Device;
class PipelineLayout;
-// Manages a ref to one of the various representations of shader blobs and information used to
-// emulate vertex/instance index starts
-struct CompiledShader {
- ComPtr<ID3DBlob> compiledFXCShader;
- ComPtr<IDxcBlob> compiledDXCShader;
- D3D12_SHADER_BYTECODE GetD3D12ShaderBytecode() const;
+#define COMPILED_SHADER_MEMBERS(X) \
+ X(Blob, shaderBlob) \
+ X(std::string, hlslSource) \
+ X(bool, usesVertexOrInstanceIndex)
- bool usesVertexOrInstanceIndex;
+// `CompiledShader` holds a ref to one of the various representations of shader blobs and
+// information used to emulate vertex/instance index starts. It also holds the `hlslSource` for the
+// shader compilation, which is only transiently available during Compile, and cleared before it
+// returns. It is not written to or loaded from the cache unless Toggle dump_shaders is true.
+DAWN_SERIALIZABLE(struct, CompiledShader, COMPILED_SHADER_MEMBERS) {
+ D3D12_SHADER_BYTECODE GetD3D12ShaderBytecode() const;
};
+#undef COMPILED_SHADER_MEMBERS
class ShaderModule final : public ShaderModuleBase {
public:
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/StreamImplD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/StreamImplD3D12.cpp
new file mode 100644
index 00000000000..7fce45a5276
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/StreamImplD3D12.cpp
@@ -0,0 +1,122 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/common/Assert.h"
+#include "dawn/common/Constants.h"
+#include "dawn/native/d3d12/d3d12_platform.h"
+#include "dawn/native/stream/Stream.h"
+
+namespace dawn::native {
+
+template <>
+void stream::Stream<D3D12_RENDER_TARGET_BLEND_DESC>::Write(
+ stream::Sink* sink,
+ const D3D12_RENDER_TARGET_BLEND_DESC& t) {
+ StreamIn(sink, t.BlendEnable, t.LogicOpEnable, t.SrcBlend, t.DestBlend, t.BlendOp,
+ t.SrcBlendAlpha, t.DestBlendAlpha, t.BlendOpAlpha, t.LogicOp, t.RenderTargetWriteMask);
+}
+
+template <>
+void stream::Stream<D3D12_BLEND_DESC>::Write(stream::Sink* sink, const D3D12_BLEND_DESC& t) {
+ StreamIn(sink, t.AlphaToCoverageEnable, t.IndependentBlendEnable, t.RenderTarget);
+}
+
+template <>
+void stream::Stream<D3D12_DEPTH_STENCILOP_DESC>::Write(stream::Sink* sink,
+ const D3D12_DEPTH_STENCILOP_DESC& t) {
+ StreamIn(sink, t.StencilFailOp, t.StencilDepthFailOp, t.StencilPassOp, t.StencilFunc);
+}
+
+template <>
+void stream::Stream<D3D12_DEPTH_STENCIL_DESC>::Write(stream::Sink* sink,
+ const D3D12_DEPTH_STENCIL_DESC& t) {
+ StreamIn(sink, t.DepthEnable, t.DepthWriteMask, t.DepthFunc, t.StencilEnable, t.StencilReadMask,
+ t.StencilWriteMask, t.FrontFace, t.BackFace);
+}
+
+template <>
+void stream::Stream<D3D12_RASTERIZER_DESC>::Write(stream::Sink* sink,
+ const D3D12_RASTERIZER_DESC& t) {
+ StreamIn(sink, t.FillMode, t.CullMode, t.FrontCounterClockwise, t.DepthBias, t.DepthBiasClamp,
+ t.SlopeScaledDepthBias, t.DepthClipEnable, t.MultisampleEnable,
+ t.AntialiasedLineEnable, t.ForcedSampleCount, t.ConservativeRaster);
+}
+
+template <>
+void stream::Stream<D3D12_INPUT_ELEMENT_DESC>::Write(stream::Sink* sink,
+ const D3D12_INPUT_ELEMENT_DESC& t) {
+ StreamIn(sink, std::string_view(t.SemanticName), t.SemanticIndex, t.Format, t.InputSlot,
+ t.AlignedByteOffset, t.InputSlotClass, t.InstanceDataStepRate);
+}
+
+template <>
+void stream::Stream<D3D12_INPUT_LAYOUT_DESC>::Write(stream::Sink* sink,
+ const D3D12_INPUT_LAYOUT_DESC& t) {
+ StreamIn(sink, Iterable(t.pInputElementDescs, t.NumElements));
+}
+
+template <>
+void stream::Stream<D3D12_SO_DECLARATION_ENTRY>::Write(stream::Sink* sink,
+ const D3D12_SO_DECLARATION_ENTRY& t) {
+ StreamIn(sink, t.Stream, std::string_view(t.SemanticName), t.SemanticIndex, t.StartComponent,
+ t.ComponentCount, t.OutputSlot);
+}
+
+template <>
+void stream::Stream<D3D12_STREAM_OUTPUT_DESC>::Write(stream::Sink* sink,
+ const D3D12_STREAM_OUTPUT_DESC& t) {
+ StreamIn(sink, Iterable(t.pSODeclaration, t.NumEntries),
+ Iterable(t.pBufferStrides, t.NumStrides), t.RasterizedStream);
+}
+
+template <>
+void stream::Stream<DXGI_SAMPLE_DESC>::Write(stream::Sink* sink, const DXGI_SAMPLE_DESC& t) {
+ StreamIn(sink, t.Count, t.Quality);
+}
+
+template <>
+void stream::Stream<D3D12_SHADER_BYTECODE>::Write(stream::Sink* sink,
+ const D3D12_SHADER_BYTECODE& t) {
+ StreamIn(sink, Iterable(reinterpret_cast<const uint8_t*>(t.pShaderBytecode), t.BytecodeLength));
+}
+
+template <>
+void stream::Stream<D3D12_GRAPHICS_PIPELINE_STATE_DESC>::Write(
+ stream::Sink* sink,
+ const D3D12_GRAPHICS_PIPELINE_STATE_DESC& t) {
+ // Don't Serialize pRootSignature as we already serialize the signature blob in pipline layout.
+ // Don't Serialize CachedPSO as it is in the cached blob.
+ StreamIn(sink, t.VS, t.PS, t.DS, t.HS, t.GS, t.StreamOutput, t.BlendState, t.SampleMask,
+ t.RasterizerState, t.DepthStencilState, t.InputLayout, t.IBStripCutValue,
+ t.PrimitiveTopologyType, Iterable(t.RTVFormats, t.NumRenderTargets), t.DSVFormat,
+ t.SampleDesc, t.NodeMask, t.Flags);
+}
+
+template <>
+void stream::Stream<D3D12_COMPUTE_PIPELINE_STATE_DESC>::Write(
+ stream::Sink* sink,
+ const D3D12_COMPUTE_PIPELINE_STATE_DESC& t) {
+ // Don't Serialize pRootSignature as we already serialize the signature blob in pipline layout.
+ StreamIn(sink, t.CS, t.NodeMask, t.Flags);
+}
+
+template <>
+void stream::Stream<ID3DBlob>::Write(stream::Sink* sink, const ID3DBlob& t) {
+ // Workaround: GetBufferPointer and GetbufferSize are not marked as const
+ ID3DBlob* pBlob = const_cast<ID3DBlob*>(&t);
+ StreamIn(sink, Iterable(reinterpret_cast<uint8_t*>(pBlob->GetBufferPointer()),
+ pBlob->GetBufferSize()));
+}
+
+} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.cpp
index f3aeee0e34f..41bc0a099c6 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.cpp
@@ -176,9 +176,9 @@ DXGI_FORMAT D3D12TypelessTextureFormat(wgpu::TextureFormat format) {
case wgpu::TextureFormat::Depth24Plus:
return DXGI_FORMAT_R32_TYPELESS;
- // Depth24UnormStencil8 is the smallest format supported on D3D12 that has stencil.
+ // DXGI_FORMAT_D24_UNORM_S8_UINT is the smallest format supported on D3D12 that has stencil,
+ // for which the typeless equivalent is DXGI_FORMAT_R24G8_TYPELESS.
case wgpu::TextureFormat::Stencil8:
- case wgpu::TextureFormat::Depth24UnormStencil8:
return DXGI_FORMAT_R24G8_TYPELESS;
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
@@ -344,9 +344,8 @@ DXGI_FORMAT D3D12TextureFormat(wgpu::TextureFormat format) {
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24Plus:
return DXGI_FORMAT_D32_FLOAT;
- // Depth24UnormStencil8 is the smallest format supported on D3D12 that has stencil.
+ // DXGI_FORMAT_D24_UNORM_S8_UINT is the smallest format supported on D3D12 that has stencil.
case wgpu::TextureFormat::Stencil8:
- case wgpu::TextureFormat::Depth24UnormStencil8:
return DXGI_FORMAT_D24_UNORM_S8_UINT;
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
@@ -511,13 +510,17 @@ ResultOrError<Ref<Texture>> Texture::CreateExternalImage(
Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
+ ComPtr<ID3D12Fence> d3d12Fence,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
+ uint64_t fenceWaitValue,
+ uint64_t fenceSignalValue,
bool isSwapChainTexture,
bool isInitialized) {
Ref<Texture> dawnTexture =
AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal));
DAWN_TRY(dawnTexture->InitializeAsExternalTexture(
- descriptor, std::move(d3d12Texture), std::move(d3d11on12Resource), isSwapChainTexture));
+ std::move(d3d12Texture), std::move(d3d12Fence), std::move(d3d11on12Resource),
+ fenceWaitValue, fenceSignalValue, isSwapChainTexture));
// Importing a multi-planar format must be initialized. This is required because
// a shared multi-planar format cannot be initialized by Dawn.
@@ -541,13 +544,12 @@ ResultOrError<Ref<Texture>> Texture::Create(Device* device,
return std::move(dawnTexture);
}
-MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descriptor,
- ComPtr<ID3D12Resource> d3d12Texture,
+MaybeError Texture::InitializeAsExternalTexture(ComPtr<ID3D12Resource> d3d12Texture,
+ ComPtr<ID3D12Fence> d3d12Fence,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
+ uint64_t fenceWaitValue,
+ uint64_t fenceSignalValue,
bool isSwapChainTexture) {
- mD3D11on12Resource = std::move(d3d11on12Resource);
- mSwapChainTexture = isSwapChainTexture;
-
D3D12_RESOURCE_DESC desc = d3d12Texture->GetDesc();
mD3D12ResourceFlags = desc.Flags;
@@ -558,6 +560,12 @@ MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descrip
// memory management.
mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr};
+ mD3D12Fence = std::move(d3d12Fence);
+ mD3D11on12Resource = std::move(d3d11on12Resource);
+ mFenceWaitValue = fenceWaitValue;
+ mFenceSignalValue = fenceSignalValue;
+ mSwapChainTexture = isSwapChainTexture;
+
SetLabelHelper("Dawn_ExternalTexture");
return {};
@@ -573,10 +581,21 @@ MaybeError Texture::InitializeAsInternalTexture() {
resourceDescriptor.Height = size.height;
resourceDescriptor.DepthOrArraySize = size.depthOrArrayLayers;
+ Device* device = ToBackend(GetDevice());
+ bool applyForceClearCopyableDepthStencilTextureOnCreationToggle =
+ device->IsToggleEnabled(Toggle::D3D12ForceClearCopyableDepthStencilTextureOnCreation) &&
+ GetFormat().HasDepthOrStencil() && (GetInternalUsage() & wgpu::TextureUsage::CopyDst);
+ if (applyForceClearCopyableDepthStencilTextureOnCreationToggle) {
+ AddInternalUsage(wgpu::TextureUsage::RenderAttachment);
+ }
+
// This will need to be much more nuanced when WebGPU has
// texture view compatibility rules.
- const bool needsTypelessFormat = GetFormat().HasDepthOrStencil() &&
- (GetInternalUsage() & wgpu::TextureUsage::TextureBinding) != 0;
+ const bool needsTypelessFormat =
+ (GetDevice()->IsToggleEnabled(Toggle::D3D12AlwaysUseTypelessFormatsForCastableTexture) &&
+ GetViewFormats().any()) ||
+ (GetFormat().HasDepthOrStencil() &&
+ (GetInternalUsage() & wgpu::TextureUsage::TextureBinding) != 0);
DXGI_FORMAT dxgiFormat = needsTypelessFormat ? D3D12TypelessTextureFormat(GetFormat().format)
: D3D12TextureFormat(GetFormat().format);
@@ -590,13 +609,16 @@ MaybeError Texture::InitializeAsInternalTexture() {
mD3D12ResourceFlags = resourceDescriptor.Flags;
DAWN_TRY_ASSIGN(mResourceAllocation,
- ToBackend(GetDevice())
- ->AllocateMemory(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor,
- D3D12_RESOURCE_STATE_COMMON));
+ device->AllocateMemory(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor,
+ D3D12_RESOURCE_STATE_COMMON));
SetLabelImpl();
- Device* device = ToBackend(GetDevice());
+ if (applyForceClearCopyableDepthStencilTextureOnCreationToggle) {
+ CommandRecordingContext* commandContext;
+ DAWN_TRY_ASSIGN(commandContext, device->GetPendingCommandContext());
+ DAWN_TRY(ClearTexture(commandContext, GetAllSubresources(), TextureBase::ClearValue::Zero));
+ }
if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
CommandRecordingContext* commandContext;
@@ -657,9 +679,23 @@ void Texture::DestroyImpl() {
// ID3D12SharingContract::Present.
mSwapChainTexture = false;
- // Now that the texture has been destroyed. It should release the refptr
- // of the d3d11on12 resource.
+ // Signal the fence on destroy after all uses of the texture.
+ if (mD3D12Fence != nullptr && mFenceSignalValue != 0) {
+ // Enqueue a fence wait if we haven't already; otherwise the fence signal will be racy.
+ if (mFenceWaitValue != UINT64_MAX) {
+ device->ConsumedError(
+ CheckHRESULT(device->GetCommandQueue()->Wait(mD3D12Fence.Get(), mFenceWaitValue),
+ "D3D12 fence wait"));
+ }
+ device->ConsumedError(
+ CheckHRESULT(device->GetCommandQueue()->Signal(mD3D12Fence.Get(), mFenceSignalValue),
+ "D3D12 fence signal"));
+ }
+
+ // Now that the texture has been destroyed. It should release the refptr of the d3d11on12
+ // resource and the fence.
mD3D11on12Resource = nullptr;
+ mD3D12Fence = nullptr;
}
DXGI_FORMAT Texture::GetD3D12Format() const {
@@ -670,11 +706,14 @@ ID3D12Resource* Texture::GetD3D12Resource() const {
return mResourceAllocation.GetD3D12Resource();
}
+D3D12_RESOURCE_FLAGS Texture::GetD3D12ResourceFlags() const {
+ return mD3D12ResourceFlags;
+}
+
DXGI_FORMAT Texture::GetD3D12CopyableSubresourceFormat(Aspect aspect) const {
ASSERT(GetFormat().aspects & aspect);
switch (GetFormat().format) {
- case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
@@ -692,14 +731,27 @@ DXGI_FORMAT Texture::GetD3D12CopyableSubresourceFormat(Aspect aspect) const {
}
}
-MaybeError Texture::AcquireKeyedMutex() {
- ASSERT(mD3D11on12Resource != nullptr);
- return mD3D11on12Resource->AcquireKeyedMutex();
+MaybeError Texture::SynchronizeImportedTextureBeforeUse() {
+ if (mD3D11on12Resource != nullptr) {
+ DAWN_TRY(mD3D11on12Resource->AcquireKeyedMutex());
+ }
+ // Perform the wait only on the first call. We can use UINT64_MAX as a sentinel value since it's
+ // also used by the D3D runtime to indicate device removed according to:
+ // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12fence-getcompletedvalue#return-value
+ if (mD3D12Fence != nullptr && mFenceWaitValue != UINT64_MAX) {
+ DAWN_TRY(CheckHRESULT(
+ ToBackend(GetDevice())->GetCommandQueue()->Wait(mD3D12Fence.Get(), mFenceWaitValue),
+ "D3D12 fence wait"));
+ mFenceWaitValue = UINT64_MAX;
+ }
+ return {};
}
-void Texture::ReleaseKeyedMutex() {
- ASSERT(mD3D11on12Resource != nullptr);
- mD3D11on12Resource->ReleaseKeyedMutex();
+void Texture::SynchronizeImportedTextureAfterUse() {
+ if (mD3D11on12Resource != nullptr) {
+ mD3D11on12Resource->ReleaseKeyedMutex();
+ }
+ // Defer signaling the fence until destroy after all uses of the fence.
}
void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
@@ -798,7 +850,7 @@ void Texture::TransitionSubresourceRange(std::vector<D3D12_RESOURCE_BARRIER>* ba
// non-simultaneous-access texture: NON_PIXEL_SHADER_RESOURCE,
// PIXEL_SHADER_RESOURCE, COPY_SRC, COPY_DEST.
{
- static constexpr D3D12_RESOURCE_STATES kD3D12PromotableReadOnlyStates =
+ const D3D12_RESOURCE_STATES kD3D12PromotableReadOnlyStates =
D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
@@ -850,10 +902,10 @@ void Texture::TransitionSubresourceRange(std::vector<D3D12_RESOURCE_BARRIER>* ba
}
void Texture::HandleTransitionSpecialCases(CommandRecordingContext* commandContext) {
- // Textures with keyed mutexes can be written from other graphics queues. Hence, they
- // must be acquired before command list submission to ensure work from the other queues
- // has finished. See Device::ExecuteCommandContext.
- if (mD3D11on12Resource != nullptr) {
+ // Externally allocated textures can be written from other graphics queues. Hence, they must be
+ // acquired before command list submission to ensure work from the other queues has finished.
+ // See CommandRecordingContext::ExecuteCommandList.
+ if (mResourceAllocation.GetInfo().mMethod == AllocationMethod::kExternal) {
commandContext->AddToSharedTextureList(this);
}
}
@@ -1182,8 +1234,7 @@ TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* desc
case wgpu::TextureFormat::Depth16Unorm:
mSrvDesc.Format = DXGI_FORMAT_R16_UNORM;
break;
- case wgpu::TextureFormat::Stencil8:
- case wgpu::TextureFormat::Depth24UnormStencil8: {
+ case wgpu::TextureFormat::Stencil8: {
Aspect aspects = SelectFormatAspects(textureFormat, descriptor->aspect);
ASSERT(aspects != Aspect::None);
if (!HasZeroOrOneBits(aspects)) {
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.h b/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.h
index 05b80db12b4..3e49bc232b2 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/TextureD3D12.h
@@ -45,7 +45,10 @@ class Texture final : public TextureBase {
Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> d3d12Texture,
+ ComPtr<ID3D12Fence> d3d12Fence,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
+ uint64_t fenceWaitValue,
+ uint64_t fenceSignalValue,
bool isSwapChainTexture,
bool isInitialized);
static ResultOrError<Ref<Texture>> Create(Device* device,
@@ -55,6 +58,7 @@ class Texture final : public TextureBase {
DXGI_FORMAT GetD3D12Format() const;
ID3D12Resource* GetD3D12Resource() const;
DXGI_FORMAT GetD3D12CopyableSubresourceFormat(Aspect aspect) const;
+ D3D12_RESOURCE_FLAGS GetD3D12ResourceFlags() const;
D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(const Format& format,
uint32_t mipLevel,
@@ -70,8 +74,8 @@ class Texture final : public TextureBase {
void EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext,
const SubresourceRange& range);
- MaybeError AcquireKeyedMutex();
- void ReleaseKeyedMutex();
+ MaybeError SynchronizeImportedTextureBeforeUse();
+ void SynchronizeImportedTextureAfterUse();
void TrackUsageAndGetResourceBarrierForPass(CommandRecordingContext* commandContext,
std::vector<D3D12_RESOURCE_BARRIER>* barrier,
@@ -97,9 +101,11 @@ class Texture final : public TextureBase {
using TextureBase::TextureBase;
MaybeError InitializeAsInternalTexture();
- MaybeError InitializeAsExternalTexture(const TextureDescriptor* descriptor,
- ComPtr<ID3D12Resource> d3d12Texture,
+ MaybeError InitializeAsExternalTexture(ComPtr<ID3D12Resource> d3d12Texture,
+ ComPtr<ID3D12Fence> d3d12Fence,
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
+ uint64_t fenceWaitValue,
+ uint64_t fenceSignalValue,
bool isSwapChainTexture);
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
@@ -132,13 +138,17 @@ class Texture final : public TextureBase {
ExecutionSerial pendingCommandSerial) const;
void HandleTransitionSpecialCases(CommandRecordingContext* commandContext);
- SubresourceStorage<StateAndDecay> mSubresourceStateAndDecay;
-
- ResourceHeapAllocation mResourceAllocation;
- bool mSwapChainTexture = false;
D3D12_RESOURCE_FLAGS mD3D12ResourceFlags;
+ ResourceHeapAllocation mResourceAllocation;
+ // TODO(dawn:1460): Encapsulate imported image fields e.g. std::unique_ptr<ExternalImportInfo>.
+ ComPtr<ID3D12Fence> mD3D12Fence;
Ref<D3D11on12ResourceCacheEntry> mD3D11on12Resource;
+ uint64_t mFenceWaitValue = 0;
+ uint64_t mFenceSignalValue = 0;
+ bool mSwapChainTexture = false;
+
+ SubresourceStorage<StateAndDecay> mSubresourceStateAndDecay;
};
class TextureView final : public TextureViewBase {
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.cpp b/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.cpp
index 0e761f8f1cd..e706d8f6585 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.cpp
@@ -81,19 +81,19 @@ bool NeedBufferSizeWorkaroundForBufferTextureCopyOnD3D12(const BufferCopy& buffe
} // anonymous namespace
-ResultOrError<std::wstring> ConvertStringToWstring(const char* str) {
- size_t len = strlen(str);
+ResultOrError<std::wstring> ConvertStringToWstring(std::string_view s) {
+ size_t len = s.length();
if (len == 0) {
return std::wstring();
}
- int numChars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, len, nullptr, 0);
+ int numChars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), len, nullptr, 0);
if (numChars == 0) {
return DAWN_INTERNAL_ERROR("Failed to convert string to wide string");
}
std::wstring result;
result.resize(numChars);
int numConvertedChars =
- MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, len, &result[0], numChars);
+ MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), len, &result[0], numChars);
if (numConvertedChars != numChars) {
return DAWN_INTERNAL_ERROR("Failed to convert string to wide string");
}
diff --git a/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.h b/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.h
index 1418f545251..dcbe782cbe8 100644
--- a/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.h
+++ b/chromium/third_party/dawn/src/dawn/native/d3d12/UtilsD3D12.h
@@ -26,7 +26,7 @@
namespace dawn::native::d3d12 {
-ResultOrError<std::wstring> ConvertStringToWstring(const char* str);
+ResultOrError<std::wstring> ConvertStringToWstring(std::string_view s);
D3D12_COMPARISON_FUNC ToD3D12ComparisonFunc(wgpu::CompareFunction func);
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/BackendMTL.mm b/chromium/third_party/dawn/src/dawn/native/metal/BackendMTL.mm
index 4d5d8543548..fdd27bf223f 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/BackendMTL.mm
+++ b/chromium/third_party/dawn/src/dawn/native/metal/BackendMTL.mm
@@ -47,11 +47,10 @@ struct Vendor {
};
#if DAWN_PLATFORM_IS(MACOS)
-const Vendor kVendors[] = {{"AMD", gpu_info::kVendorID_AMD},
- {"Radeon", gpu_info::kVendorID_AMD},
- {"Intel", gpu_info::kVendorID_Intel},
- {"Geforce", gpu_info::kVendorID_Nvidia},
- {"Quadro", gpu_info::kVendorID_Nvidia}};
+const Vendor kVendors[] = {
+ {"AMD", gpu_info::kVendorID_AMD}, {"Apple", gpu_info::kVendorID_Apple},
+ {"Radeon", gpu_info::kVendorID_AMD}, {"Intel", gpu_info::kVendorID_Intel},
+ {"Geforce", gpu_info::kVendorID_Nvidia}, {"Quadro", gpu_info::kVendorID_Nvidia}};
// Find vendor ID from MTLDevice name.
MaybeError GetVendorIdFromVendors(id<MTLDevice> device, PCIIDs* ids) {
@@ -147,28 +146,26 @@ MaybeError GetDevicePCIInfo(id<MTLDevice> device, PCIIDs* ids) {
// [device registryID] is introduced on macOS 10.13+, otherwise workaround to get vendor
// id by vendor name on old macOS
if (@available(macos 10.13, *)) {
- return GetDeviceIORegistryPCIInfo(device, ids);
- } else {
- return GetVendorIdFromVendors(device, ids);
+ auto result = GetDeviceIORegistryPCIInfo(device, ids);
+ if (result.IsError()) {
+ dawn::WarningLog() << "GetDeviceIORegistryPCIInfo failed: "
+ << result.AcquireError()->GetFormattedMessage();
+ } else if (ids->vendorId != 0) {
+ return result;
+ }
}
-}
-bool IsMetalSupported() {
- // Metal was first introduced in macOS 10.11
- // WebGPU is targeted at macOS 10.12+
- // TODO(dawn:1181): Dawn native should allow non-conformant WebGPU on macOS 10.11
- return IsMacOSVersionAtLeast(10, 12);
+ return GetVendorIdFromVendors(device, ids);
}
+
#elif DAWN_PLATFORM_IS(IOS)
+
MaybeError GetDevicePCIInfo(id<MTLDevice> device, PCIIDs* ids) {
DAWN_UNUSED(device);
*ids = PCIIDs{0, 0};
return {};
}
-bool IsMetalSupported() {
- return true;
-}
#else
#error "Unsupported Apple platform."
#endif
@@ -366,7 +363,7 @@ class Adapter : public AdapterBase {
}
if (@available(macOS 10.11, iOS 11.0, *)) {
- mSupportedFeatures.EnableFeature(Feature::DepthClamping);
+ mSupportedFeatures.EnableFeature(Feature::DepthClipControl);
}
if (@available(macOS 10.11, iOS 9.0, *)) {
@@ -379,18 +376,38 @@ class Adapter : public AdapterBase {
mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats);
}
-#if DAWN_PLATFORM_IS(MACOS)
- // MTLPixelFormatDepth24Unorm_Stencil8 is only available on macOS 10.11+
- if ([*mDevice isDepth24Stencil8PixelFormatSupported]) {
- mSupportedFeatures.EnableFeature(Feature::Depth24UnormStencil8);
- }
-#endif
-
mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance);
return {};
}
+ void InitializeVendorArchitectureImpl() override {
+ if (@available(macOS 10.15, iOS 13.0, *)) {
+ // According to Apple's documentation:
+ // https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/detecting_gpu_features_and_metal_software_versions
+ // - "Use the Common family to create apps that target a range of GPUs on multiple
+ // platforms.""
+ // - "A GPU can be a member of more than one family; in most cases, a GPU supports one
+ // of the Common families and then one or more families specific to the build target."
+ // So we'll use the highest supported common family as the reported "architecture" on
+ // devices where a deviceID isn't available.
+ if (mDeviceId == 0) {
+ if ([*mDevice supportsFamily:MTLGPUFamilyCommon3]) {
+ mArchitectureName = "common-3";
+ } else if ([*mDevice supportsFamily:MTLGPUFamilyCommon2]) {
+ mArchitectureName = "common-2";
+ } else if ([*mDevice supportsFamily:MTLGPUFamilyCommon1]) {
+ mArchitectureName = "common-1";
+ }
+ }
+ }
+
+ mVendorName = gpu_info::GetVendorName(mVendorId);
+ if (mDeviceId != 0) {
+ mArchitectureName = gpu_info::GetArchitectureName(mVendorId, mDeviceId);
+ }
+ };
+
enum class MTLGPUFamily {
Apple1,
Apple2,
@@ -442,10 +459,8 @@ class Adapter : public AdapterBase {
return MTLGPUFamily::Mac2;
}
}
- if (@available(macOS 10.11, *)) {
- if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
- return MTLGPUFamily::Mac1;
- }
+ if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
+ return MTLGPUFamily::Mac1;
}
#elif TARGET_OS_IOS
if (@available(iOS 10.11, *)) {
@@ -486,6 +501,7 @@ class Adapter : public AdapterBase {
uint32_t max3DTextureSize;
uint32_t maxTextureArrayLayers;
uint32_t minBufferOffsetAlignment;
+ uint32_t maxColorRenderTargets;
};
struct LimitsForFamily {
@@ -497,7 +513,7 @@ class Adapter : public AdapterBase {
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
// Apple Mac
// 1, 2, 3, 4, 5, 6, 7, 1, 2
- constexpr LimitsForFamily kMTLLimits[12] = {
+ constexpr LimitsForFamily kMTLLimits[13] = {
{&MTLDeviceLimits::maxVertexAttribsPerDescriptor, { 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u }},
{&MTLDeviceLimits::maxBufferArgumentEntriesPerFunc, { 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u }},
{&MTLDeviceLimits::maxTextureArgumentEntriesPerFunc, { 31u, 31u, 31u, 96u, 96u, 128u, 128u, 128u, 128u }},
@@ -510,6 +526,7 @@ class Adapter : public AdapterBase {
{&MTLDeviceLimits::max3DTextureSize, { 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u }},
{&MTLDeviceLimits::maxTextureArrayLayers, { 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u }},
{&MTLDeviceLimits::minBufferOffsetAlignment, { 4u, 4u, 4u, 4u, 4u, 4u, 4u, 256u, 256u }},
+ {&MTLDeviceLimits::maxColorRenderTargets, { 4u, 8u, 8u, 8u, 8u, 8u, 8u, 8u, 8u }},
};
// clang-format on
@@ -527,6 +544,7 @@ class Adapter : public AdapterBase {
limits->v1.maxTextureDimension2D = mtlLimits.max2DTextureSize;
limits->v1.maxTextureDimension3D = mtlLimits.max3DTextureSize;
limits->v1.maxTextureArrayLayers = mtlLimits.maxTextureArrayLayers;
+ limits->v1.maxColorAttachments = mtlLimits.maxColorRenderTargets;
uint32_t maxBuffersPerStage = mtlLimits.maxBufferArgumentEntriesPerFunc;
maxBuffersPerStage -= 1; // One slot is reserved to store buffer lengths.
@@ -591,11 +609,14 @@ class Adapter : public AdapterBase {
limits->v1.maxUniformBufferBindingSize = maxBufferSize;
limits->v1.maxStorageBufferBindingSize = maxBufferSize;
+ // Using base limits for:
// TODO(crbug.com/dawn/685):
- // LIMITS NOT SET:
// - maxBindGroups
// - maxVertexBufferArrayStride
+ // TODO(crbug.com/dawn/1448):
+ // - maxInterStageShaderVariables
+
return {};
}
@@ -627,43 +648,30 @@ ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
ASSERT(optionsBase->backendType == WGPUBackendType_Metal);
std::vector<Ref<AdapterBase>> adapters;
- BOOL supportedVersion = NO;
#if DAWN_PLATFORM_IS(MACOS)
- if (@available(macOS 10.11, *)) {
- supportedVersion = YES;
-
- NSRef<NSArray<id<MTLDevice>>> devices = AcquireNSRef(MTLCopyAllDevices());
-
- for (id<MTLDevice> device in devices.Get()) {
- Ref<Adapter> adapter = AcquireRef(new Adapter(GetInstance(), device));
- if (!GetInstance()->ConsumedError(adapter->Initialize())) {
- adapters.push_back(std::move(adapter));
- }
- }
- }
-#endif
+ NSRef<NSArray<id<MTLDevice>>> devices = AcquireNSRef(MTLCopyAllDevices());
-#if DAWN_PLATFORM_IS(IOS)
- if (@available(iOS 8.0, *)) {
- supportedVersion = YES;
- // iOS only has a single device so MTLCopyAllDevices doesn't exist there.
- Ref<Adapter> adapter =
- AcquireRef(new Adapter(GetInstance(), MTLCreateSystemDefaultDevice()));
+ for (id<MTLDevice> device in devices.Get()) {
+ Ref<Adapter> adapter = AcquireRef(new Adapter(GetInstance(), device));
if (!GetInstance()->ConsumedError(adapter->Initialize())) {
adapters.push_back(std::move(adapter));
}
}
#endif
- if (!supportedVersion) {
- UNREACHABLE();
+
+ // iOS only has a single device so MTLCopyAllDevices doesn't exist there.
+#if defined(DAWN_PLATFORM_IOS)
+ Ref<Adapter> adapter =
+ AcquireRef(new Adapter(GetInstance(), MTLCreateSystemDefaultDevice()));
+ if (!GetInstance()->ConsumedError(adapter->Initialize())) {
+ adapters.push_back(std::move(adapter));
}
+#endif
+
return adapters;
}
BackendConnection* Connect(InstanceBase* instance) {
- if (!IsMetalSupported()) {
- return nullptr;
- }
return new Backend(instance);
}
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/CommandBufferMTL.mm b/chromium/third_party/dawn/src/dawn/native/metal/CommandBufferMTL.mm
index 04dab406994..66a4569277b 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/CommandBufferMTL.mm
+++ b/chromium/third_party/dawn/src/dawn/native/metal/CommandBufferMTL.mm
@@ -610,7 +610,12 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
- mCommands.NextCommand<BeginComputePassCmd>();
+ BeginComputePassCmd* cmd = mCommands.NextCommand<BeginComputePassCmd>();
+
+ if (cmd->beginTimestamp.querySet.Get() != nullptr ||
+ cmd->endTimestamp.querySet.Get() != nullptr) {
+ return DAWN_UNIMPLEMENTED_ERROR("timestampWrites unimplemented.");
+ }
for (const SyncScopeResourceUsage& scope :
GetResourceUsages().computePasses[nextComputePassNumber].dispatchUsages) {
@@ -627,6 +632,11 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
case Command::BeginRenderPass: {
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
+ if (cmd->beginTimestamp.querySet.Get() != nullptr ||
+ cmd->endTimestamp.querySet.Get() != nullptr) {
+ return DAWN_UNIMPLEMENTED_ERROR("timestampWrites unimplemented.");
+ }
+
LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber],
commandContext);
commandContext->EndBlit();
@@ -1242,7 +1252,7 @@ MaybeError CommandBuffer::EncodeRenderPass(id<MTLRenderCommandEncoder> encoder)
slopeScale:newPipeline->GetDepthBiasSlopeScale()
clamp:newPipeline->GetDepthBiasClamp()];
if (@available(macOS 10.11, iOS 11.0, *)) {
- MTLDepthClipMode clipMode = newPipeline->ShouldClampDepth()
+ MTLDepthClipMode clipMode = newPipeline->HasUnclippedDepth()
? MTLDepthClipModeClamp
: MTLDepthClipModeClip;
[encoder setDepthClipMode:clipMode];
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/DeviceMTL.mm b/chromium/third_party/dawn/src/dawn/native/metal/DeviceMTL.mm
index 0a7d4963b1c..4b589eab3ef 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/DeviceMTL.mm
+++ b/chromium/third_party/dawn/src/dawn/native/metal/DeviceMTL.mm
@@ -212,7 +212,7 @@ void Device::InitTogglesFromDriver() {
SetToggle(Toggle::MetalRenderR8RG8UnormSmallMipToTempTexture, true);
}
- // On some Intel GPU vertex only render pipeline get wrong depth result if no fragment
+ // On some Intel GPUs vertex only render pipeline get wrong depth result if no fragment
// shader provided. Create a placeholder fragment shader module to work around this issue.
if (gpu_info::IsIntel(vendorId)) {
bool usePlaceholderFragmentShader = true;
@@ -221,6 +221,14 @@ void Device::InitTogglesFromDriver() {
}
SetToggle(Toggle::UsePlaceholderFragmentInVertexOnlyPipeline, usePlaceholderFragmentShader);
}
+
+ // On some Intel GPUs using big integer values as clear values in render pass doesn't work
+ // correctly. Currently we have to add workaround for this issue by enabling the toggle
+ // "apply_clear_big_integer_color_value_with_draw". See https://crbug.com/dawn/1109 and
+ // https://crbug.com/dawn/1463 for more details.
+ if (gpu_info::IsIntel(vendorId)) {
+ SetToggle(Toggle::ApplyClearBigIntegerColorValueWithDraw, true);
+ }
}
ResultOrError<Ref<BindGroupBase>> Device::CreateBindGroupImpl(
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/MetalBackend.mm b/chromium/third_party/dawn/src/dawn/native/metal/MetalBackend.mm
index f6cbbdce74e..d4140205bbb 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/MetalBackend.mm
+++ b/chromium/third_party/dawn/src/dawn/native/metal/MetalBackend.mm
@@ -22,10 +22,6 @@
namespace dawn::native::metal {
-id<MTLDevice> GetMetalDevice(WGPUDevice device) {
- return ToBackend(FromAPI(device))->GetMTLDevice();
-}
-
AdapterDiscoveryOptions::AdapterDiscoveryOptions()
: AdapterDiscoveryOptionsBase(WGPUBackendType_Metal) {}
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.h b/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.h
index 035922384a1..27f1def213b 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.h
+++ b/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.h
@@ -55,15 +55,6 @@ class ShaderModule final : public ShaderModuleBase {
const RenderPipeline* renderPipeline = nullptr);
private:
- ResultOrError<std::string> TranslateToMSL(const char* entryPointName,
- SingleShaderStage stage,
- const PipelineLayout* layout,
- uint32_t sampleMask,
- const RenderPipeline* renderPipeline,
- std::string* remappedEntryPointName,
- bool* needsStorageBufferLength,
- bool* hasInvariantAttribute,
- std::vector<uint32_t>* workgroupAllocations);
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
~ShaderModule() override;
MaybeError Initialize(ShaderModuleParseResult* parseResult,
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.mm b/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.mm
index fa8befd2e5e..e56eb22d9bd 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.mm
+++ b/chromium/third_party/dawn/src/dawn/native/metal/ShaderModuleMTL.mm
@@ -15,10 +15,14 @@
#include "dawn/native/metal/ShaderModuleMTL.h"
#include "dawn/native/BindGroupLayout.h"
+#include "dawn/native/CacheRequest.h"
+#include "dawn/native/Serializable.h"
#include "dawn/native/TintUtils.h"
#include "dawn/native/metal/DeviceMTL.h"
#include "dawn/native/metal/PipelineLayoutMTL.h"
#include "dawn/native/metal/RenderPipelineMTL.h"
+#include "dawn/native/stream/BlobSource.h"
+#include "dawn/native/stream/ByteVectorSink.h"
#include "dawn/platform/DawnPlatform.h"
#include "dawn/platform/tracing/TraceEvent.h"
@@ -27,6 +31,42 @@
#include <sstream>
namespace dawn::native::metal {
+namespace {
+
+using OptionalVertexPullingTransformConfig = std::optional<tint::transform::VertexPulling::Config>;
+
+#define MSL_COMPILATION_REQUEST_MEMBERS(X) \
+ X(const tint::Program*, inputProgram) \
+ X(tint::transform::BindingRemapper::BindingPoints, bindingPoints) \
+ X(tint::transform::MultiplanarExternalTexture::BindingsMap, externalTextureBindings) \
+ X(OptionalVertexPullingTransformConfig, vertexPullingTransformConfig) \
+ X(std::string, entryPointName) \
+ X(uint32_t, sampleMask) \
+ X(bool, emitVertexPointSize) \
+ X(bool, isRobustnessEnabled) \
+ X(bool, disableSymbolRenaming) \
+ X(bool, disableWorkgroupInit) \
+ X(CacheKey::UnsafeUnkeyedValue<dawn::platform::Platform*>, tracePlatform)
+
+DAWN_MAKE_CACHE_REQUEST(MslCompilationRequest, MSL_COMPILATION_REQUEST_MEMBERS);
+#undef MSL_COMPILATION_REQUEST_MEMBERS
+
+using WorkgroupAllocations = std::vector<uint32_t>;
+
+#define MSL_COMPILATION_MEMBERS(X) \
+ X(std::string, msl) \
+ X(std::string, remappedEntryPointName) \
+ X(bool, needsStorageBufferLength) \
+ X(bool, hasInvariantAttribute) \
+ X(WorkgroupAllocations, workgroupAllocations)
+
+DAWN_SERIALIZABLE(struct, MslCompilation, MSL_COMPILATION_MEMBERS){};
+#undef MSL_COMPILATION_MEMBERS
+
+} // namespace
+} // namespace dawn::native::metal
+
+namespace dawn::native::metal {
// static
ResultOrError<Ref<ShaderModule>> ShaderModule::Create(
@@ -50,17 +90,16 @@ MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
return InitializeBase(parseResult, compilationMessages);
}
-ResultOrError<std::string> ShaderModule::TranslateToMSL(
- const char* entryPointName,
- SingleShaderStage stage,
- const PipelineLayout* layout,
- uint32_t sampleMask,
- const RenderPipeline* renderPipeline,
- std::string* remappedEntryPointName,
- bool* needsStorageBufferLength,
- bool* hasInvariantAttribute,
- std::vector<uint32_t>* workgroupAllocations) {
- ScopedTintICEHandler scopedICEHandler(GetDevice());
+namespace {
+
+ResultOrError<CacheResult<MslCompilation>> TranslateToMSL(DeviceBase* device,
+ const tint::Program* inputProgram,
+ const char* entryPointName,
+ SingleShaderStage stage,
+ const PipelineLayout* layout,
+ uint32_t sampleMask,
+ const RenderPipeline* renderPipeline) {
+ ScopedTintICEHandler scopedICEHandler(device);
std::ostringstream errorStream;
errorStream << "Tint MSL failure:" << std::endl;
@@ -69,7 +108,6 @@ ResultOrError<std::string> ShaderModule::TranslateToMSL(
using BindingRemapper = tint::transform::BindingRemapper;
using BindingPoint = tint::transform::BindingPoint;
BindingRemapper::BindingPoints bindingPoints;
- BindingRemapper::AccessControls accessControls;
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
const BindGroupLayoutBase::BindingMap& bindingMap =
@@ -93,21 +131,13 @@ ResultOrError<std::string> ShaderModule::TranslateToMSL(
}
}
- tint::transform::Manager transformManager;
- tint::transform::DataMap transformInputs;
-
- // We only remap bindings for the target entry point, so we need to strip all other entry
- // points to avoid generating invalid bindings for them.
- transformManager.Add<tint::transform::SingleEntryPoint>();
- transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
-
- AddExternalTextureTransform(layout, &transformManager, &transformInputs);
+ auto externalTextureBindings = BuildExternalTextureTransformBindings(layout);
+ std::optional<tint::transform::VertexPulling::Config> vertexPullingTransformConfig;
if (stage == SingleShaderStage::Vertex &&
- GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling)) {
- transformManager.Add<tint::transform::VertexPulling>();
- AddVertexPullingTransformConfig(*renderPipeline, entryPointName, kPullingBufferBindingSet,
- &transformInputs);
+ device->IsToggleEnabled(Toggle::MetalEnableVertexPulling)) {
+ vertexPullingTransformConfig = BuildVertexPullingTransformConfig(
+ *renderPipeline, entryPointName, kPullingBufferBindingSet);
for (VertexBufferSlot slot : IterateBitSet(renderPipeline->GetVertexBufferSlotsUsed())) {
uint32_t metalIndex = renderPipeline->GetMtlVertexBufferIndex(slot);
@@ -121,62 +151,127 @@ ResultOrError<std::string> ShaderModule::TranslateToMSL(
}
}
}
- if (GetDevice()->IsRobustnessEnabled()) {
- transformManager.Add<tint::transform::Robustness>();
- }
- transformManager.Add<tint::transform::BindingRemapper>();
- transformManager.Add<tint::transform::Renamer>();
- if (GetDevice()->IsToggleEnabled(Toggle::DisableSymbolRenaming)) {
- // We still need to rename MSL reserved keywords
- transformInputs.Add<tint::transform::Renamer::Config>(
- tint::transform::Renamer::Target::kMslKeywords);
- }
+ MslCompilationRequest req = {};
+ req.inputProgram = inputProgram;
+ req.bindingPoints = std::move(bindingPoints);
+ req.externalTextureBindings = std::move(externalTextureBindings);
+ req.vertexPullingTransformConfig = std::move(vertexPullingTransformConfig);
+ req.entryPointName = entryPointName;
+ req.sampleMask = sampleMask;
+ req.emitVertexPointSize =
+ stage == SingleShaderStage::Vertex &&
+ renderPipeline->GetPrimitiveTopology() == wgpu::PrimitiveTopology::PointList;
+ req.isRobustnessEnabled = device->IsRobustnessEnabled();
+ req.disableSymbolRenaming = device->IsToggleEnabled(Toggle::DisableSymbolRenaming);
+ req.tracePlatform = UnsafeUnkeyedValue(device->GetPlatform());
+
+ CacheResult<MslCompilation> mslCompilation;
+ DAWN_TRY_LOAD_OR_RUN(
+ mslCompilation, device, std::move(req), MslCompilation::FromBlob,
+ [](MslCompilationRequest r) -> ResultOrError<MslCompilation> {
+ tint::transform::Manager transformManager;
+ tint::transform::DataMap transformInputs;
+
+ // We only remap bindings for the target entry point, so we need to strip all other
+ // entry points to avoid generating invalid bindings for them.
+ transformManager.Add<tint::transform::SingleEntryPoint>();
+ transformInputs.Add<tint::transform::SingleEntryPoint::Config>(r.entryPointName);
+
+ if (!r.externalTextureBindings.empty()) {
+ transformManager.Add<tint::transform::MultiplanarExternalTexture>();
+ transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
+ std::move(r.externalTextureBindings));
+ }
- transformInputs.Add<BindingRemapper::Remappings>(std::move(bindingPoints),
- std::move(accessControls),
- /* mayCollide */ true);
+ if (r.vertexPullingTransformConfig) {
+ transformManager.Add<tint::transform::VertexPulling>();
+ transformInputs.Add<tint::transform::VertexPulling::Config>(
+ std::move(r.vertexPullingTransformConfig).value());
+ }
- tint::Program program;
- tint::transform::DataMap transformOutputs;
- {
- TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms");
- DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(), transformInputs,
- &transformOutputs, nullptr));
- }
+ if (r.isRobustnessEnabled) {
+ transformManager.Add<tint::transform::Robustness>();
+ }
+ transformManager.Add<BindingRemapper>();
+ transformInputs.Add<BindingRemapper::Remappings>(std::move(r.bindingPoints),
+ BindingRemapper::AccessControls{},
+ /* mayCollide */ true);
- if (auto* data = transformOutputs.Get<tint::transform::Renamer::Data>()) {
- auto it = data->remappings.find(entryPointName);
- if (it != data->remappings.end()) {
- *remappedEntryPointName = it->second;
- } else {
- DAWN_INVALID_IF(!GetDevice()->IsToggleEnabled(Toggle::DisableSymbolRenaming),
- "Could not find remapped name for entry point.");
+ transformManager.Add<tint::transform::Renamer>();
- *remappedEntryPointName = entryPointName;
- }
- } else {
- return DAWN_FORMAT_VALIDATION_ERROR("Transform output missing renamer data.");
- }
+ if (r.disableSymbolRenaming) {
+ // We still need to rename MSL reserved keywords
+ transformInputs.Add<tint::transform::Renamer::Config>(
+ tint::transform::Renamer::Target::kMslKeywords);
+ }
- tint::writer::msl::Options options;
- options.buffer_size_ubo_index = kBufferLengthBufferSlot;
- options.fixed_sample_mask = sampleMask;
- options.disable_workgroup_init = GetDevice()->IsToggleEnabled(Toggle::DisableWorkgroupInit);
- options.emit_vertex_point_size =
- stage == SingleShaderStage::Vertex &&
- renderPipeline->GetPrimitiveTopology() == wgpu::PrimitiveTopology::PointList;
- TRACE_EVENT0(GetDevice()->GetPlatform(), General, "tint::writer::msl::Generate");
- auto result = tint::writer::msl::Generate(&program, options);
- DAWN_INVALID_IF(!result.success, "An error occured while generating MSL: %s.", result.error);
+ tint::Program program;
+ tint::transform::DataMap transformOutputs;
+ {
+ TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "RunTransforms");
+ DAWN_TRY_ASSIGN(program,
+ RunTransforms(&transformManager, r.inputProgram, transformInputs,
+ &transformOutputs, nullptr));
+ }
- *needsStorageBufferLength = result.needs_storage_buffer_sizes;
- *hasInvariantAttribute = result.has_invariant_attribute;
- *workgroupAllocations = std::move(result.workgroup_allocations[*remappedEntryPointName]);
+ std::string remappedEntryPointName;
+ if (auto* data = transformOutputs.Get<tint::transform::Renamer::Data>()) {
+ auto it = data->remappings.find(r.entryPointName);
+ if (it != data->remappings.end()) {
+ remappedEntryPointName = it->second;
+ } else {
+ DAWN_INVALID_IF(!r.disableSymbolRenaming,
+ "Could not find remapped name for entry point.");
+
+ remappedEntryPointName = r.entryPointName;
+ }
+ } else {
+ return DAWN_FORMAT_VALIDATION_ERROR("Transform output missing renamer data.");
+ }
- return std::move(result.msl);
+ tint::writer::msl::Options options;
+ options.buffer_size_ubo_index = kBufferLengthBufferSlot;
+ options.fixed_sample_mask = r.sampleMask;
+ options.disable_workgroup_init = r.disableWorkgroupInit;
+ options.emit_vertex_point_size = r.emitVertexPointSize;
+ TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "tint::writer::msl::Generate");
+ auto result = tint::writer::msl::Generate(&program, options);
+ DAWN_INVALID_IF(!result.success, "An error occured while generating MSL: %s.",
+ result.error);
+
+ // Metal uses Clang to compile the shader as C++14. Disable everything in the -Wall
+ // category. -Wunused-variable in particular comes up a lot in generated code, and some
+ // (old?) Metal drivers accidentally treat it as a MTLLibraryErrorCompileError instead
+ // of a warning.
+ result.msl = R"(
+ #ifdef __clang__
+ #pragma clang diagnostic ignored "-Wall"
+ #endif
+ )" + result.msl;
+
+ auto workgroupAllocations =
+ std::move(result.workgroup_allocations[remappedEntryPointName]);
+ return MslCompilation{{
+ std::move(result.msl),
+ std::move(remappedEntryPointName),
+ result.needs_storage_buffer_sizes,
+ result.has_invariant_attribute,
+ std::move(workgroupAllocations),
+ }};
+ });
+
+ if (device->IsToggleEnabled(Toggle::DumpShaders)) {
+ std::ostringstream dumpedMsg;
+ dumpedMsg << "/* Dumped generated MSL */" << std::endl << mslCompilation->msl;
+ device->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
+ }
+
+ return mslCompilation;
}
+} // namespace
+
MaybeError ShaderModule::CreateFunction(const char* entryPointName,
SingleShaderStage stage,
const PipelineLayout* layout,
@@ -194,33 +289,17 @@ MaybeError ShaderModule::CreateFunction(const char* entryPointName,
ASSERT(renderPipeline != nullptr);
}
- std::string remappedEntryPointName;
- std::string msl;
- bool hasInvariantAttribute = false;
- DAWN_TRY_ASSIGN(msl, TranslateToMSL(entryPointName, stage, layout, sampleMask, renderPipeline,
- &remappedEntryPointName, &out->needsStorageBufferLength,
- &hasInvariantAttribute, &out->workgroupAllocations));
-
- // Metal uses Clang to compile the shader as C++14. Disable everything in the -Wall
- // category. -Wunused-variable in particular comes up a lot in generated code, and some
- // (old?) Metal drivers accidentally treat it as a MTLLibraryErrorCompileError instead
- // of a warning.
- msl = R"(
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wall"
-#endif
-)" + msl;
-
- if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
- std::ostringstream dumpedMsg;
- dumpedMsg << "/* Dumped generated MSL */" << std::endl << msl;
- GetDevice()->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
- }
+ CacheResult<MslCompilation> mslCompilation;
+ DAWN_TRY_ASSIGN(mslCompilation, TranslateToMSL(GetDevice(), GetTintProgram(), entryPointName,
+ stage, layout, sampleMask, renderPipeline));
+ out->needsStorageBufferLength = mslCompilation->needsStorageBufferLength;
+ out->workgroupAllocations = std::move(mslCompilation->workgroupAllocations);
- NSRef<NSString> mslSource = AcquireNSRef([[NSString alloc] initWithUTF8String:msl.c_str()]);
+ NSRef<NSString> mslSource =
+ AcquireNSRef([[NSString alloc] initWithUTF8String:mslCompilation->msl.c_str()]);
NSRef<MTLCompileOptions> compileOptions = AcquireNSRef([[MTLCompileOptions alloc] init]);
- if (hasInvariantAttribute) {
+ if (mslCompilation->hasInvariantAttribute) {
if (@available(macOS 11.0, iOS 13.0, *)) {
(*compileOptions).preserveInvariance = true;
}
@@ -243,8 +322,8 @@ MaybeError ShaderModule::CreateFunction(const char* entryPointName,
}
ASSERT(library != nil);
- NSRef<NSString> name =
- AcquireNSRef([[NSString alloc] initWithUTF8String:remappedEntryPointName.c_str()]);
+ NSRef<NSString> name = AcquireNSRef(
+ [[NSString alloc] initWithUTF8String:mslCompilation->remappedEntryPointName.c_str()]);
{
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "MTLLibrary::newFunctionWithName");
@@ -269,6 +348,10 @@ MaybeError ShaderModule::CreateFunction(const char* entryPointName,
}
}
+ if (BlobCache* cache = GetDevice()->GetBlobCache()) {
+ cache->EnsureStored(mslCompilation);
+ }
+
if (GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling) &&
GetEntryPoint(entryPointName).usedVertexInputs.any()) {
out->needsStorageBufferLength = true;
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/TextureMTL.mm b/chromium/third_party/dawn/src/dawn/native/metal/TextureMTL.mm
index 06e525b1f5d..a508b656bfc 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/TextureMTL.mm
+++ b/chromium/third_party/dawn/src/dawn/native/metal/TextureMTL.mm
@@ -318,9 +318,6 @@ MTLPixelFormat MetalPixelFormat(wgpu::TextureFormat format) {
return MTLPixelFormatStencil8;
#if DAWN_PLATFORM_IS(MACOS)
- case wgpu::TextureFormat::Depth24UnormStencil8:
- return MTLPixelFormatDepth24Unorm_Stencil8;
-
case wgpu::TextureFormat::BC1RGBAUnorm:
return MTLPixelFormatBC1_RGBA;
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
@@ -350,8 +347,6 @@ MTLPixelFormat MetalPixelFormat(wgpu::TextureFormat format) {
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
return MTLPixelFormatBC7_RGBAUnorm_sRGB;
#else
- case wgpu::TextureFormat::Depth24UnormStencil8:
-
case wgpu::TextureFormat::BC1RGBAUnorm:
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
case wgpu::TextureFormat::BC2RGBAUnorm:
@@ -1066,11 +1061,6 @@ MaybeError TextureView::Initialize(const TextureViewDescriptor* descriptor) {
if (textureFormat == MTLPixelFormatDepth32Float_Stencil8) {
viewFormat = MTLPixelFormatX32_Stencil8;
}
-#if DAWN_PLATFORM_IS(MACOS)
- else if (textureFormat == MTLPixelFormatDepth24Unorm_Stencil8) {
- viewFormat = MTLPixelFormatX24_Stencil8;
- }
-#endif
else {
UNREACHABLE();
}
diff --git a/chromium/third_party/dawn/src/dawn/native/metal/UtilsMetal.mm b/chromium/third_party/dawn/src/dawn/native/metal/UtilsMetal.mm
index 22d3681ab50..df122f3e3e2 100644
--- a/chromium/third_party/dawn/src/dawn/native/metal/UtilsMetal.mm
+++ b/chromium/third_party/dawn/src/dawn/native/metal/UtilsMetal.mm
@@ -332,7 +332,7 @@ MaybeError CreateMTLFunction(const ProgrammableStage& programmableStage,
ShaderModule* shaderModule = ToBackend(programmableStage.module.Get());
const char* shaderEntryPoint = programmableStage.entryPoint.c_str();
const auto& entryPointMetadata = programmableStage.module->GetEntryPoint(shaderEntryPoint);
- if (entryPointMetadata.overridableConstants.size() == 0) {
+ if (entryPointMetadata.overrides.size() == 0) {
DAWN_TRY(shaderModule->CreateFunction(shaderEntryPoint, singleShaderStage, pipelineLayout,
functionData, nil, sampleMask, renderPipeline));
return {};
@@ -345,29 +345,29 @@ MaybeError CreateMTLFunction(const ProgrammableStage& programmableStage,
std::unordered_set<std::string> overriddenConstants;
- auto switchType = [&](EntryPointMetadata::OverridableConstant::Type dawnType,
- MTLDataType* type, OverridableConstantScalar* entry,
+ auto switchType = [&](EntryPointMetadata::Override::Type dawnType,
+ MTLDataType* type, OverrideScalar* entry,
double value = 0) {
switch (dawnType) {
- case EntryPointMetadata::OverridableConstant::Type::Boolean:
+ case EntryPointMetadata::Override::Type::Boolean:
*type = MTLDataTypeBool;
if (entry) {
entry->b = static_cast<int32_t>(value);
}
break;
- case EntryPointMetadata::OverridableConstant::Type::Float32:
+ case EntryPointMetadata::Override::Type::Float32:
*type = MTLDataTypeFloat;
if (entry) {
entry->f32 = static_cast<float>(value);
}
break;
- case EntryPointMetadata::OverridableConstant::Type::Int32:
+ case EntryPointMetadata::Override::Type::Int32:
*type = MTLDataTypeInt;
if (entry) {
entry->i32 = static_cast<int32_t>(value);
}
break;
- case EntryPointMetadata::OverridableConstant::Type::Uint32:
+ case EntryPointMetadata::Override::Type::Uint32:
*type = MTLDataTypeUInt;
if (entry) {
entry->u32 = static_cast<uint32_t>(value);
@@ -382,10 +382,10 @@ MaybeError CreateMTLFunction(const ProgrammableStage& programmableStage,
overriddenConstants.insert(name);
// This is already validated so `name` must exist
- const auto& moduleConstant = entryPointMetadata.overridableConstants.at(name);
+ const auto& moduleConstant = entryPointMetadata.overrides.at(name);
MTLDataType type;
- OverridableConstantScalar entry{};
+ OverrideScalar entry{};
switchType(moduleConstant.type, &type, &entry, value);
@@ -394,14 +394,14 @@ MaybeError CreateMTLFunction(const ProgrammableStage& programmableStage,
// Set shader initialized default values because MSL function_constant
// has no default value
- for (const std::string& name : entryPointMetadata.initializedOverridableConstants) {
+ for (const std::string& name : entryPointMetadata.initializedOverrides) {
if (overriddenConstants.count(name) != 0) {
// This constant already has overridden value
continue;
}
// Must exist because it is validated
- const auto& moduleConstant = entryPointMetadata.overridableConstants.at(name);
+ const auto& moduleConstant = entryPointMetadata.overrides.at(name);
ASSERT(moduleConstant.isInitialized);
MTLDataType type;
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.cpp
index b3be547286f..7a4f3360781 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.cpp
@@ -14,11 +14,13 @@
#include "dawn/native/opengl/AdapterGL.h"
+#include <memory>
#include <string>
+#include <utility>
#include "dawn/common/GPUInfo.h"
-#include "dawn/common/Log.h"
#include "dawn/native/Instance.h"
+#include "dawn/native/opengl/ContextEGL.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
@@ -49,69 +51,6 @@ uint32_t GetVendorIdFromVendors(const char* vendor) {
return vendorId;
}
-void KHRONOS_APIENTRY OnGLDebugMessage(GLenum source,
- GLenum type,
- GLuint id,
- GLenum severity,
- GLsizei length,
- const GLchar* message,
- const void* userParam) {
- const char* sourceText;
- switch (source) {
- case GL_DEBUG_SOURCE_API:
- sourceText = "OpenGL";
- break;
- case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
- sourceText = "Window System";
- break;
- case GL_DEBUG_SOURCE_SHADER_COMPILER:
- sourceText = "Shader Compiler";
- break;
- case GL_DEBUG_SOURCE_THIRD_PARTY:
- sourceText = "Third Party";
- break;
- case GL_DEBUG_SOURCE_APPLICATION:
- sourceText = "Application";
- break;
- case GL_DEBUG_SOURCE_OTHER:
- sourceText = "Other";
- break;
- default:
- sourceText = "UNKNOWN";
- break;
- }
-
- const char* severityText;
- switch (severity) {
- case GL_DEBUG_SEVERITY_HIGH:
- severityText = "High";
- break;
- case GL_DEBUG_SEVERITY_MEDIUM:
- severityText = "Medium";
- break;
- case GL_DEBUG_SEVERITY_LOW:
- severityText = "Low";
- break;
- case GL_DEBUG_SEVERITY_NOTIFICATION:
- severityText = "Notification";
- break;
- default:
- severityText = "UNKNOWN";
- break;
- }
-
- if (type == GL_DEBUG_TYPE_ERROR) {
- dawn::WarningLog() << "OpenGL error:"
- << "\n Source: " << sourceText //
- << "\n ID: " << id //
- << "\n Severity: " << severityText //
- << "\n Message: " << message;
-
- // Abort on an error when in Debug mode.
- UNREACHABLE();
- }
-}
-
} // anonymous namespace
Adapter::Adapter(InstanceBase* instance, wgpu::BackendType backendType)
@@ -119,6 +58,7 @@ Adapter::Adapter(InstanceBase* instance, wgpu::BackendType backendType)
MaybeError Adapter::InitializeGLFunctions(void* (*getProc)(const char*)) {
// Use getProc to populate the dispatch table
+ mEGLFunctions.Init(getProc);
return mFunctions.Initialize(getProc);
}
@@ -134,47 +74,6 @@ MaybeError Adapter::InitializeImpl() {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGL);
}
- // Use the debug output functionality to get notified about GL errors
- // TODO(cwallez@chromium.org): add support for the KHR_debug and ARB_debug_output
- // extensions
- bool hasDebugOutput = mFunctions.IsAtLeastGL(4, 3) || mFunctions.IsAtLeastGLES(3, 2);
-
- if (GetInstance()->IsBackendValidationEnabled() && hasDebugOutput) {
- mFunctions.Enable(GL_DEBUG_OUTPUT);
- mFunctions.Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
-
- // Any GL error; dangerous undefined behavior; any shader compiler and linker errors
- mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0,
- nullptr, GL_TRUE);
-
- // Severe performance warnings; GLSL or other shader compiler and linker warnings;
- // use of currently deprecated behavior
- mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0,
- nullptr, GL_TRUE);
-
- // Performance warnings from redundant state changes; trivial undefined behavior
- // This is disabled because we do an incredible amount of redundant state changes.
- mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
- nullptr, GL_FALSE);
-
- // Any message which is not an error or performance concern
- mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION,
- 0, nullptr, GL_FALSE);
- mFunctions.DebugMessageCallback(&OnGLDebugMessage, nullptr);
- }
-
- // Set state that never changes between devices.
- mFunctions.Enable(GL_DEPTH_TEST);
- mFunctions.Enable(GL_SCISSOR_TEST);
- mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
- if (mFunctions.GetVersion().IsDesktop()) {
- // These are not necessary on GLES. The functionality is enabled by default, and
- // works by specifying sample counts and SRGB textures, respectively.
- mFunctions.Enable(GL_MULTISAMPLE);
- mFunctions.Enable(GL_FRAMEBUFFER_SRGB);
- }
- mFunctions.Enable(GL_SAMPLE_MASK);
-
mName = reinterpret_cast<const char*>(mFunctions.GetString(GL_RENDERER));
// Workaroud to find vendor id from vendor name
@@ -231,7 +130,6 @@ MaybeError Adapter::InitializeSupportedFeaturesImpl() {
supportsBPTC) {
mSupportedFeatures.EnableFeature(dawn::native::Feature::TextureCompressionBC);
}
- mSupportedFeatures.EnableFeature(Feature::Depth24UnormStencil8);
}
// Non-zero baseInstance requires at least desktop OpenGL 4.2, and it is not supported in
@@ -252,9 +150,11 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
}
ResultOrError<Ref<DeviceBase>> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
- // There is no limit on the number of devices created from this adapter because they can
- // all share the same backing OpenGL context.
- return Device::Create(this, descriptor, mFunctions);
+ EGLenum api =
+ GetBackendType() == wgpu::BackendType::OpenGL ? EGL_OPENGL_API : EGL_OPENGL_ES_API;
+ std::unique_ptr<Device::Context> context;
+ DAWN_TRY_ASSIGN(context, ContextEGL::Create(mEGLFunctions, api));
+ return Device::Create(this, descriptor, mFunctions, std::move(context));
}
} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.h b/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.h
index 41018872d76..6e354b2d030 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.h
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/AdapterGL.h
@@ -16,6 +16,7 @@
#define SRC_DAWN_NATIVE_OPENGL_ADAPTERGL_H_
#include "dawn/native/Adapter.h"
+#include "dawn/native/opengl/EGLFunctions.h"
#include "dawn/native/opengl/OpenGLFunctions.h"
namespace dawn::native::opengl {
@@ -38,6 +39,7 @@ class Adapter : public AdapterBase {
ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
OpenGLFunctions mFunctions;
+ EGLFunctions mEGLFunctions;
};
} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.cpp
index c4b877667a6..ac4e374e0d8 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.cpp
@@ -14,10 +14,17 @@
#include "dawn/native/opengl/BackendGL.h"
+#include <EGL/egl.h>
+
+#include <memory>
#include <utility>
+#include "dawn/common/SystemUtils.h"
+#include "dawn/native/Instance.h"
#include "dawn/native/OpenGLBackend.h"
#include "dawn/native/opengl/AdapterGL.h"
+#include "dawn/native/opengl/ContextEGL.h"
+#include "dawn/native/opengl/EGLFunctions.h"
namespace dawn::native::opengl {
@@ -27,8 +34,53 @@ Backend::Backend(InstanceBase* instance, wgpu::BackendType backendType)
: BackendConnection(instance, backendType) {}
std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
- // The OpenGL backend needs at least "getProcAddress" to discover an adapter.
- return {};
+ std::vector<Ref<AdapterBase>> adapters;
+#if DAWN_PLATFORM_IS(WINDOWS)
+ const char* eglLib = "libEGL.dll";
+#elif DAWN_PLATFORM_IS(MACOS)
+ const char* eglLib = "libEGL.dylib";
+#else
+ const char* eglLib = "libEGL.so";
+#endif
+ if (!mLibEGL.Valid() && !mLibEGL.Open(eglLib)) {
+ return {};
+ }
+
+ AdapterDiscoveryOptions options(ToAPI(GetType()));
+ options.getProc =
+ reinterpret_cast<void* (*)(const char*)>(mLibEGL.GetProc("eglGetProcAddress"));
+ if (!options.getProc) {
+ return {};
+ }
+
+ EGLFunctions egl;
+ egl.Init(options.getProc);
+
+ EGLenum api = GetType() == wgpu::BackendType::OpenGLES ? EGL_OPENGL_ES_API : EGL_OPENGL_API;
+ std::unique_ptr<ContextEGL> context;
+ if (GetInstance()->ConsumedError(ContextEGL::Create(egl, api), &context)) {
+ return {};
+ }
+
+ EGLDisplay prevDisplay = egl.GetCurrentDisplay();
+ EGLContext prevDrawSurface = egl.GetCurrentSurface(EGL_DRAW);
+ EGLContext prevReadSurface = egl.GetCurrentSurface(EGL_READ);
+ EGLContext prevContext = egl.GetCurrentContext();
+
+ context->MakeCurrent();
+
+ auto result = DiscoverAdapters(&options);
+
+ if (result.IsError()) {
+ GetInstance()->ConsumedError(result.AcquireError());
+ } else {
+ auto value = result.AcquireSuccess();
+ adapters.insert(adapters.end(), value.begin(), value.end());
+ }
+
+ egl.MakeCurrent(prevDisplay, prevDrawSurface, prevReadSurface, prevContext);
+
+ return adapters;
}
ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.h b/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.h
index 591672809e2..dc8fea5d6c0 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.h
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/BackendGL.h
@@ -17,6 +17,7 @@
#include <vector>
+#include "dawn/common/DynamicLib.h"
#include "dawn/native/BackendConnection.h"
namespace dawn::native::opengl {
@@ -31,6 +32,7 @@ class Backend : public BackendConnection {
private:
bool mCreatedAdapter = false;
+ DynamicLib mLibEGL;
};
} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/BufferGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/BufferGL.cpp
index c05730bbdd3..5fce54f6dde 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/BufferGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/BufferGL.cpp
@@ -39,21 +39,22 @@ ResultOrError<Ref<Buffer>> Buffer::CreateInternalBuffer(Device* device,
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
: BufferBase(device, descriptor) {
+ const OpenGLFunctions& gl = device->GetGL();
// Allocate at least 4 bytes so clamped accesses are always in bounds.
mAllocatedSize = std::max(GetSize(), uint64_t(4u));
- device->gl.GenBuffers(1, &mBuffer);
- device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
+ gl.GenBuffers(1, &mBuffer);
+ gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
// The buffers with mappedAtCreation == true will be initialized in
// BufferBase::MapAtCreation().
if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting) &&
!descriptor->mappedAtCreation) {
std::vector<uint8_t> clearValues(mAllocatedSize, 1u);
- device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, clearValues.data(), GL_STATIC_DRAW);
+ gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, clearValues.data(), GL_STATIC_DRAW);
} else {
// Buffers start zeroed if you pass nullptr to glBufferData.
- device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, nullptr, GL_STATIC_DRAW);
+ gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, nullptr, GL_STATIC_DRAW);
}
}
@@ -112,10 +113,11 @@ void Buffer::InitializeToZero() {
const uint64_t size = GetAllocatedSize();
Device* device = ToBackend(GetDevice());
+ const OpenGLFunctions& gl = device->GetGL();
const std::vector<uint8_t> clearValues(size, 0u);
- device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
- device->gl.BufferSubData(GL_ARRAY_BUFFER, 0, size, clearValues.data());
+ gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
+ gl.BufferSubData(GL_ARRAY_BUFFER, 0, size, clearValues.data());
device->IncrementLazyClearCountForTesting();
SetIsDataInitialized();
@@ -128,14 +130,14 @@ bool Buffer::IsCPUWritableAtCreation() const {
}
MaybeError Buffer::MapAtCreationImpl() {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
mMappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, 0, GetSize(), GL_MAP_WRITE_BIT);
return {};
}
MaybeError Buffer::MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
// It is an error to map an empty range in OpenGL. We always have at least a 4-byte buffer
// so we extend the range to be 4 bytes.
@@ -171,7 +173,7 @@ void* Buffer::GetMappedPointerImpl() {
}
void Buffer::UnmapImpl() {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
gl.UnmapBuffer(GL_ARRAY_BUFFER);
@@ -179,8 +181,10 @@ void Buffer::UnmapImpl() {
}
void Buffer::DestroyImpl() {
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
+
BufferBase::DestroyImpl();
- ToBackend(GetDevice())->gl.DeleteBuffers(1, &mBuffer);
+ gl.DeleteBuffers(1, &mBuffer);
mBuffer = 0;
}
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/CommandBufferGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/CommandBufferGL.cpp
index 851413dffef..f0ea75b6417 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/CommandBufferGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/CommandBufferGL.cpp
@@ -448,7 +448,7 @@ CommandBuffer::CommandBuffer(CommandEncoder* encoder, const CommandBufferDescrip
: CommandBufferBase(encoder, descriptor) {}
MaybeError CommandBuffer::Execute() {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
auto LazyClearSyncScope = [](const SyncScopeResourceUsage& scope) {
for (size_t i = 0; i < scope.textures.size(); i++) {
@@ -767,7 +767,7 @@ MaybeError CommandBuffer::Execute() {
}
MaybeError CommandBuffer::ExecuteComputePass() {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
ComputePipeline* lastPipeline = nullptr;
BindGroupTracker bindGroupTracker = {};
@@ -844,7 +844,7 @@ MaybeError CommandBuffer::ExecuteComputePass() {
}
MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
GLuint fbo = 0;
// Create the framebuffer used for this render pass and calls the correct glDrawBuffers
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/ComputePipelineGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/ComputePipelineGL.cpp
index 35d2abda2f1..08a7c89dde5 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/ComputePipelineGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/ComputePipelineGL.cpp
@@ -29,16 +29,17 @@ ComputePipeline::~ComputePipeline() = default;
void ComputePipeline::DestroyImpl() {
ComputePipelineBase::DestroyImpl();
- DeleteProgram(ToBackend(GetDevice())->gl);
+ DeleteProgram(ToBackend(GetDevice())->GetGL());
}
MaybeError ComputePipeline::Initialize() {
- DAWN_TRY(InitializeBase(ToBackend(GetDevice())->gl, ToBackend(GetLayout()), GetAllStages()));
+ DAWN_TRY(
+ InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages()));
return {};
}
void ComputePipeline::ApplyNow() {
- PipelineGL::ApplyNow(ToBackend(GetDevice())->gl);
+ PipelineGL::ApplyNow(ToBackend(GetDevice())->GetGL());
}
} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.cpp
new file mode 100644
index 00000000000..b2618a32c84
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.cpp
@@ -0,0 +1,81 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/native/opengl/ContextEGL.h"
+
+#include <memory>
+#include <vector>
+
+#include "dawn/native/opengl/UtilsEGL.h"
+
+namespace dawn::native::opengl {
+
+ResultOrError<std::unique_ptr<ContextEGL>> ContextEGL::Create(const EGLFunctions& egl,
+ EGLenum api) {
+ EGLDisplay display = egl.GetCurrentDisplay();
+
+ if (display == EGL_NO_DISPLAY) {
+ display = egl.GetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+
+ DAWN_INVALID_IF(display == EGL_NO_DISPLAY, "eglGetDisplay");
+
+ EGLint renderableType = api == EGL_OPENGL_ES_API ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_BIT;
+
+ EGLint major, minor;
+
+ DAWN_TRY(CheckEGL(egl, egl.Initialize(display, &major, &minor), "eglInitialize"));
+
+ // We use EGLImage unconditionally, which only became core in 1.5.
+ DAWN_INVALID_IF(major < 1 || (major == 1 && minor < 5),
+ "EGL version (%u.%u) must be at least 1.5", major, minor);
+
+ // Since we're creating a surfaceless context, the only thing we really care
+ // about is the RENDERABLE_TYPE.
+ EGLint config_attribs[] = {EGL_RENDERABLE_TYPE, renderableType, EGL_NONE};
+
+ EGLint num_config;
+ EGLConfig config;
+ DAWN_TRY(CheckEGL(egl, egl.ChooseConfig(display, config_attribs, &config, 1, &num_config),
+ "eglChooseConfig"));
+
+ DAWN_INVALID_IF(num_config == 0, "eglChooseConfig returned zero configs");
+
+ DAWN_TRY(CheckEGL(egl, egl.BindAPI(api), "eglBindAPI"));
+
+ if (api == EGL_OPENGL_ES_API) {
+ major = 3;
+ minor = 1;
+ } else {
+ major = 4;
+ minor = 4;
+ }
+ EGLint attrib_list[] = {
+ EGL_CONTEXT_MAJOR_VERSION, major, EGL_CONTEXT_MINOR_VERSION, minor, EGL_NONE, EGL_NONE,
+ };
+ EGLContext context = egl.CreateContext(display, config, EGL_NO_CONTEXT, attrib_list);
+ DAWN_TRY(CheckEGL(egl, context != EGL_NO_CONTEXT, "eglCreateContext"));
+
+ return std::unique_ptr<ContextEGL>(new ContextEGL(egl, display, context));
+}
+
+void ContextEGL::MakeCurrent() {
+ egl.MakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mContext);
+}
+
+ContextEGL::~ContextEGL() {
+ egl.DestroyContext(mDisplay, mContext);
+}
+
+} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.h b/chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.h
new file mode 100644
index 00000000000..99fe5993ddc
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/ContextEGL.h
@@ -0,0 +1,45 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_OPENGL_CONTEXTEGL_H_
+#define SRC_DAWN_NATIVE_OPENGL_CONTEXTEGL_H_
+
+#include <EGL/egl.h>
+
+#include <memory>
+
+#include "dawn/native/opengl/DeviceGL.h"
+#include "dawn/native/opengl/EGLFunctions.h"
+
+namespace dawn::native::opengl {
+
+class ContextEGL : public Device::Context {
+ public:
+ static ResultOrError<std::unique_ptr<ContextEGL>> Create(const EGLFunctions& functions,
+ EGLenum api);
+ void MakeCurrent() override;
+ ~ContextEGL() override;
+
+ private:
+ ContextEGL(const EGLFunctions& functions, EGLDisplay display, EGLContext context)
+ : egl(functions), mDisplay(display), mContext(context) {}
+
+ const EGLFunctions egl;
+ EGLDisplay mDisplay;
+ EGLContext mContext;
+};
+
+} // namespace dawn::native::opengl
+
+#endif // SRC_DAWN_NATIVE_OPENGL_CONTEXTEGL_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.cpp
index 274cc1aed53..35ff4efd731 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.cpp
@@ -14,9 +14,12 @@
#include "dawn/native/opengl/DeviceGL.h"
+#include "dawn/common/Log.h"
+
#include "dawn/native/BackendConnection.h"
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/ErrorData.h"
+#include "dawn/native/Instance.h"
#include "dawn/native/StagingBuffer.h"
#include "dawn/native/opengl/BindGroupGL.h"
#include "dawn/native/opengl/BindGroupLayoutGL.h"
@@ -32,34 +35,146 @@
#include "dawn/native/opengl/SwapChainGL.h"
#include "dawn/native/opengl/TextureGL.h"
+namespace {
+
+void KHRONOS_APIENTRY OnGLDebugMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ const void* userParam) {
+ const char* sourceText;
+ switch (source) {
+ case GL_DEBUG_SOURCE_API:
+ sourceText = "OpenGL";
+ break;
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
+ sourceText = "Window System";
+ break;
+ case GL_DEBUG_SOURCE_SHADER_COMPILER:
+ sourceText = "Shader Compiler";
+ break;
+ case GL_DEBUG_SOURCE_THIRD_PARTY:
+ sourceText = "Third Party";
+ break;
+ case GL_DEBUG_SOURCE_APPLICATION:
+ sourceText = "Application";
+ break;
+ case GL_DEBUG_SOURCE_OTHER:
+ sourceText = "Other";
+ break;
+ default:
+ sourceText = "UNKNOWN";
+ break;
+ }
+
+ const char* severityText;
+ switch (severity) {
+ case GL_DEBUG_SEVERITY_HIGH:
+ severityText = "High";
+ break;
+ case GL_DEBUG_SEVERITY_MEDIUM:
+ severityText = "Medium";
+ break;
+ case GL_DEBUG_SEVERITY_LOW:
+ severityText = "Low";
+ break;
+ case GL_DEBUG_SEVERITY_NOTIFICATION:
+ severityText = "Notification";
+ break;
+ default:
+ severityText = "UNKNOWN";
+ break;
+ }
+
+ if (type == GL_DEBUG_TYPE_ERROR) {
+ dawn::WarningLog() << "OpenGL error:"
+ << "\n Source: " << sourceText //
+ << "\n ID: " << id //
+ << "\n Severity: " << severityText //
+ << "\n Message: " << message;
+
+ // Abort on an error when in Debug mode.
+ UNREACHABLE();
+ }
+}
+
+} // anonymous namespace
+
namespace dawn::native::opengl {
// static
ResultOrError<Ref<Device>> Device::Create(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
- const OpenGLFunctions& functions) {
- Ref<Device> device = AcquireRef(new Device(adapter, descriptor, functions));
+ const OpenGLFunctions& functions,
+ std::unique_ptr<Context> context) {
+ Ref<Device> device = AcquireRef(new Device(adapter, descriptor, functions, std::move(context)));
DAWN_TRY(device->Initialize(descriptor));
return device;
}
Device::Device(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
- const OpenGLFunctions& functions)
- : DeviceBase(adapter, descriptor), gl(functions) {}
+ const OpenGLFunctions& functions,
+ std::unique_ptr<Context> context)
+ : DeviceBase(adapter, descriptor), mGL(functions), mContext(std::move(context)) {}
Device::~Device() {
Destroy();
}
MaybeError Device::Initialize(const DeviceDescriptor* descriptor) {
+ const OpenGLFunctions& gl = GetGL();
InitTogglesFromDriver();
mFormatTable = BuildGLFormatTable(GetBGRAInternalFormat());
+ // Use the debug output functionality to get notified about GL errors
+ // TODO(crbug.com/dawn/1475): add support for the KHR_debug and ARB_debug_output
+ // extensions
+ bool hasDebugOutput = gl.IsAtLeastGL(4, 3) || gl.IsAtLeastGLES(3, 2);
+
+ if (GetAdapter()->GetInstance()->IsBackendValidationEnabled() && hasDebugOutput) {
+ gl.Enable(GL_DEBUG_OUTPUT);
+ gl.Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+
+ // Any GL error; dangerous undefined behavior; any shader compiler and linker errors
+ gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr,
+ GL_TRUE);
+
+ // Severe performance warnings; GLSL or other shader compiler and linker warnings;
+ // use of currently deprecated behavior
+ gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr,
+ GL_TRUE);
+
+ // Performance warnings from redundant state changes; trivial undefined behavior
+ // This is disabled because we do an incredible amount of redundant state changes.
+ gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, nullptr,
+ GL_FALSE);
+
+ // Any message which is not an error or performance concern
+ gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0,
+ nullptr, GL_FALSE);
+ gl.DebugMessageCallback(&OnGLDebugMessage, nullptr);
+ }
+
+ // Set initial state.
+ gl.Enable(GL_DEPTH_TEST);
+ gl.Enable(GL_SCISSOR_TEST);
+ gl.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
+ if (gl.GetVersion().IsDesktop()) {
+ // These are not necessary on GLES. The functionality is enabled by default, and
+ // works by specifying sample counts and SRGB textures, respectively.
+ gl.Enable(GL_MULTISAMPLE);
+ gl.Enable(GL_FRAMEBUFFER_SRGB);
+ }
+ gl.Enable(GL_SAMPLE_MASK);
+
return DeviceBase::Initialize(AcquireRef(new Queue(this, &descriptor->defaultQueue)));
}
void Device::InitTogglesFromDriver() {
+ const OpenGLFunctions& gl = GetGL();
bool supportsBaseVertex = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(3, 2);
bool supportsBaseInstance = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(4, 2);
@@ -124,6 +239,7 @@ const GLFormat& Device::GetGLFormat(const Format& format) {
}
GLenum Device::GetBGRAInternalFormat() const {
+ const OpenGLFunctions& gl = GetGL();
if (gl.IsGLExtensionSupported("GL_EXT_texture_format_BGRA8888") ||
gl.IsGLExtensionSupported("GL_APPLE_texture_format_BGRA8888")) {
return GL_BGRA8_EXT;
@@ -195,6 +311,7 @@ ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
}
void Device::SubmitFenceSync() {
+ const OpenGLFunctions& gl = GetGL();
GLsync sync = gl.FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
IncrementLastSubmittedCommandSerial();
mFencesInFlight.emplace(sync, GetLastSubmittedCommandSerial());
@@ -224,6 +341,7 @@ MaybeError Device::ValidateEGLImageCanBeWrapped(const TextureDescriptor* descrip
}
TextureBase* Device::CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
::EGLImage image) {
+ const OpenGLFunctions& gl = GetGL();
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
@@ -264,6 +382,7 @@ MaybeError Device::TickImpl() {
ResultOrError<ExecutionSerial> Device::CheckAndUpdateCompletedSerials() {
ExecutionSerial fenceSerial{0};
+ const OpenGLFunctions& gl = GetGL();
while (!mFencesInFlight.empty()) {
auto [sync, tentativeSerial] = mFencesInFlight.front();
@@ -314,6 +433,7 @@ void Device::DestroyImpl() {
}
MaybeError Device::WaitForIdleForDestruction() {
+ const OpenGLFunctions& gl = GetGL();
gl.Finish();
DAWN_TRY(CheckPassedSerials());
ASSERT(mFencesInFlight.empty());
@@ -333,4 +453,11 @@ float Device::GetTimestampPeriodInNS() const {
return 1.0f;
}
+const OpenGLFunctions& Device::GetGL() const {
+ if (mContext) {
+ mContext->MakeCurrent();
+ }
+ return mGL;
+}
+
} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.h b/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.h
index d9158952022..78abf1147a0 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.h
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/DeviceGL.h
@@ -39,15 +39,18 @@ namespace dawn::native::opengl {
class Device final : public DeviceBase {
public:
+ class Context;
static ResultOrError<Ref<Device>> Create(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
- const OpenGLFunctions& functions);
+ const OpenGLFunctions& functions,
+ std::unique_ptr<Context> context);
~Device() override;
MaybeError Initialize(const DeviceDescriptor* descriptor);
- // Contains all the OpenGL entry points, glDoFoo is called via device->gl.DoFoo.
- const OpenGLFunctions gl;
+ // Returns all the OpenGL entry points and ensures that the associated
+ // Context is current.
+ const OpenGLFunctions& GetGL() const;
const GLFormat& GetGLFormat(const Format& format);
@@ -80,10 +83,17 @@ class Device final : public DeviceBase {
float GetTimestampPeriodInNS() const override;
+ class Context {
+ public:
+ virtual ~Context() {}
+ virtual void MakeCurrent() = 0;
+ };
+
private:
Device(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
- const OpenGLFunctions& functions);
+ const OpenGLFunctions& functions,
+ std::unique_ptr<Context> context);
ResultOrError<Ref<BindGroupBase>> CreateBindGroupImpl(
const BindGroupDescriptor* descriptor) override;
@@ -121,9 +131,12 @@ class Device final : public DeviceBase {
void DestroyImpl() override;
MaybeError WaitForIdleForDestruction() override;
+ const OpenGLFunctions mGL;
+
std::queue<std::pair<GLsync, ExecutionSerial>> mFencesInFlight;
GLFormatTable mFormatTable;
+ std::unique_ptr<Context> mContext = nullptr;
};
} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.cpp
new file mode 100644
index 00000000000..5796131d420
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.cpp
@@ -0,0 +1,43 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/native/opengl/EGLFunctions.h"
+
+namespace dawn::native::opengl {
+
+void EGLFunctions::Init(void* (*getProc)(const char*)) {
+ GetProcAddress = reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(getProc);
+ BindAPI = reinterpret_cast<PFNEGLBINDAPIPROC>(GetProcAddress("eglBindAPI"));
+ ChooseConfig = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(GetProcAddress("eglChooseConfig"));
+ CreateContext = reinterpret_cast<PFNEGLCREATECONTEXTPROC>(GetProcAddress("eglCreateContext"));
+ CreatePbufferSurface =
+ reinterpret_cast<PFNEGLCREATEPBUFFERSURFACEPROC>(GetProcAddress("eglCreatePbufferSurface"));
+ CreatePlatformWindowSurface = reinterpret_cast<PFNEGLCREATEPLATFORMWINDOWSURFACEPROC>(
+ GetProcAddress("eglCreatePlatformWindowSurface"));
+ DestroyContext =
+ reinterpret_cast<PFNEGLDESTROYCONTEXTPROC>(GetProcAddress("eglDestroyContext"));
+ GetConfigs = reinterpret_cast<PFNEGLGETCONFIGSPROC>(GetProcAddress("eglGetConfigs"));
+ GetCurrentContext =
+ reinterpret_cast<PFNEGLGETCURRENTCONTEXTPROC>(GetProcAddress("eglGetCurrentContext"));
+ GetCurrentDisplay =
+ reinterpret_cast<PFNEGLGETCURRENTDISPLAYPROC>(GetProcAddress("eglGetCurrentDisplay"));
+ GetCurrentSurface =
+ reinterpret_cast<PFNEGLGETCURRENTSURFACEPROC>(GetProcAddress("eglGetCurrentSurface"));
+ GetDisplay = reinterpret_cast<PFNEGLGETDISPLAYPROC>(GetProcAddress("eglGetDisplay"));
+ GetError = reinterpret_cast<PFNEGLGETERRORPROC>(GetProcAddress("eglGetError"));
+ Initialize = reinterpret_cast<PFNEGLINITIALIZEPROC>(GetProcAddress("eglInitialize"));
+ MakeCurrent = reinterpret_cast<PFNEGLMAKECURRENTPROC>(GetProcAddress("eglMakeCurrent"));
+}
+
+} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.h b/chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.h
new file mode 100644
index 00000000000..5c2688fb66e
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/EGLFunctions.h
@@ -0,0 +1,43 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_OPENGL_EGLFUNCTIONS_H_
+#define SRC_DAWN_NATIVE_OPENGL_EGLFUNCTIONS_H_
+
+#include <EGL/egl.h>
+
+namespace dawn::native::opengl {
+
+struct EGLFunctions {
+ void Init(void* (*getProc)(const char*));
+ PFNEGLBINDAPIPROC BindAPI;
+ PFNEGLCHOOSECONFIGPROC ChooseConfig;
+ PFNEGLCREATECONTEXTPROC CreateContext;
+ PFNEGLCREATEPLATFORMWINDOWSURFACEPROC CreatePlatformWindowSurface;
+ PFNEGLCREATEPBUFFERSURFACEPROC CreatePbufferSurface;
+ PFNEGLDESTROYCONTEXTPROC DestroyContext;
+ PFNEGLGETCONFIGSPROC GetConfigs;
+ PFNEGLGETCURRENTCONTEXTPROC GetCurrentContext;
+ PFNEGLGETCURRENTDISPLAYPROC GetCurrentDisplay;
+ PFNEGLGETCURRENTSURFACEPROC GetCurrentSurface;
+ PFNEGLGETDISPLAYPROC GetDisplay;
+ PFNEGLGETERRORPROC GetError;
+ PFNEGLGETPROCADDRESSPROC GetProcAddress;
+ PFNEGLINITIALIZEPROC Initialize;
+ PFNEGLMAKECURRENTPROC MakeCurrent;
+};
+
+} // namespace dawn::native::opengl
+
+#endif // SRC_DAWN_NATIVE_OPENGL_EGLFUNCTIONS_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/GLFormat.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/GLFormat.cpp
index 6fbca797284..529cc35adde 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/GLFormat.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/GLFormat.cpp
@@ -92,7 +92,6 @@ GLFormatTable BuildGLFormatTable(GLenum internalFormatForBGRA) {
// Depth stencil formats
AddFormat(wgpu::TextureFormat::Depth32Float, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth24Plus, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, Type::DepthStencil);
- AddFormat(wgpu::TextureFormat::Depth24UnormStencil8, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth24PlusStencil8, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth16Unorm, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Stencil8, GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE, Type::DepthStencil);
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/NativeSwapChainImplGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/NativeSwapChainImplGL.cpp
index 409acf1ed7c..05e377a0767 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/NativeSwapChainImplGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/NativeSwapChainImplGL.cpp
@@ -24,13 +24,13 @@ NativeSwapChainImpl::NativeSwapChainImpl(Device* device,
: mPresentCallback(present), mPresentUserdata(presentUserdata), mDevice(device) {}
NativeSwapChainImpl::~NativeSwapChainImpl() {
- const OpenGLFunctions& gl = mDevice->gl;
+ const OpenGLFunctions& gl = mDevice->GetGL();
gl.DeleteTextures(1, &mBackTexture);
gl.DeleteFramebuffers(1, &mBackFBO);
}
void NativeSwapChainImpl::Init(DawnWSIContextGL* /*context*/) {
- const OpenGLFunctions& gl = mDevice->gl;
+ const OpenGLFunctions& gl = mDevice->GetGL();
gl.GenTextures(1, &mBackTexture);
gl.BindTexture(GL_TEXTURE_2D, mBackTexture);
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
@@ -53,7 +53,7 @@ DawnSwapChainError NativeSwapChainImpl::Configure(WGPUTextureFormat format,
mWidth = width;
mHeight = height;
- const OpenGLFunctions& gl = mDevice->gl;
+ const OpenGLFunctions& gl = mDevice->GetGL();
gl.BindTexture(GL_TEXTURE_2D, mBackTexture);
// Reallocate the texture
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
@@ -67,7 +67,7 @@ DawnSwapChainError NativeSwapChainImpl::GetNextTexture(DawnSwapChainNextTexture*
}
DawnSwapChainError NativeSwapChainImpl::Present() {
- const OpenGLFunctions& gl = mDevice->gl;
+ const OpenGLFunctions& gl = mDevice->GetGL();
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.Scissor(0, 0, mWidth, mHeight);
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLBackend.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLBackend.cpp
index c77c1d0f794..87cd37f7658 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLBackend.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLBackend.cpp
@@ -23,11 +23,11 @@
namespace dawn::native::opengl {
-AdapterDiscoveryOptions::AdapterDiscoveryOptions()
- : AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGL) {}
+AdapterDiscoveryOptions::AdapterDiscoveryOptions(WGPUBackendType type)
+ : AdapterDiscoveryOptionsBase(type) {}
AdapterDiscoveryOptionsES::AdapterDiscoveryOptionsES()
- : AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGLES) {}
+ : AdapterDiscoveryOptions(WGPUBackendType_OpenGLES) {}
DawnSwapChainImplementation CreateNativeSwapChainImpl(WGPUDevice device,
PresentCallback present,
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.cpp
index 297b5fb7b60..80857064bd6 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.cpp
@@ -26,9 +26,9 @@ MaybeError OpenGLVersion::Initialize(GetProcAddress getProc) {
return DAWN_INTERNAL_ERROR("Couldn't load glGetString");
}
- std::string version = reinterpret_cast<const char*>(getString(GL_VERSION));
+ const char* version = reinterpret_cast<const char*>(getString(GL_VERSION));
- if (version.find("OpenGL ES") != std::string::npos) {
+ if (strstr(version, "OpenGL ES") != nullptr) {
// ES spec states that the GL_VERSION string will be in the following format:
// "OpenGL ES N.M vendor-specific information"
mStandard = Standard::ES;
@@ -36,7 +36,7 @@ MaybeError OpenGLVersion::Initialize(GetProcAddress getProc) {
mMinorVersion = version[12] - '0';
// The minor version shouldn't get to two digits.
- ASSERT(version.size() <= 13 || !isdigit(version[13]));
+ ASSERT(strlen(version) <= 13 || !isdigit(version[13]));
} else {
// OpenGL spec states the GL_VERSION string will be in the following format:
// <version number><space><vendor-specific information>
@@ -48,7 +48,7 @@ MaybeError OpenGLVersion::Initialize(GetProcAddress getProc) {
mMinorVersion = version[2] - '0';
// The minor version shouldn't get to two digits.
- ASSERT(version.size() <= 3 || !isdigit(version[3]));
+ ASSERT(strlen(version) <= 3 || !isdigit(version[3]));
}
return {};
@@ -62,6 +62,10 @@ bool OpenGLVersion::IsES() const {
return mStandard == Standard::ES;
}
+OpenGLVersion::Standard OpenGLVersion::GetStandard() const {
+ return mStandard;
+}
+
uint32_t OpenGLVersion::GetMajor() const {
return mMajorVersion;
}
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.h b/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.h
index a9a296fb1fe..5f490abc99f 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.h
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/OpenGLVersion.h
@@ -21,19 +21,21 @@ namespace dawn::native::opengl {
struct OpenGLVersion {
public:
+ enum class Standard {
+ Desktop,
+ ES,
+ };
+
MaybeError Initialize(GetProcAddress getProc);
bool IsDesktop() const;
bool IsES() const;
+ Standard GetStandard() const;
uint32_t GetMajor() const;
uint32_t GetMinor() const;
bool IsAtLeast(uint32_t majorVersion, uint32_t minorVersion) const;
private:
- enum class Standard {
- Desktop,
- ES,
- };
uint32_t mMajorVersion;
uint32_t mMinorVersion;
Standard mStandard;
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/PipelineGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/PipelineGL.cpp
index 2ddabce6654..701102c6bcc 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/PipelineGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/PipelineGL.cpp
@@ -30,22 +30,6 @@
namespace dawn::native::opengl {
-namespace {
-
-GLenum GLShaderType(SingleShaderStage stage) {
- switch (stage) {
- case SingleShaderStage::Vertex:
- return GL_VERTEX_SHADER;
- case SingleShaderStage::Fragment:
- return GL_FRAGMENT_SHADER;
- case SingleShaderStage::Compute:
- return GL_COMPUTE_SHADER;
- }
- UNREACHABLE();
-}
-
-} // namespace
-
PipelineGL::PipelineGL() : mProgram(0) {}
PipelineGL::~PipelineGL() = default;
@@ -53,28 +37,6 @@ PipelineGL::~PipelineGL() = default;
MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
const PipelineLayout* layout,
const PerStage<ProgrammableStage>& stages) {
- auto CreateShader = [](const OpenGLFunctions& gl, GLenum type,
- const char* source) -> ResultOrError<GLuint> {
- GLuint shader = gl.CreateShader(type);
- gl.ShaderSource(shader, 1, &source, nullptr);
- gl.CompileShader(shader);
-
- GLint compileStatus = GL_FALSE;
- gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
- if (compileStatus == GL_FALSE) {
- GLint infoLogLength = 0;
- gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
-
- if (infoLogLength > 1) {
- std::vector<char> buffer(infoLogLength);
- gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
- return DAWN_FORMAT_VALIDATION_ERROR("%s\nProgram compilation failed:\n%s", source,
- buffer.data());
- }
- }
- return shader;
- };
-
mProgram = gl.CreateProgram();
// Compute the set of active stages.
@@ -91,12 +53,10 @@ MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
std::vector<GLuint> glShaders;
for (SingleShaderStage stage : IterateStages(activeStages)) {
const ShaderModule* module = ToBackend(stages[stage].module.Get());
- std::string glsl;
- DAWN_TRY_ASSIGN(glsl, module->TranslateToGLSL(stages[stage].entryPoint.c_str(), stage,
- &combinedSamplers[stage], layout,
- &needsPlaceholderSampler));
GLuint shader;
- DAWN_TRY_ASSIGN(shader, CreateShader(gl, GLShaderType(stage), glsl.c_str()));
+ DAWN_TRY_ASSIGN(shader,
+ module->CompileShader(gl, stages[stage], stage, &combinedSamplers[stage],
+ layout, &needsPlaceholderSampler));
gl.AttachShader(mProgram, shader);
glShaders.push_back(shader);
}
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/QueueGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/QueueGL.cpp
index 68eb918ba7c..38fec619a01 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/QueueGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/QueueGL.cpp
@@ -42,7 +42,7 @@ MaybeError Queue::WriteBufferImpl(BufferBase* buffer,
uint64_t bufferOffset,
const void* data,
size_t size) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
ToBackend(buffer)->EnsureDataInitializedAsDestination(bufferOffset, size);
@@ -70,7 +70,7 @@ MaybeError Queue::WriteTextureImpl(const ImageCopyTexture& destination,
} else {
ToBackend(destination.texture)->EnsureSubresourceContentInitialized(range);
}
- DoTexSubImage(ToBackend(GetDevice())->gl, textureCopy, data, dataLayout, writeSizePixel);
+ DoTexSubImage(ToBackend(GetDevice())->GetGL(), textureCopy, data, dataLayout, writeSizePixel);
ToBackend(destination.texture)->Touch();
return {};
}
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/RenderPipelineGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/RenderPipelineGL.cpp
index 54b6ffba668..59927297fa5 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/RenderPipelineGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/RenderPipelineGL.cpp
@@ -226,7 +226,8 @@ RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* d
mGlPrimitiveTopology(GLPrimitiveTopology(GetPrimitiveTopology())) {}
MaybeError RenderPipeline::Initialize() {
- DAWN_TRY(InitializeBase(ToBackend(GetDevice())->gl, ToBackend(GetLayout()), GetAllStages()));
+ DAWN_TRY(
+ InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages()));
CreateVAOForVertexState();
return {};
}
@@ -235,7 +236,7 @@ RenderPipeline::~RenderPipeline() = default;
void RenderPipeline::DestroyImpl() {
RenderPipelineBase::DestroyImpl();
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
gl.DeleteVertexArrays(1, &mVertexArrayObject);
gl.BindVertexArray(0);
DeleteProgram(gl);
@@ -252,7 +253,7 @@ RenderPipeline::GetAttributesUsingVertexBuffer(VertexBufferSlot slot) const {
}
void RenderPipeline::CreateVAOForVertexState() {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
gl.GenVertexArrays(1, &mVertexArrayObject);
gl.BindVertexArray(mVertexArrayObject);
@@ -284,7 +285,7 @@ void RenderPipeline::CreateVAOForVertexState() {
}
void RenderPipeline::ApplyNow(PersistentPipelineState& persistentPipelineState) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
PipelineGL::ApplyNow(gl);
ASSERT(mVertexArrayObject);
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/SamplerGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/SamplerGL.cpp
index b40e1d6592f..2f8c59b9480 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/SamplerGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/SamplerGL.cpp
@@ -67,7 +67,7 @@ GLenum WrapMode(wgpu::AddressMode mode) {
Sampler::Sampler(Device* device, const SamplerDescriptor* descriptor)
: SamplerBase(device, descriptor) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
gl.GenSamplers(1, &mFilteringHandle);
SetupGLSampler(mFilteringHandle, descriptor, false);
@@ -80,7 +80,7 @@ Sampler::~Sampler() = default;
void Sampler::DestroyImpl() {
SamplerBase::DestroyImpl();
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
gl.DeleteSamplers(1, &mFilteringHandle);
gl.DeleteSamplers(1, &mNonFilteringHandle);
}
@@ -89,7 +89,7 @@ void Sampler::SetupGLSampler(GLuint sampler,
const SamplerDescriptor* descriptor,
bool forceNearest) {
Device* device = ToBackend(GetDevice());
- const OpenGLFunctions& gl = device->gl;
+ const OpenGLFunctions& gl = device->GetGL();
if (forceNearest) {
gl.SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.cpp
index 253600b6c35..3ad4cc25ff3 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -18,14 +18,67 @@
#include <utility>
#include "dawn/native/BindGroupLayout.h"
+#include "dawn/native/CacheRequest.h"
+#include "dawn/native/Pipeline.h"
#include "dawn/native/TintUtils.h"
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/PipelineLayoutGL.h"
+#include "dawn/native/stream/BlobSource.h"
+#include "dawn/native/stream/ByteVectorSink.h"
#include "dawn/platform/DawnPlatform.h"
#include "dawn/platform/tracing/TraceEvent.h"
#include "tint/tint.h"
+namespace dawn::native {
+namespace {
+
+GLenum GLShaderType(SingleShaderStage stage) {
+ switch (stage) {
+ case SingleShaderStage::Vertex:
+ return GL_VERTEX_SHADER;
+ case SingleShaderStage::Fragment:
+ return GL_FRAGMENT_SHADER;
+ case SingleShaderStage::Compute:
+ return GL_COMPUTE_SHADER;
+ }
+ UNREACHABLE();
+}
+
+tint::writer::glsl::Version::Standard ToTintGLStandard(opengl::OpenGLVersion::Standard standard) {
+ switch (standard) {
+ case opengl::OpenGLVersion::Standard::Desktop:
+ return tint::writer::glsl::Version::Standard::kDesktop;
+ case opengl::OpenGLVersion::Standard::ES:
+ return tint::writer::glsl::Version::Standard::kES;
+ }
+}
+
+using BindingMap = std::unordered_map<tint::sem::BindingPoint, tint::sem::BindingPoint>;
+
+#define GLSL_COMPILATION_REQUEST_MEMBERS(X) \
+ X(const tint::Program*, inputProgram) \
+ X(std::string, entryPointName) \
+ X(tint::transform::MultiplanarExternalTexture::BindingsMap, externalTextureBindings) \
+ X(BindingMap, glBindings) \
+ X(opengl::OpenGLVersion::Standard, glVersionStandard) \
+ X(uint32_t, glVersionMajor) \
+ X(uint32_t, glVersionMinor)
+
+DAWN_MAKE_CACHE_REQUEST(GLSLCompilationRequest, GLSL_COMPILATION_REQUEST_MEMBERS);
+#undef GLSL_COMPILATION_REQUEST_MEMBERS
+
+#define GLSL_COMPILATION_MEMBERS(X) \
+ X(std::string, glsl) \
+ X(bool, needsPlaceholderSampler) \
+ X(opengl::CombinedSamplerInfo, combinedSamplerInfo)
+
+DAWN_SERIALIZABLE(struct, GLSLCompilation, GLSL_COMPILATION_MEMBERS){};
+#undef GLSL_COMPILATION_MEMBERS
+
+} // namespace
+} // namespace dawn::native
+
namespace dawn::native::opengl {
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber) {
@@ -81,99 +134,146 @@ MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
return {};
}
-ResultOrError<std::string> ShaderModule::TranslateToGLSL(const char* entryPointName,
- SingleShaderStage stage,
- CombinedSamplerInfo* combinedSamplers,
- const PipelineLayout* layout,
- bool* needsPlaceholderSampler) const {
+ResultOrError<GLuint> ShaderModule::CompileShader(const OpenGLFunctions& gl,
+ const ProgrammableStage& programmableStage,
+ SingleShaderStage stage,
+ CombinedSamplerInfo* combinedSamplers,
+ const PipelineLayout* layout,
+ bool* needsPlaceholderSampler) const {
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL");
- tint::transform::Manager transformManager;
- tint::transform::DataMap transformInputs;
-
- AddExternalTextureTransform(layout, &transformManager, &transformInputs);
-
- tint::Program program;
- DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(), transformInputs,
- nullptr, nullptr));
- const OpenGLVersion& version = ToBackend(GetDevice())->gl.GetVersion();
- tint::writer::glsl::Options tintOptions;
- using Version = tint::writer::glsl::Version;
- tintOptions.version =
- Version(version.IsDesktop() ? Version::Standard::kDesktop : Version::Standard::kES,
- version.GetMajor(), version.GetMinor());
+ const OpenGLVersion& version = ToBackend(GetDevice())->GetGL().GetVersion();
using tint::transform::BindingPoint;
- // When textures are accessed without a sampler (e.g., textureLoad()),
- // GetSamplerTextureUses() will return this sentinel value.
- BindingPoint placeholderBindingPoint{static_cast<uint32_t>(kMaxBindGroupsTyped), 0};
-
- tint::inspector::Inspector inspector(&program);
- // Find all the sampler/texture pairs for this entry point, and create
- // CombinedSamplers for them. CombinedSampler records the binding points
- // of the original texture and sampler, and generates a unique name. The
- // corresponding uniforms will be retrieved by these generated names
- // in PipelineGL. Any texture-only references will have
- // "usePlaceholderSampler" set to true, and only the texture binding point
- // will be used in naming them. In addition, Dawn will bind a
- // non-filtering sampler for them (see PipelineGL).
- auto uses = inspector.GetSamplerTextureUses(entryPointName, placeholderBindingPoint);
- for (const auto& use : uses) {
- combinedSamplers->emplace_back();
-
- CombinedSampler* info = &combinedSamplers->back();
- if (use.sampler_binding_point == placeholderBindingPoint) {
- info->usePlaceholderSampler = true;
- *needsPlaceholderSampler = true;
- } else {
- info->usePlaceholderSampler = false;
- }
- info->samplerLocation.group = BindGroupIndex(use.sampler_binding_point.group);
- info->samplerLocation.binding = BindingNumber(use.sampler_binding_point.binding);
- info->textureLocation.group = BindGroupIndex(use.texture_binding_point.group);
- info->textureLocation.binding = BindingNumber(use.texture_binding_point.binding);
- tintOptions.binding_map[use] = info->GetName();
- }
- if (*needsPlaceholderSampler) {
- tintOptions.placeholder_binding_point = placeholderBindingPoint;
- }
-
// Since (non-Vulkan) GLSL does not support descriptor sets, generate a
// mapping from the original group/binding pair to a binding-only
// value. This mapping will be used by Tint to remap all global
// variables to the 1D space.
+ const BindingInfoArray& moduleBindingInfo =
+ GetEntryPoint(programmableStage.entryPoint).bindings;
+ std::unordered_map<tint::sem::BindingPoint, tint::sem::BindingPoint> glBindings;
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
- const BindGroupLayoutBase::BindingMap& bindingMap =
- layout->GetBindGroupLayout(group)->GetBindingMap();
- for (const auto& it : bindingMap) {
- BindingNumber bindingNumber = it.first;
- BindingIndex bindingIndex = it.second;
- const BindingInfo& bindingInfo =
- layout->GetBindGroupLayout(group)->GetBindingInfo(bindingIndex);
- if (!(bindingInfo.visibility & StageBit(stage))) {
- continue;
- }
-
- uint32_t shaderIndex = layout->GetBindingIndexInfo()[group][bindingIndex];
+ const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(group);
+ const auto& groupBindingInfo = moduleBindingInfo[group];
+ for (const auto& [bindingNumber, bindingInfo] : groupBindingInfo) {
+ BindingIndex bindingIndex = bgl->GetBindingIndex(bindingNumber);
+ GLuint shaderIndex = layout->GetBindingIndexInfo()[group][bindingIndex];
BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
static_cast<uint32_t>(bindingNumber)};
BindingPoint dstBindingPoint{0, shaderIndex};
- tintOptions.binding_points.emplace(srcBindingPoint, dstBindingPoint);
+ if (srcBindingPoint != dstBindingPoint) {
+ glBindings.emplace(srcBindingPoint, dstBindingPoint);
+ }
}
- tintOptions.allow_collisions = true;
}
- auto result = tint::writer::glsl::Generate(&program, tintOptions, entryPointName);
- DAWN_INVALID_IF(!result.success, "An error occured while generating GLSL: %s.", result.error);
- std::string glsl = std::move(result.glsl);
+
+ GLSLCompilationRequest req = {};
+ req.inputProgram = GetTintProgram();
+ req.entryPointName = programmableStage.entryPoint;
+ req.externalTextureBindings = BuildExternalTextureTransformBindings(layout);
+ req.glBindings = std::move(glBindings);
+ req.glVersionStandard = version.GetStandard();
+ req.glVersionMajor = version.GetMajor();
+ req.glVersionMinor = version.GetMinor();
+
+ CacheResult<GLSLCompilation> compilationResult;
+ DAWN_TRY_LOAD_OR_RUN(
+ compilationResult, GetDevice(), std::move(req), GLSLCompilation::FromBlob,
+ [](GLSLCompilationRequest r) -> ResultOrError<GLSLCompilation> {
+ tint::transform::Manager transformManager;
+ tint::transform::DataMap transformInputs;
+
+ if (!r.externalTextureBindings.empty()) {
+ transformManager.Add<tint::transform::MultiplanarExternalTexture>();
+ transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
+ std::move(r.externalTextureBindings));
+ }
+
+ tint::Program program;
+ DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, r.inputProgram,
+ transformInputs, nullptr, nullptr));
+
+ tint::writer::glsl::Options tintOptions;
+ tintOptions.version = tint::writer::glsl::Version(ToTintGLStandard(r.glVersionStandard),
+ r.glVersionMajor, r.glVersionMinor);
+
+ // When textures are accessed without a sampler (e.g., textureLoad()),
+ // GetSamplerTextureUses() will return this sentinel value.
+ BindingPoint placeholderBindingPoint{static_cast<uint32_t>(kMaxBindGroupsTyped), 0};
+
+ bool needsPlaceholderSampler = false;
+ tint::inspector::Inspector inspector(&program);
+ // Find all the sampler/texture pairs for this entry point, and create
+ // CombinedSamplers for them. CombinedSampler records the binding points
+ // of the original texture and sampler, and generates a unique name. The
+ // corresponding uniforms will be retrieved by these generated names
+ // in PipelineGL. Any texture-only references will have
+ // "usePlaceholderSampler" set to true, and only the texture binding point
+ // will be used in naming them. In addition, Dawn will bind a
+ // non-filtering sampler for them (see PipelineGL).
+ auto uses = inspector.GetSamplerTextureUses(r.entryPointName, placeholderBindingPoint);
+ CombinedSamplerInfo combinedSamplerInfo;
+ for (const auto& use : uses) {
+ combinedSamplerInfo.emplace_back();
+
+ CombinedSampler* info = &combinedSamplerInfo.back();
+ if (use.sampler_binding_point == placeholderBindingPoint) {
+ info->usePlaceholderSampler = true;
+ needsPlaceholderSampler = true;
+ tintOptions.placeholder_binding_point = placeholderBindingPoint;
+ } else {
+ info->usePlaceholderSampler = false;
+ }
+ info->samplerLocation.group = BindGroupIndex(use.sampler_binding_point.group);
+ info->samplerLocation.binding = BindingNumber(use.sampler_binding_point.binding);
+ info->textureLocation.group = BindGroupIndex(use.texture_binding_point.group);
+ info->textureLocation.binding = BindingNumber(use.texture_binding_point.binding);
+ tintOptions.binding_map[use] = info->GetName();
+ }
+ tintOptions.binding_points = std::move(r.glBindings);
+ tintOptions.allow_collisions = true;
+
+ auto result = tint::writer::glsl::Generate(&program, tintOptions, r.entryPointName);
+ DAWN_INVALID_IF(!result.success, "An error occured while generating GLSL: %s.",
+ result.error);
+
+ return GLSLCompilation{
+ {std::move(result.glsl), needsPlaceholderSampler, std::move(combinedSamplerInfo)}};
+ });
if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
std::ostringstream dumpedMsg;
- dumpedMsg << "/* Dumped generated GLSL */" << std::endl << glsl;
+ dumpedMsg << "/* Dumped generated GLSL */" << std::endl << compilationResult->glsl;
GetDevice()->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
}
- return glsl;
+ GLuint shader = gl.CreateShader(GLShaderType(stage));
+ const char* source = compilationResult->glsl.c_str();
+ gl.ShaderSource(shader, 1, &source, nullptr);
+ gl.CompileShader(shader);
+
+ GLint compileStatus = GL_FALSE;
+ gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
+ if (compileStatus == GL_FALSE) {
+ GLint infoLogLength = 0;
+ gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+ if (infoLogLength > 1) {
+ std::vector<char> buffer(infoLogLength);
+ gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
+ gl.DeleteShader(shader);
+ return DAWN_FORMAT_VALIDATION_ERROR("%s\nProgram compilation failed:\n%s", source,
+ buffer.data());
+ }
+ }
+
+ if (BlobCache* cache = GetDevice()->GetBlobCache()) {
+ cache->EnsureStored(compilationResult);
+ }
+ *needsPlaceholderSampler = compilationResult->needsPlaceholderSampler;
+ *combinedSamplers = std::move(compilationResult->combinedSamplerInfo);
+ return shader;
}
} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.h b/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.h
index 4dcff097fe8..b19b4c62c88 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.h
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/ShaderModuleGL.h
@@ -20,38 +20,52 @@
#include <unordered_map>
#include <vector>
+#include "dawn/native/Serializable.h"
#include "dawn/native/ShaderModule.h"
-
#include "dawn/native/opengl/opengl_platform.h"
-namespace dawn::native::opengl {
+namespace dawn::native {
+
+struct ProgrammableStage;
+
+namespace stream {
+class Sink;
+class Source;
+} // namespace stream
+
+namespace opengl {
class Device;
class PipelineLayout;
+struct OpenGLFunctions;
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber);
-struct BindingLocation {
- BindGroupIndex group;
- BindingNumber binding;
-};
+#define BINDING_LOCATION_MEMBERS(X) \
+ X(BindGroupIndex, group) \
+ X(BindingNumber, binding)
+DAWN_SERIALIZABLE(struct, BindingLocation, BINDING_LOCATION_MEMBERS){};
+#undef BINDING_LOCATION_MEMBERS
+
bool operator<(const BindingLocation& a, const BindingLocation& b);
-struct CombinedSampler {
- BindingLocation samplerLocation;
- BindingLocation textureLocation;
- // OpenGL requires a sampler with texelFetch. If this is true, the developer did not provide
- // one and Dawn should bind a placeholder non-filtering sampler. |samplerLocation| is
- // unused.
- bool usePlaceholderSampler;
+#define COMBINED_SAMPLER_MEMBERS(X) \
+ X(BindingLocation, samplerLocation) \
+ X(BindingLocation, textureLocation) \
+ /* OpenGL requires a sampler with texelFetch. If this is true, the developer did not */ \
+ /* provide one and Dawn should bind a placeholder non-filtering sampler; */ \
+ /* |samplerLocation| is unused. */ \
+ X(bool, usePlaceholderSampler)
+
+DAWN_SERIALIZABLE(struct, CombinedSampler, COMBINED_SAMPLER_MEMBERS) {
std::string GetName() const;
};
+#undef COMBINED_SAMPLER_MEMBERS
+
bool operator<(const CombinedSampler& a, const CombinedSampler& b);
using CombinedSamplerInfo = std::vector<CombinedSampler>;
-using BindingInfoArrayTable = std::unordered_map<std::string, std::unique_ptr<BindingInfoArray>>;
-
class ShaderModule final : public ShaderModuleBase {
public:
static ResultOrError<Ref<ShaderModule>> Create(Device* device,
@@ -59,11 +73,12 @@ class ShaderModule final : public ShaderModuleBase {
ShaderModuleParseResult* parseResult,
OwnedCompilationMessages* compilationMessages);
- ResultOrError<std::string> TranslateToGLSL(const char* entryPointName,
- SingleShaderStage stage,
- CombinedSamplerInfo* combinedSamplers,
- const PipelineLayout* layout,
- bool* needsPlaceholderSampler) const;
+ ResultOrError<GLuint> CompileShader(const OpenGLFunctions& gl,
+ const ProgrammableStage& programmableStage,
+ SingleShaderStage stage,
+ CombinedSamplerInfo* combinedSamplers,
+ const PipelineLayout* layout,
+ bool* needsPlaceholderSampler) const;
private:
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
@@ -72,6 +87,7 @@ class ShaderModule final : public ShaderModuleBase {
OwnedCompilationMessages* compilationMessages);
};
-} // namespace dawn::native::opengl
+} // namespace opengl
+} // namespace dawn::native
#endif // SRC_DAWN_NATIVE_OPENGL_SHADERMODULEGL_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/TextureGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/TextureGL.cpp
index 88130bd8c61..6b473420710 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/TextureGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/TextureGL.cpp
@@ -83,12 +83,6 @@ GLenum TargetForTextureViewDimension(wgpu::TextureViewDimension dimension,
UNREACHABLE();
}
-GLuint GenTexture(const OpenGLFunctions& gl) {
- GLuint handle = 0;
- gl.GenTextures(1, &handle);
- return handle;
-}
-
bool RequiresCreatingNewTextureView(const TextureBase* texture,
const TextureViewDescriptor* textureViewDescriptor) {
constexpr wgpu::TextureUsage kShaderUsageNeedsView =
@@ -179,9 +173,10 @@ void AllocateTexture(const OpenGLFunctions& gl,
// Texture
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
- : Texture(device, descriptor, GenTexture(device->gl), TextureState::OwnedInternal) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ : Texture(device, descriptor, 0, TextureState::OwnedInternal) {
+ const OpenGLFunctions& gl = device->GetGL();
+ gl.GenTextures(1, &mHandle);
uint32_t levels = GetNumMipLevels();
const GLFormat& glFormat = GetGLFormat();
@@ -221,7 +216,8 @@ Texture::~Texture() {}
void Texture::DestroyImpl() {
TextureBase::DestroyImpl();
if (GetTextureState() == TextureState::OwnedInternal) {
- ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
+ gl.DeleteTextures(1, &mHandle);
mHandle = 0;
}
}
@@ -246,7 +242,7 @@ MaybeError Texture::ClearTexture(const SubresourceRange& range,
}
Device* device = ToBackend(GetDevice());
- const OpenGLFunctions& gl = device->gl;
+ const OpenGLFunctions& gl = device->GetGL();
uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f;
@@ -534,7 +530,7 @@ MaybeError Texture::ClearTexture(const SubresourceRange& range,
}
textureCopy.origin.z = layer;
- DoTexSubImage(ToBackend(GetDevice())->gl, textureCopy, 0, dataLayout, mipSize);
+ DoTexSubImage(gl, textureCopy, 0, dataLayout, mipSize);
}
}
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@@ -571,9 +567,9 @@ TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* desc
if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mHandle = ToBackend(texture)->GetHandle();
} else {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
if (gl.IsAtLeastGL(4, 3)) {
- mHandle = GenTexture(gl);
+ gl.GenTextures(1, &mHandle);
const Texture* textureGL = ToBackend(texture);
gl.TextureView(mHandle, mTarget, textureGL->GetHandle(), GetInternalFormat(),
descriptor->baseMipLevel, descriptor->mipLevelCount,
@@ -592,7 +588,8 @@ TextureView::~TextureView() {}
void TextureView::DestroyImpl() {
TextureViewBase::DestroyImpl();
if (mOwnsHandle) {
- ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
+ gl.DeleteTextures(1, &mHandle);
}
}
@@ -606,7 +603,7 @@ GLenum TextureView::GetGLTarget() const {
}
void TextureView::BindToFramebuffer(GLenum target, GLenum attachment) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
+ const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
// Use the base texture where possible to minimize the amount of copying required on GLES.
bool useOwnView = GetFormat().format != GetTexture()->GetFormat().format &&
@@ -648,7 +645,7 @@ void TextureView::CopyIfNeeded() {
}
Device* device = ToBackend(GetDevice());
- const OpenGLFunctions& gl = device->gl;
+ const OpenGLFunctions& gl = device->GetGL();
uint32_t srcLevel = GetBaseMipLevel();
uint32_t numLevels = GetLevelCount();
@@ -657,7 +654,7 @@ void TextureView::CopyIfNeeded() {
Extent3D size{width, height, GetLayerCount()};
if (mHandle == 0) {
- mHandle = GenTexture(gl);
+ gl.GenTextures(1, &mHandle);
gl.BindTexture(mTarget, mHandle);
AllocateTexture(gl, mTarget, texture->GetSampleCount(), numLevels, GetInternalFormat(),
size);
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/UtilsEGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/UtilsEGL.cpp
new file mode 100644
index 00000000000..479923e1e12
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/UtilsEGL.cpp
@@ -0,0 +1,75 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/native/opengl/UtilsEGL.h"
+
+#include <string>
+
+#include "dawn/native/opengl/EGLFunctions.h"
+
+namespace dawn::native::opengl {
+
+const char* EGLErrorAsString(EGLint error) {
+ switch (error) {
+ case EGL_SUCCESS:
+ return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED:
+ return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS:
+ return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC:
+ return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE:
+ return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONTEXT:
+ return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CONFIG:
+ return "EGL_BAD_CONFIG";
+ case EGL_BAD_CURRENT_SURFACE:
+ return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY:
+ return "EGL_BAD_DISPLAY";
+ case EGL_BAD_SURFACE:
+ return "EGL_BAD_SURFACE";
+ case EGL_BAD_MATCH:
+ return "EGL_BAD_MATCH";
+ case EGL_BAD_PARAMETER:
+ return "EGL_BAD_PARAMETER";
+ case EGL_BAD_NATIVE_PIXMAP:
+ return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW:
+ return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_CONTEXT_LOST:
+ return "EGL_CONTEXT_LOST";
+ default:
+ return "<Unknown EGL error>";
+ }
+}
+
+MaybeError CheckEGL(const EGLFunctions& egl, EGLBoolean result, const char* context) {
+ if (DAWN_LIKELY(result == EGL_TRUE)) {
+ return {};
+ }
+ EGLint error = egl.GetError();
+ std::string message = std::string(context) + " failed with " + EGLErrorAsString(error);
+ if (error == EGL_BAD_ALLOC) {
+ return DAWN_OUT_OF_MEMORY_ERROR(message);
+ } else if (error == EGL_CONTEXT_LOST) {
+ return DAWN_DEVICE_LOST_ERROR(message);
+ } else {
+ return DAWN_INTERNAL_ERROR(message);
+ }
+}
+
+} // namespace dawn::native::opengl
diff --git a/chromium/third_party/dawn/src/include/dawn/EnumClassBitmasks.h b/chromium/third_party/dawn/src/dawn/native/opengl/UtilsEGL.h
index 7d76b377923..cf631455d59 100644
--- a/chromium/third_party/dawn/src/include/dawn/EnumClassBitmasks.h
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/UtilsEGL.h
@@ -12,9 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_INCLUDE_DAWN_ENUMCLASSBITMASKS_H_
-#define SRC_INCLUDE_DAWN_ENUMCLASSBITMASKS_H_
+#ifndef SRC_DAWN_NATIVE_OPENGL_UTILSEGL_H_
+#define SRC_DAWN_NATIVE_OPENGL_UTILSEGL_H_
-#include "dawn/EnumClassBitmasks.h"
+#include <EGL/egl.h>
-#endif // SRC_INCLUDE_DAWN_ENUMCLASSBITMASKS_H_
+#include "dawn/native/Error.h"
+
+namespace dawn::native::opengl {
+
+struct EGLFunctions;
+
+const char* EGLErrorAsString(EGLint error);
+MaybeError CheckEGL(const EGLFunctions& egl, EGLBoolean result, const char* context);
+
+} // namespace dawn::native::opengl
+
+#endif // SRC_DAWN_NATIVE_OPENGL_UTILSEGL_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/opengl/UtilsGL.cpp b/chromium/third_party/dawn/src/dawn/native/opengl/UtilsGL.cpp
index e35b9a14aa9..d5dd34d5e4e 100644
--- a/chromium/third_party/dawn/src/dawn/native/opengl/UtilsGL.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/opengl/UtilsGL.cpp
@@ -48,7 +48,6 @@ GLuint ToOpenGLCompareFunction(wgpu::CompareFunction compareFunction) {
GLint GetStencilMaskFromStencilFormat(wgpu::TextureFormat depthStencilFormat) {
switch (depthStencilFormat) {
case wgpu::TextureFormat::Depth24PlusStencil8:
- case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
return 0xFF;
diff --git a/chromium/third_party/dawn/src/include/dawn/dawn_thread_dispatch_proc.h b/chromium/third_party/dawn/src/dawn/native/stream/BlobSource.cpp
index 126e50cafd8..deeaf12450d 100644
--- a/chromium/third_party/dawn/src/include/dawn/dawn_thread_dispatch_proc.h
+++ b/chromium/third_party/dawn/src/dawn/native/stream/BlobSource.cpp
@@ -12,9 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_INCLUDE_DAWN_DAWN_THREAD_DISPATCH_PROC_H_
-#define SRC_INCLUDE_DAWN_DAWN_THREAD_DISPATCH_PROC_H_
+#include "dawn/native/stream/BlobSource.h"
-#include "dawn/dawn_thread_dispatch_proc.h"
+#include <utility>
-#endif // SRC_INCLUDE_DAWN_DAWN_THREAD_DISPATCH_PROC_H_
+namespace dawn::native::stream {
+
+BlobSource::BlobSource(Blob&& blob) : mBlob(std::move(blob)) {}
+
+MaybeError BlobSource::Read(const void** ptr, size_t bytes) {
+ DAWN_INVALID_IF(bytes > mBlob.Size() - mOffset, "Out of bounds.");
+ *ptr = mBlob.Data() + mOffset;
+ mOffset += bytes;
+ return {};
+}
+
+} // namespace dawn::native::stream
diff --git a/chromium/third_party/dawn/src/dawn/native/stream/BlobSource.h b/chromium/third_party/dawn/src/dawn/native/stream/BlobSource.h
new file mode 100644
index 00000000000..d93478e712c
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/stream/BlobSource.h
@@ -0,0 +1,38 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_STREAM_BLOBSOURCE_H_
+#define SRC_DAWN_NATIVE_STREAM_BLOBSOURCE_H_
+
+#include "dawn/native/Blob.h"
+#include "dawn/native/Error.h"
+#include "dawn/native/stream/Source.h"
+
+namespace dawn::native::stream {
+
+class BlobSource : public Source {
+ public:
+ explicit BlobSource(Blob&& blob);
+
+ // stream::Source implementation.
+ MaybeError Read(const void** ptr, size_t bytes) override;
+
+ private:
+ const Blob mBlob;
+ size_t mOffset = 0;
+};
+
+} // namespace dawn::native::stream
+
+#endif // SRC_DAWN_NATIVE_STREAM_BLOBSOURCE_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.cpp b/chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.cpp
new file mode 100644
index 00000000000..20c27f23698
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.cpp
@@ -0,0 +1,47 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/native/stream/ByteVectorSink.h"
+
+#include "dawn/native/stream/Stream.h"
+
+namespace dawn::native::stream {
+
+void* ByteVectorSink::GetSpace(size_t bytes) {
+ size_t currentSize = this->size();
+ this->resize(currentSize + bytes);
+ return &this->operator[](currentSize);
+}
+
+template <>
+void stream::Stream<ByteVectorSink>::Write(stream::Sink* sink, const ByteVectorSink& vec) {
+ // For nested sinks, we do not record the length, and just copy the data so that it
+ // appears flattened.
+ size_t size = vec.size();
+ if (size > 0) {
+ void* ptr = sink->GetSpace(size);
+ memcpy(ptr, vec.data(), size);
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, const ByteVectorSink& vec) {
+ os << std::hex;
+ for (const int b : vec) {
+ os << std::setfill('0') << std::setw(2) << b << " ";
+ }
+ os << std::dec;
+ return os;
+}
+
+} // namespace dawn::native::stream
diff --git a/chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.h b/chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.h
new file mode 100644
index 00000000000..3b6016c0823
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/stream/ByteVectorSink.h
@@ -0,0 +1,39 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_STREAM_BYTEVECTORSINK_H_
+#define SRC_DAWN_NATIVE_STREAM_BYTEVECTORSINK_H_
+
+#include <ostream>
+#include <vector>
+
+#include "dawn/native/stream/Sink.h"
+
+namespace dawn::native::stream {
+
+// Implementation of stream::Sink backed by a byte vector.
+class ByteVectorSink : public std::vector<uint8_t>, public Sink {
+ public:
+ using std::vector<uint8_t>::vector;
+
+ // Implementation of stream::Sink
+ void* GetSpace(size_t bytes) override;
+};
+
+// Stream operator for ByteVectorSink for debugging.
+std::ostream& operator<<(std::ostream& os, const ByteVectorSink& key);
+
+} // namespace dawn::native::stream
+
+#endif // SRC_DAWN_NATIVE_STREAM_BYTEVECTORSINK_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/stream/Sink.h b/chromium/third_party/dawn/src/dawn/native/stream/Sink.h
new file mode 100644
index 00000000000..caf1ba4fff5
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/stream/Sink.h
@@ -0,0 +1,32 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_STREAM_SINK_H_
+#define SRC_DAWN_NATIVE_STREAM_SINK_H_
+
+#include <cstddef>
+
+namespace dawn::native::stream {
+
+// Interface for a serialization sink.
+class Sink {
+ public:
+ // Allocate `bytes` space in the sink. Returns the pointer to the start
+ // of the allocation.
+ virtual void* GetSpace(size_t bytes) = 0;
+};
+
+} // namespace dawn::native::stream
+
+#endif // SRC_DAWN_NATIVE_STREAM_SINK_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/stream/Source.h b/chromium/third_party/dawn/src/dawn/native/stream/Source.h
new file mode 100644
index 00000000000..c7b19d092c3
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/stream/Source.h
@@ -0,0 +1,34 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_STREAM_SOURCE_H_
+#define SRC_DAWN_NATIVE_STREAM_SOURCE_H_
+
+#include <cstddef>
+
+namespace dawn::native::stream {
+
+// Interface for a deserialization source.
+class Source {
+ public:
+ // Try to read `bytes` space from the source. The data must live as long as `Source.
+ // Returns MaybeError and writes result to |ptr| because ResultOrError uses
+ // a tagged pointer that must be 4-byte aligned. This function writes out |ptr|
+ // which may not be aligned.
+ virtual MaybeError Read(const void** ptr, size_t bytes) = 0;
+};
+
+} // namespace dawn::native::stream
+
+#endif // SRC_DAWN_NATIVE_STREAM_SOURCE_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/stream/Stream.cpp b/chromium/third_party/dawn/src/dawn/native/stream/Stream.cpp
new file mode 100644
index 00000000000..beb3823da00
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/stream/Stream.cpp
@@ -0,0 +1,61 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/native/stream/Stream.h"
+
+#include <string>
+
+namespace dawn::native::stream {
+
+template <>
+void Stream<std::string>::Write(Sink* s, const std::string& t) {
+ StreamIn(s, t.length());
+ size_t size = t.length() * sizeof(char);
+ if (size > 0) {
+ void* ptr = s->GetSpace(size);
+ memcpy(ptr, t.data(), size);
+ }
+}
+
+template <>
+MaybeError Stream<std::string>::Read(Source* s, std::string* t) {
+ size_t length;
+ DAWN_TRY(StreamOut(s, &length));
+ const void* ptr;
+ DAWN_TRY(s->Read(&ptr, length));
+ *t = std::string(static_cast<const char*>(ptr), length);
+ return {};
+}
+
+template <>
+void Stream<std::string_view>::Write(Sink* s, const std::string_view& t) {
+ StreamIn(s, t.length());
+ size_t size = t.length() * sizeof(char);
+ if (size > 0) {
+ void* ptr = s->GetSpace(size);
+ memcpy(ptr, t.data(), size);
+ }
+}
+
+template <>
+void Stream<std::wstring_view>::Write(Sink* s, const std::wstring_view& t) {
+ StreamIn(s, t.length());
+ size_t size = t.length() * sizeof(wchar_t);
+ if (size > 0) {
+ void* ptr = s->GetSpace(size);
+ memcpy(ptr, t.data(), size);
+ }
+}
+
+} // namespace dawn::native::stream
diff --git a/chromium/third_party/dawn/src/dawn/native/stream/Stream.h b/chromium/third_party/dawn/src/dawn/native/stream/Stream.h
new file mode 100644
index 00000000000..d077cccc60c
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/stream/Stream.h
@@ -0,0 +1,338 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_STREAM_STREAM_H_
+#define SRC_DAWN_NATIVE_STREAM_STREAM_H_
+
+#include <algorithm>
+#include <bitset>
+#include <functional>
+#include <limits>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <optional>
+
+#include "dawn/common/Platform.h"
+#include "dawn/common/TypedInteger.h"
+#include "dawn/native/Error.h"
+#include "dawn/native/stream/Sink.h"
+#include "dawn/native/stream/Source.h"
+
+namespace dawn::native::stream {
+
+// Base Stream template for specialization. Specializations may define static methods:
+// static void Write(Sink* s, const T& v);
+// static MaybeError Read(Source* s, T* v);
+template <typename T, typename SFINAE = void>
+class Stream {
+ public:
+ static void Write(Sink* s, const T& v);
+ static MaybeError Read(Source* s, T* v);
+};
+
+// Helper to call Stream<T>::Write.
+// By default, calling StreamIn will call this overload inside the stream namespace.
+// Other definitons of StreamIn found by ADL may override this one.
+template <typename T>
+constexpr void StreamIn(Sink* s, const T& v) {
+ Stream<T>::Write(s, v);
+}
+
+// Helper to call Stream<T>::Read
+// By default, calling StreamOut will call this overload inside the stream namespace.
+// Other definitons of StreamOut found by ADL may override this one.
+template <typename T>
+MaybeError StreamOut(Source* s, T* v) {
+ return Stream<T>::Read(s, v);
+}
+
+// Helper to take an rvalue passed to StreamOut and forward it as a pointer.
+// This makes it possible to pass output wrappers like stream::StructMembers inline.
+// For example: `DAWN_TRY(StreamOut(&source, stream::StructMembers(...)));`
+template <typename T>
+MaybeError StreamOut(Source* s, T&& v) {
+ return StreamOut(s, &v);
+}
+
+// Helper to call StreamIn on a parameter pack.
+template <typename T, typename... Ts>
+constexpr void StreamIn(Sink* s, const T& v, const Ts&... vs) {
+ StreamIn(s, v);
+ (StreamIn(s, vs), ...);
+}
+
+// Helper to call StreamOut on a parameter pack.
+template <typename T, typename... Ts>
+MaybeError StreamOut(Source* s, T* v, Ts*... vs) {
+ DAWN_TRY(StreamOut(s, v));
+ return StreamOut(s, vs...);
+}
+
+// Stream specialization for fundamental types.
+template <typename T>
+class Stream<T, std::enable_if_t<std::is_fundamental_v<T>>> {
+ public:
+ static void Write(Sink* s, const T& v) { memcpy(s->GetSpace(sizeof(T)), &v, sizeof(T)); }
+ static MaybeError Read(Source* s, T* v) {
+ const void* ptr;
+ DAWN_TRY(s->Read(&ptr, sizeof(T)));
+ memcpy(v, ptr, sizeof(T));
+ return {};
+ }
+};
+
+namespace detail {
+// NOLINTNEXTLINE(runtime/int) Alias "unsigned long long" type to match std::bitset to_ullong
+using BitsetUllong = unsigned long long;
+constexpr size_t kBitsPerUllong = 8 * sizeof(BitsetUllong);
+constexpr bool BitsetSupportsToUllong(size_t N) {
+ return N <= kBitsPerUllong;
+}
+} // namespace detail
+
+// Stream specialization for bitsets that are smaller than BitsetUllong.
+template <size_t N>
+class Stream<std::bitset<N>, std::enable_if_t<detail::BitsetSupportsToUllong(N)>> {
+ public:
+ static void Write(Sink* s, const std::bitset<N>& t) { StreamIn(s, t.to_ullong()); }
+ static MaybeError Read(Source* s, std::bitset<N>* v) {
+ detail::BitsetUllong value;
+ DAWN_TRY(StreamOut(s, &value));
+ *v = std::bitset<N>(value);
+ return {};
+ }
+};
+
+// Stream specialization for bitsets since using the built-in to_ullong has a size limit.
+template <size_t N>
+class Stream<std::bitset<N>, std::enable_if_t<!detail::BitsetSupportsToUllong(N)>> {
+ public:
+ static void Write(Sink* s, const std::bitset<N>& t) {
+ // Iterate in chunks of detail::BitsetUllong.
+ static std::bitset<N> mask(std::numeric_limits<detail::BitsetUllong>::max());
+
+ std::bitset<N> bits = t;
+ for (size_t offset = 0; offset < N;
+ offset += detail::kBitsPerUllong, bits >>= detail::kBitsPerUllong) {
+ StreamIn(s, (mask & bits).to_ullong());
+ }
+ }
+
+ static MaybeError Read(Source* s, std::bitset<N>* v) {
+ static_assert(N > 0);
+ *v = {};
+
+ // Iterate in chunks of detail::BitsetUllong.
+ for (size_t offset = 0; offset < N;
+ offset += detail::kBitsPerUllong, (*v) <<= detail::kBitsPerUllong) {
+ detail::BitsetUllong ullong;
+ DAWN_TRY(StreamOut(s, &ullong));
+ *v |= std::bitset<N>(ullong);
+ }
+ return {};
+ }
+};
+
+// Stream specialization for enums.
+template <typename T>
+class Stream<T, std::enable_if_t<std::is_enum_v<T>>> {
+ using U = std::underlying_type_t<T>;
+
+ public:
+ static void Write(Sink* s, const T& v) { StreamIn(s, static_cast<U>(v)); }
+
+ static MaybeError Read(Source* s, T* v) {
+ U out;
+ DAWN_TRY(StreamOut(s, &out));
+ *v = static_cast<T>(out);
+ return {};
+ }
+};
+
+// Stream specialization for TypedInteger.
+template <typename Tag, typename Integer>
+class Stream<::detail::TypedIntegerImpl<Tag, Integer>> {
+ using T = ::detail::TypedIntegerImpl<Tag, Integer>;
+
+ public:
+ static void Write(Sink* s, const T& t) { StreamIn(s, static_cast<Integer>(t)); }
+
+ static MaybeError Read(Source* s, T* v) {
+ Integer out;
+ DAWN_TRY(StreamOut(s, &out));
+ *v = T(out);
+ return {};
+ }
+};
+
+// Stream specialization for pointers. We always serialize via value, not by pointer.
+// To handle nullptr scenarios, we always serialize whether the pointer was not nullptr,
+// followed by the contents if applicable.
+template <typename T>
+class Stream<T, std::enable_if_t<std::is_pointer_v<T>>> {
+ public:
+ static void Write(stream::Sink* sink, const T& t) {
+ using Pointee = std::decay_t<std::remove_pointer_t<T>>;
+ static_assert(!std::is_same_v<char, Pointee> && !std::is_same_v<wchar_t, Pointee> &&
+ !std::is_same_v<char16_t, Pointee> && !std::is_same_v<char32_t, Pointee>,
+ "C-str like type likely has ambiguous serialization. For a string, wrap with "
+ "std::string_view instead.");
+ StreamIn(sink, t != nullptr);
+ if (t != nullptr) {
+ StreamIn(sink, *t);
+ }
+ }
+};
+
+// Stream specialization for std::optional
+template <typename T>
+class Stream<std::optional<T>> {
+ public:
+ static void Write(stream::Sink* sink, const std::optional<T>& t) {
+ bool hasValue = t.has_value();
+ StreamIn(sink, hasValue);
+ if (hasValue) {
+ StreamIn(sink, *t);
+ }
+ }
+};
+
+// Stream specialization for fixed arrays of fundamental types.
+template <typename T, size_t N>
+class Stream<T[N], std::enable_if_t<std::is_fundamental_v<T>>> {
+ public:
+ static void Write(Sink* s, const T (&t)[N]) {
+ static_assert(N > 0);
+ memcpy(s->GetSpace(sizeof(t)), &t, sizeof(t));
+ }
+
+ static MaybeError Read(Source* s, T (*t)[N]) {
+ static_assert(N > 0);
+ const void* ptr;
+ DAWN_TRY(s->Read(&ptr, sizeof(*t)));
+ memcpy(*t, ptr, sizeof(*t));
+ return {};
+ }
+};
+
+// Specialization for fixed arrays of non-fundamental types.
+template <typename T, size_t N>
+class Stream<T[N], std::enable_if_t<!std::is_fundamental_v<T>>> {
+ public:
+ static void Write(Sink* s, const T (&t)[N]) {
+ static_assert(N > 0);
+ for (size_t i = 0; i < N; i++) {
+ StreamIn(s, t[i]);
+ }
+ }
+
+ static MaybeError Read(Source* s, T (*t)[N]) {
+ static_assert(N > 0);
+ for (size_t i = 0; i < N; i++) {
+ DAWN_TRY(StreamOut(s, &(*t)[i]));
+ }
+ return {};
+ }
+};
+
+// Stream specialization for std::vector.
+template <typename T>
+class Stream<std::vector<T>> {
+ public:
+ static void Write(Sink* s, const std::vector<T>& v) {
+ StreamIn(s, v.size());
+ for (const T& it : v) {
+ StreamIn(s, it);
+ }
+ }
+
+ static MaybeError Read(Source* s, std::vector<T>* v) {
+ using SizeT = decltype(std::declval<std::vector<T>>().size());
+ SizeT size;
+ DAWN_TRY(StreamOut(s, &size));
+ *v = {};
+ v->reserve(size);
+ for (SizeT i = 0; i < size; ++i) {
+ T el;
+ DAWN_TRY(StreamOut(s, &el));
+ v->push_back(std::move(el));
+ }
+ return {};
+ }
+};
+
+// Stream specialization for std::pair.
+template <typename A, typename B>
+class Stream<std::pair<A, B>> {
+ public:
+ static void Write(Sink* s, const std::pair<A, B>& v) {
+ StreamIn(s, v.first);
+ StreamIn(s, v.second);
+ }
+
+ static MaybeError Read(Source* s, std::pair<A, B>* v) {
+ DAWN_TRY(StreamOut(s, &v->first));
+ DAWN_TRY(StreamOut(s, &v->second));
+ return {};
+ }
+};
+
+// Stream specialization for std::unordered_map<K, V> which sorts the entries
+// to provide a stable ordering.
+template <typename K, typename V>
+class Stream<std::unordered_map<K, V>> {
+ public:
+ static void Write(stream::Sink* sink, const std::unordered_map<K, V>& m) {
+ std::vector<std::pair<K, V>> ordered(m.begin(), m.end());
+ std::sort(
+ ordered.begin(), ordered.end(),
+ [](const std::pair<K, V>& a, const std::pair<K, V>& b) { return a.first < b.first; });
+ StreamIn(sink, ordered);
+ }
+};
+
+// Helper class to contain the begin/end iterators of an iterable.
+namespace detail {
+template <typename Iterator>
+struct Iterable {
+ Iterator begin;
+ Iterator end;
+};
+} // namespace detail
+
+// Helper for making detail::Iterable from a pointer and count.
+template <typename T>
+auto Iterable(const T* ptr, size_t count) {
+ using Iterator = const T*;
+ return detail::Iterable<Iterator>{ptr, ptr + count};
+}
+
+// Stream specialization for detail::Iterable which writes the number of elements,
+// followed by the elements.
+template <typename Iterator>
+class Stream<detail::Iterable<Iterator>> {
+ public:
+ static void Write(stream::Sink* sink, const detail::Iterable<Iterator>& iter) {
+ StreamIn(sink, std::distance(iter.begin, iter.end));
+ for (auto it = iter.begin; it != iter.end; ++it) {
+ StreamIn(sink, *it);
+ }
+ }
+};
+
+} // namespace dawn::native::stream
+
+#endif // SRC_DAWN_NATIVE_STREAM_STREAM_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.cpp b/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.cpp
index 722476e8cc3..2a7a5e0a3cc 100644
--- a/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.cpp
@@ -165,7 +165,8 @@ BindGroupEntry BindingInitializationHelper::GetAsBinding() const {
ResultOrError<Ref<BindGroupBase>> MakeBindGroup(
DeviceBase* device,
const Ref<BindGroupLayoutBase>& layout,
- std::initializer_list<BindingInitializationHelper> entriesInitializer) {
+ std::initializer_list<BindingInitializationHelper> entriesInitializer,
+ UsageValidationMode mode) {
std::vector<BindGroupEntry> entries;
for (const BindingInitializationHelper& helper : entriesInitializer) {
entries.push_back(helper.GetAsBinding());
@@ -176,7 +177,7 @@ ResultOrError<Ref<BindGroupBase>> MakeBindGroup(
descriptor.entryCount = entries.size();
descriptor.entries = entries.data();
- return device->CreateBindGroup(&descriptor);
+ return device->CreateBindGroup(&descriptor, mode);
}
const char* GetLabelForTrace(const char* label) {
diff --git a/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.h b/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.h
index 9eab9906689..45cfa46e2b6 100644
--- a/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.h
+++ b/chromium/third_party/dawn/src/dawn/native/utils/WGPUHelpers.h
@@ -21,6 +21,7 @@
#include "dawn/common/RefCounted.h"
#include "dawn/native/Error.h"
+#include "dawn/native/UsageValidationMode.h"
#include "dawn/native/dawn_platform.h"
namespace dawn::native::utils {
@@ -110,10 +111,12 @@ struct BindingInitializationHelper {
uint64_t size = 0;
};
+// This helper is only used inside dawn native.
ResultOrError<Ref<BindGroupBase>> MakeBindGroup(
DeviceBase* device,
const Ref<BindGroupLayoutBase>& layout,
- std::initializer_list<BindingInitializationHelper> entriesInitializer);
+ std::initializer_list<BindingInitializationHelper> entriesInitializer,
+ UsageValidationMode mode);
const char* GetLabelForTrace(const char* label);
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/AdapterVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/AdapterVk.cpp
index fbdb709d1ad..9ccc4d65146 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/AdapterVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/AdapterVk.cpp
@@ -147,18 +147,10 @@ MaybeError Adapter::InitializeSupportedFeaturesImpl() {
mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery);
}
- if (mDeviceInfo.features.depthClamp == VK_TRUE) {
- mSupportedFeatures.EnableFeature(Feature::DepthClamping);
- }
-
if (mDeviceInfo.properties.limits.timestampComputeAndGraphics == VK_TRUE) {
mSupportedFeatures.EnableFeature(Feature::TimestampQuery);
}
- if (IsDepthStencilFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT)) {
- mSupportedFeatures.EnableFeature(Feature::Depth24UnormStencil8);
- }
-
if (IsDepthStencilFormatSupported(VK_FORMAT_D32_SFLOAT_S8_UINT)) {
mSupportedFeatures.EnableFeature(Feature::Depth32FloatStencil8);
}
@@ -175,6 +167,11 @@ MaybeError Adapter::InitializeSupportedFeaturesImpl() {
mSupportedFeatures.EnableFeature(Feature::ChromiumExperimentalDp4a);
}
+ if (mDeviceInfo.HasExt(DeviceExt::DepthClipEnable) &&
+ mDeviceInfo.depthClipEnableFeatures.depthClipEnable == VK_TRUE) {
+ mSupportedFeatures.EnableFeature(Feature::DepthClipControl);
+ }
+
#if defined(DAWN_USE_SYNC_FDS)
// TODO(chromium:1258986): Precisely enable the feature by querying the device's format
// features.
@@ -281,9 +278,7 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
vkLimits.maxComputeWorkGroupCount[2],
});
- if (vkLimits.maxColorAttachments < kMaxColorAttachments) {
- return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxColorAttachments");
- }
+ CHECK_AND_SET_V1_MAX_LIMIT(maxColorAttachments, maxColorAttachments);
if (!IsSubset(VkSampleCountFlags(VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT),
vkLimits.framebufferColorSampleCounts)) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for framebufferColorSampleCounts");
@@ -345,6 +340,10 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
}
}
+ // Using base limits for:
+ // TODO(crbug.com/dawn/1448):
+ // - maxInterStageShaderVariables
+
return {};
}
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp
index fccf6001e42..de2c2c7cfc4 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp
@@ -82,6 +82,10 @@ constexpr SkippedMessage kSkippedMessages[] = {
"stencil aspect during store with stencilStoreOp VK_ATTACHMENT_STORE_OP_STORE. Access info "
"(usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: "
"SYNC_FRAGMENT_SHADER_SHADER_STORAGE_READ, read_barriers: VK_PIPELINE_STAGE_2_NONE"},
+
+ // http://anglebug.com/7513
+ {"VUID-VkGraphicsPipelineCreateInfo-pStages-06896",
+ "contains fragment shader state, but stages"},
};
namespace dawn::native::vulkan {
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/BindGroupLayoutVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/BindGroupLayoutVk.cpp
index a87a91fc981..94b5a7dc6b8 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/BindGroupLayoutVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/BindGroupLayoutVk.cpp
@@ -117,7 +117,7 @@ MaybeError BindGroupLayout::Initialize() {
createInfo.pBindings = bindings.data();
// Record cache key information now since the createInfo is not stored.
- mCacheKey.Record(createInfo);
+ StreamIn(&mCacheKey, createInfo);
Device* device = ToBackend(GetDevice());
DAWN_TRY(CheckVkSuccess(device->fn.CreateDescriptorSetLayout(device->GetVkDevice(), &createInfo,
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.cpp
deleted file mode 100644
index d89649e7462..00000000000
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <cstring>
-
-#include "dawn/native/vulkan/CacheKeyVk.h"
-#include "dawn/native/vulkan/RenderPassCache.h"
-
-namespace dawn::native {
-
-template <>
-void CacheKeySerializer<VkDescriptorSetLayoutBinding>::Serialize(
- CacheKey* key,
- const VkDescriptorSetLayoutBinding& t) {
- key->Record(t.binding, t.descriptorType, t.descriptorCount, t.stageFlags);
-}
-
-template <>
-void CacheKeySerializer<VkDescriptorSetLayoutCreateInfo>::Serialize(
- CacheKey* key,
- const VkDescriptorSetLayoutCreateInfo& t) {
- key->Record(t.flags).RecordIterable(t.pBindings, t.bindingCount);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPushConstantRange>::Serialize(CacheKey* key,
- const VkPushConstantRange& t) {
- key->Record(t.stageFlags, t.offset, t.size);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineLayoutCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineLayoutCreateInfo& t) {
- // The set layouts are not serialized here because they are pointers to backend objects.
- // They need to be cross-referenced with the frontend objects and serialized from there.
- key->Record(t.flags).RecordIterable(t.pPushConstantRanges, t.pushConstantRangeCount);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>::Serialize(
- CacheKey* key,
- const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT& t) {
- key->Record(t.requiredSubgroupSize);
-}
-
-template <>
-void CacheKeySerializer<VkSpecializationMapEntry>::Serialize(CacheKey* key,
- const VkSpecializationMapEntry& t) {
- key->Record(t.constantID, t.offset, t.size);
-}
-
-template <>
-void CacheKeySerializer<VkSpecializationInfo>::Serialize(CacheKey* key,
- const VkSpecializationInfo& t) {
- key->RecordIterable(t.pMapEntries, t.mapEntryCount)
- .RecordIterable(static_cast<const uint8_t*>(t.pData), t.dataSize);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineShaderStageCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineShaderStageCreateInfo& t) {
- // The shader module is not serialized here because it is a pointer to a backend object.
- key->Record(t.flags, t.stage)
- .RecordIterable(t.pName, strlen(t.pName))
- .Record(t.pSpecializationInfo);
- vulkan::SerializePnext<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkComputePipelineCreateInfo>::Serialize(
- CacheKey* key,
- const VkComputePipelineCreateInfo& t) {
- // The pipeline layout is not serialized here because it is a pointer to a backend object.
- // It needs to be cross-referenced with the frontend objects and serialized from there. The
- // base pipeline information is also currently not recorded since we do not use them in our
- // backend implementation. If we decide to use them later on, they also need to be
- // cross-referenced from the frontend.
- key->Record(t.flags, t.stage);
-}
-
-template <>
-void CacheKeySerializer<VkVertexInputBindingDescription>::Serialize(
- CacheKey* key,
- const VkVertexInputBindingDescription& t) {
- key->Record(t.binding, t.stride, t.inputRate);
-}
-
-template <>
-void CacheKeySerializer<VkVertexInputAttributeDescription>::Serialize(
- CacheKey* key,
- const VkVertexInputAttributeDescription& t) {
- key->Record(t.location, t.binding, t.format, t.offset);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineVertexInputStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineVertexInputStateCreateInfo& t) {
- key->Record(t.flags)
- .RecordIterable(t.pVertexBindingDescriptions, t.vertexBindingDescriptionCount)
- .RecordIterable(t.pVertexAttributeDescriptions, t.vertexAttributeDescriptionCount);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineInputAssemblyStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineInputAssemblyStateCreateInfo& t) {
- key->Record(t.flags, t.topology, t.primitiveRestartEnable);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineTessellationStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineTessellationStateCreateInfo& t) {
- key->Record(t.flags, t.patchControlPoints);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkViewport>::Serialize(CacheKey* key, const VkViewport& t) {
- key->Record(t.x, t.y, t.width, t.height, t.minDepth, t.maxDepth);
-}
-
-template <>
-void CacheKeySerializer<VkOffset2D>::Serialize(CacheKey* key, const VkOffset2D& t) {
- key->Record(t.x, t.y);
-}
-
-template <>
-void CacheKeySerializer<VkExtent2D>::Serialize(CacheKey* key, const VkExtent2D& t) {
- key->Record(t.width, t.height);
-}
-
-template <>
-void CacheKeySerializer<VkRect2D>::Serialize(CacheKey* key, const VkRect2D& t) {
- key->Record(t.offset, t.extent);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineViewportStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineViewportStateCreateInfo& t) {
- key->Record(t.flags)
- .RecordIterable(t.pViewports, t.viewportCount)
- .RecordIterable(t.pScissors, t.scissorCount);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineRasterizationStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineRasterizationStateCreateInfo& t) {
- key->Record(t.flags, t.depthClampEnable, t.rasterizerDiscardEnable, t.polygonMode, t.cullMode,
- t.frontFace, t.depthBiasEnable, t.depthBiasConstantFactor, t.depthBiasClamp,
- t.depthBiasSlopeFactor, t.lineWidth);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineMultisampleStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineMultisampleStateCreateInfo& t) {
- key->Record(t.flags, t.rasterizationSamples, t.sampleShadingEnable, t.minSampleShading,
- t.pSampleMask, t.alphaToCoverageEnable, t.alphaToOneEnable);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkStencilOpState>::Serialize(CacheKey* key, const VkStencilOpState& t) {
- key->Record(t.failOp, t.passOp, t.depthFailOp, t.compareOp, t.compareMask, t.writeMask,
- t.reference);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineDepthStencilStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineDepthStencilStateCreateInfo& t) {
- key->Record(t.flags, t.depthTestEnable, t.depthWriteEnable, t.depthCompareOp,
- t.depthBoundsTestEnable, t.stencilTestEnable, t.front, t.back, t.minDepthBounds,
- t.maxDepthBounds);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineColorBlendAttachmentState>::Serialize(
- CacheKey* key,
- const VkPipelineColorBlendAttachmentState& t) {
- key->Record(t.blendEnable, t.srcColorBlendFactor, t.dstColorBlendFactor, t.colorBlendOp,
- t.srcAlphaBlendFactor, t.dstAlphaBlendFactor, t.alphaBlendOp, t.colorWriteMask);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineColorBlendStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineColorBlendStateCreateInfo& t) {
- key->Record(t.flags, t.logicOpEnable, t.logicOp)
- .RecordIterable(t.pAttachments, t.attachmentCount)
- .Record(t.blendConstants);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<VkPipelineDynamicStateCreateInfo>::Serialize(
- CacheKey* key,
- const VkPipelineDynamicStateCreateInfo& t) {
- key->Record(t.flags).RecordIterable(t.pDynamicStates, t.dynamicStateCount);
- vulkan::SerializePnext<>(key, &t);
-}
-
-template <>
-void CacheKeySerializer<vulkan::RenderPassCacheQuery>::Serialize(
- CacheKey* key,
- const vulkan::RenderPassCacheQuery& t) {
- key->Record(t.colorMask.to_ulong(), t.resolveTargetMask.to_ulong(), t.sampleCount);
-
- // Manually iterate the color attachment indices and their corresponding format/load/store
- // ops because the data is sparse and may be uninitialized. Since we record the colorMask
- // member above, recording sparse data should be fine here.
- for (ColorAttachmentIndex i : IterateBitSet(t.colorMask)) {
- key->Record(t.colorFormats[i], t.colorLoadOp[i], t.colorStoreOp[i]);
- }
-
- // Serialize the depth-stencil toggle bit, and the parameters if applicable.
- key->Record(t.hasDepthStencil);
- if (t.hasDepthStencil) {
- key->Record(t.depthStencilFormat, t.depthLoadOp, t.depthStoreOp, t.stencilLoadOp,
- t.stencilStoreOp, t.readOnlyDepthStencil);
- }
-}
-
-template <>
-void CacheKeySerializer<VkGraphicsPipelineCreateInfo>::Serialize(
- CacheKey* key,
- const VkGraphicsPipelineCreateInfo& t) {
- // The pipeline layout and render pass are not serialized here because they are pointers to
- // backend objects. They need to be cross-referenced with the frontend objects and
- // serialized from there. The base pipeline information is also currently not recorded since
- // we do not use them in our backend implementation. If we decide to use them later on, they
- // also need to be cross-referenced from the frontend.
- key->Record(t.flags)
- .RecordIterable(t.pStages, t.stageCount)
- .Record(t.pVertexInputState, t.pInputAssemblyState, t.pTessellationState, t.pViewportState,
- t.pRasterizationState, t.pMultisampleState, t.pDepthStencilState,
- t.pColorBlendState, t.pDynamicState, t.subpass);
- vulkan::SerializePnext<>(key, &t);
-}
-
-} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.h b/chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.h
deleted file mode 100644
index 80b04dbd9a2..00000000000
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/CacheKeyVk.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_DAWN_NATIVE_VULKAN_CACHEKEYVK_H_
-#define SRC_DAWN_NATIVE_VULKAN_CACHEKEYVK_H_
-
-#include <map>
-
-#include "dawn/common/Assert.h"
-#include "dawn/common/vulkan_platform.h"
-#include "dawn/native/CacheKey.h"
-
-#include "icd/generated/vk_typemap_helper.h"
-
-namespace dawn::native::vulkan {
-
-namespace detail {
-
-template <typename... VK_STRUCT_TYPES>
-void ValidatePnextImpl(const VkBaseOutStructure* root) {
- const VkBaseOutStructure* next = reinterpret_cast<const VkBaseOutStructure*>(root->pNext);
- while (next != nullptr) {
- // Assert that the type of each pNext struct is exactly one of the specified
- // templates.
- ASSERT(((LvlTypeMap<VK_STRUCT_TYPES>::kSType == next->sType ? 1 : 0) + ... + 0) == 1);
- next = reinterpret_cast<const VkBaseOutStructure*>(next->pNext);
- }
-}
-
-template <typename VK_STRUCT_TYPE>
-void SerializePnextImpl(CacheKey* key, const VkBaseOutStructure* root) {
- const VkBaseOutStructure* next = reinterpret_cast<const VkBaseOutStructure*>(root->pNext);
- const VK_STRUCT_TYPE* found = nullptr;
- while (next != nullptr) {
- if (LvlTypeMap<VK_STRUCT_TYPE>::kSType == next->sType) {
- if (found == nullptr) {
- found = reinterpret_cast<const VK_STRUCT_TYPE*>(next);
- } else {
- // Fail an assert here since that means that the chain had more than one of
- // the same typed chained object.
- ASSERT(false);
- }
- }
- next = reinterpret_cast<const VkBaseOutStructure*>(next->pNext);
- }
- if (found != nullptr) {
- key->Record(found);
- }
-}
-
-template <typename VK_STRUCT_TYPE,
- typename... VK_STRUCT_TYPES,
- typename = std::enable_if_t<(sizeof...(VK_STRUCT_TYPES) > 0)>>
-void SerializePnextImpl(CacheKey* key, const VkBaseOutStructure* root) {
- SerializePnextImpl<VK_STRUCT_TYPE>(key, root);
- SerializePnextImpl<VK_STRUCT_TYPES...>(key, root);
-}
-
-template <typename VK_STRUCT_TYPE>
-const VkBaseOutStructure* ToVkBaseOutStructure(const VK_STRUCT_TYPE* t) {
- // Checks to ensure proper type safety.
- static_assert(offsetof(VK_STRUCT_TYPE, sType) == offsetof(VkBaseOutStructure, sType) &&
- offsetof(VK_STRUCT_TYPE, pNext) == offsetof(VkBaseOutStructure, pNext),
- "Argument type is not a proper Vulkan structure type");
- return reinterpret_cast<const VkBaseOutStructure*>(t);
-}
-
-} // namespace detail
-
-template <typename... VK_STRUCT_TYPES,
- typename VK_STRUCT_TYPE,
- typename = std::enable_if_t<(sizeof...(VK_STRUCT_TYPES) > 0)>>
-void SerializePnext(CacheKey* key, const VK_STRUCT_TYPE* t) {
- const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t);
- detail::ValidatePnextImpl<VK_STRUCT_TYPES...>(root);
- detail::SerializePnextImpl<VK_STRUCT_TYPES...>(key, root);
-}
-
-// Empty template specialization so that we can put this in to ensure failures occur if new
-// extensions are added without updating serialization.
-template <typename VK_STRUCT_TYPE>
-void SerializePnext(CacheKey* key, const VK_STRUCT_TYPE* t) {
- const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t);
- detail::ValidatePnextImpl<>(root);
-}
-
-} // namespace dawn::native::vulkan
-
-#endif // SRC_DAWN_NATIVE_VULKAN_CACHEKEYVK_H_
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.cpp
index fca86c2db72..a61a800d98d 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.cpp
@@ -377,12 +377,19 @@ void ResetUsedQuerySetsOnRenderPass(Device* device,
void RecordWriteTimestampCmd(CommandRecordingContext* recordingContext,
Device* device,
- WriteTimestampCmd* cmd) {
+ QuerySetBase* querySet,
+ uint32_t queryIndex,
+ bool isRenderPass) {
VkCommandBuffer commands = recordingContext->commandBuffer;
- QuerySet* querySet = ToBackend(cmd->querySet.Get());
+
+ // The queries must be reset between uses, and the reset command cannot be called in render
+ // pass.
+ if (!isRenderPass) {
+ device->fn.CmdResetQueryPool(commands, ToBackend(querySet)->GetHandle(), queryIndex, 1);
+ }
device->fn.CmdWriteTimestamp(commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
- querySet->GetHandle(), cmd->queryIndex);
+ ToBackend(querySet)->GetHandle(), queryIndex);
}
void RecordResolveQuerySetCmd(VkCommandBuffer commands,
@@ -735,10 +742,11 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* recordingConte
}
case Command::BeginComputePass: {
- mCommands.NextCommand<BeginComputePassCmd>();
+ BeginComputePassCmd* cmd = mCommands.NextCommand<BeginComputePassCmd>();
- DAWN_TRY(RecordComputePass(
- recordingContext, GetResourceUsages().computePasses[nextComputePassNumber]));
+ DAWN_TRY(
+ RecordComputePass(recordingContext, cmd,
+ GetResourceUsages().computePasses[nextComputePassNumber]));
nextComputePassNumber++;
break;
@@ -777,11 +785,8 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* recordingConte
case Command::WriteTimestamp: {
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
- // The query must be reset between uses.
- device->fn.CmdResetQueryPool(commands, ToBackend(cmd->querySet)->GetHandle(),
- cmd->queryIndex, 1);
-
- RecordWriteTimestampCmd(recordingContext, device, cmd);
+ RecordWriteTimestampCmd(recordingContext, device, cmd->querySet.Get(),
+ cmd->queryIndex, false);
break;
}
@@ -878,8 +883,17 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* recordingConte
}
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext,
+ BeginComputePassCmd* computePassCmd,
const ComputePassResourceUsage& resourceUsages) {
Device* device = ToBackend(GetDevice());
+
+ // Write timestamp at the beginning of compute pass if it's set
+ if (computePassCmd->beginTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(recordingContext, device,
+ computePassCmd->beginTimestamp.querySet.Get(),
+ computePassCmd->beginTimestamp.queryIndex, false);
+ }
+
VkCommandBuffer commands = recordingContext->commandBuffer;
uint64_t currentDispatch = 0;
@@ -890,6 +904,13 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingCo
switch (type) {
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
+
+ // Write timestamp at the end of compute pass if it's set.
+ if (computePassCmd->endTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(recordingContext, device,
+ computePassCmd->endTimestamp.querySet.Get(),
+ computePassCmd->endTimestamp.queryIndex, false);
+ }
return {};
}
@@ -996,11 +1017,8 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingCo
case Command::WriteTimestamp: {
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
- // The query must be reset between uses.
- device->fn.CmdResetQueryPool(commands, ToBackend(cmd->querySet)->GetHandle(),
- cmd->queryIndex, 1);
-
- RecordWriteTimestampCmd(recordingContext, device, cmd);
+ RecordWriteTimestampCmd(recordingContext, device, cmd->querySet.Get(),
+ cmd->queryIndex, false);
break;
}
@@ -1020,6 +1038,13 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingCon
DAWN_TRY(RecordBeginRenderPass(recordingContext, device, renderPassCmd));
+ // Write timestamp at the beginning of render pass if it's set.
+ if (renderPassCmd->beginTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(recordingContext, device,
+ renderPassCmd->beginTimestamp.querySet.Get(),
+ renderPassCmd->beginTimestamp.queryIndex, true);
+ }
+
// Set the default value for the dynamic state
{
device->fn.CmdSetLineWidth(commands, 1.0f);
@@ -1203,6 +1228,14 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingCon
switch (type) {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
+
+ // Write timestamp at the end of render pass if it's set.
+ if (renderPassCmd->endTimestamp.querySet.Get() != nullptr) {
+ RecordWriteTimestampCmd(recordingContext, device,
+ renderPassCmd->endTimestamp.querySet.Get(),
+ renderPassCmd->endTimestamp.queryIndex, true);
+ }
+
device->fn.CmdEndRenderPass(commands);
return {};
}
@@ -1290,7 +1323,8 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingCon
case Command::WriteTimestamp: {
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
- RecordWriteTimestampCmd(recordingContext, device, cmd);
+ RecordWriteTimestampCmd(recordingContext, device, cmd->querySet.Get(),
+ cmd->queryIndex, true);
break;
}
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.h b/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.h
index dbb7fdcd7f5..b748f0daac7 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.h
@@ -21,6 +21,7 @@
#include "dawn/common/vulkan_platform.h"
namespace dawn::native {
+struct BeginComputePassCmd;
struct BeginRenderPassCmd;
struct TextureCopy;
} // namespace dawn::native
@@ -41,6 +42,7 @@ class CommandBuffer final : public CommandBufferBase {
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
MaybeError RecordComputePass(CommandRecordingContext* recordingContext,
+ BeginComputePassCmd* computePass,
const ComputePassResourceUsage& resourceUsages);
MaybeError RecordRenderPass(CommandRecordingContext* recordingContext,
BeginRenderPassCmd* renderPass);
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/CommandRecordingContext.h b/chromium/third_party/dawn/src/dawn/native/vulkan/CommandRecordingContext.h
index b5ced101ebb..ab43ae2d71b 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/CommandRecordingContext.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/CommandRecordingContext.h
@@ -14,23 +14,30 @@
#ifndef SRC_DAWN_NATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_
#define SRC_DAWN_NATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_
+#include <set>
#include <vector>
#include "dawn/common/vulkan_platform.h"
#include "dawn/native/vulkan/BufferVk.h"
namespace dawn::native::vulkan {
+
+class Texture;
+
// Used to track operations that are handled after recording.
// Currently only tracks semaphores, but may be used to do barrier coalescing in the future.
struct CommandRecordingContext {
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
std::vector<VkSemaphore> waitSemaphores = {};
- std::vector<VkSemaphore> signalSemaphores = {};
// The internal buffers used in the workaround of texture-to-texture copies with compressed
// formats.
std::vector<Ref<Buffer>> tempBuffers;
+ // External textures that will be eagerly transitioned just before VkSubmit. The textures are
+ // kept alive by the CommandBuffer so they don't need to be Ref-ed.
+ std::set<Texture*> externalTexturesForEagerTransition;
+
// For Device state tracking only.
VkCommandPool commandPool = VK_NULL_HANDLE;
bool used = false;
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/ComputePipelineVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/ComputePipelineVk.cpp
index 21937981dd3..ad6fbf8410c 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/ComputePipelineVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/ComputePipelineVk.cpp
@@ -41,7 +41,7 @@ MaybeError ComputePipeline::Initialize() {
const PipelineLayout* layout = ToBackend(GetLayout());
// Vulkan devices need cache UUID field to be serialized into pipeline cache keys.
- mCacheKey.Record(device->GetDeviceInfo().properties.pipelineCacheUUID);
+ StreamIn(&mCacheKey, device->GetDeviceInfo().properties.pipelineCacheUUID);
VkComputePipelineCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
@@ -58,13 +58,15 @@ MaybeError ComputePipeline::Initialize() {
// Generate a new VkShaderModule with BindingRemapper tint transform for each pipeline
const ProgrammableStage& computeStage = GetStage(SingleShaderStage::Compute);
ShaderModule* module = ToBackend(computeStage.module.Get());
- const ShaderModule::Spirv* spirv;
- DAWN_TRY_ASSIGN((std::tie(createInfo.stage.module, spirv)),
+
+ ShaderModule::ModuleAndSpirv moduleAndSpirv;
+ DAWN_TRY_ASSIGN(moduleAndSpirv,
module->GetHandleAndSpirv(computeStage.entryPoint.c_str(), layout));
+ createInfo.stage.module = moduleAndSpirv.module;
createInfo.stage.pName = computeStage.entryPoint.c_str();
- std::vector<OverridableConstantScalar> specializationDataEntries;
+ std::vector<OverrideScalar> specializationDataEntries;
std::vector<VkSpecializationMapEntry> specializationMapEntries;
VkSpecializationInfo specializationInfo{};
createInfo.stage.pSpecializationInfo = GetVkSpecializationInfo(
@@ -83,7 +85,8 @@ MaybeError ComputePipeline::Initialize() {
}
// Record cache key information now since the createInfo is not stored.
- mCacheKey.Record(createInfo, layout).RecordIterable(*spirv);
+ StreamIn(&mCacheKey, createInfo, layout,
+ stream::Iterable(moduleAndSpirv.spirv, moduleAndSpirv.wordCount));
// Try to see if we have anything in the blob cache.
Ref<PipelineCache> cache = ToBackend(GetDevice()->GetOrCreatePipelineCache(GetCacheKey()));
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.cpp
index 3605dc027df..662fa5a1cd6 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.cpp
@@ -15,6 +15,7 @@
#include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/common/Log.h"
+#include "dawn/common/NonCopyable.h"
#include "dawn/common/Platform.h"
#include "dawn/native/BackendConnection.h"
#include "dawn/native/ChainUtils_autogen.h"
@@ -47,6 +48,35 @@
namespace dawn::native::vulkan {
+namespace {
+
+// Destroy the semaphore when out of scope.
+class ScopedSignalSemaphore : public NonMovable {
+ public:
+ ScopedSignalSemaphore(Device* device, VkSemaphore semaphore)
+ : mDevice(device), mSemaphore(semaphore) {}
+ ~ScopedSignalSemaphore() {
+ if (mSemaphore != VK_NULL_HANDLE) {
+ ASSERT(mDevice);
+ mDevice->fn.DestroySemaphore(mDevice->GetVkDevice(), mSemaphore, nullptr);
+ }
+ }
+
+ VkSemaphore Get() { return mSemaphore; }
+ VkSemaphore Detach() {
+ VkSemaphore semaphore = mSemaphore;
+ mSemaphore = VK_NULL_HANDLE;
+ return semaphore;
+ }
+ VkSemaphore* InitializeInto() { return &mSemaphore; }
+
+ private:
+ Device* mDevice = nullptr;
+ VkSemaphore mSemaphore = VK_NULL_HANDLE;
+};
+
+} // namespace
+
// static
ResultOrError<Ref<Device>> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) {
Ref<Device> device = AcquireRef(new Device(adapter, descriptor));
@@ -245,6 +275,10 @@ ResourceMemoryAllocator* Device::GetResourceMemoryAllocator() const {
return mResourceMemoryAllocator.get();
}
+external_semaphore::Service* Device::GetExternalSemaphoreService() const {
+ return mExternalSemaphoreService.get();
+}
+
void Device::EnqueueDeferredDeallocation(DescriptorSetAllocator* allocator) {
mDescriptorAllocatorsPendingDeallocation.Enqueue(allocator, GetPendingCommandSerial());
}
@@ -260,6 +294,19 @@ MaybeError Device::SubmitPendingCommands() {
return {};
}
+ ScopedSignalSemaphore scopedSignalSemaphore(this, VK_NULL_HANDLE);
+ if (mRecordingContext.externalTexturesForEagerTransition.size() > 0) {
+ // Create an external semaphore for all external textures that have been used in the pending
+ // submit.
+ DAWN_TRY_ASSIGN(*scopedSignalSemaphore.InitializeInto(),
+ mExternalSemaphoreService->CreateExportableSemaphore());
+ }
+
+ // Transition eagerly all used external textures for export.
+ for (auto* texture : mRecordingContext.externalTexturesForEagerTransition) {
+ texture->TransitionEagerlyForExport(&mRecordingContext);
+ }
+
DAWN_TRY(
CheckVkSuccess(fn.EndCommandBuffer(mRecordingContext.commandBuffer), "vkEndCommandBuffer"));
@@ -274,9 +321,8 @@ MaybeError Device::SubmitPendingCommands() {
submitInfo.pWaitDstStageMask = dstStageMasks.data();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &mRecordingContext.commandBuffer;
- submitInfo.signalSemaphoreCount =
- static_cast<uint32_t>(mRecordingContext.signalSemaphores.size());
- submitInfo.pSignalSemaphores = AsVkArray(mRecordingContext.signalSemaphores.data());
+ submitInfo.signalSemaphoreCount = (scopedSignalSemaphore.Get() == VK_NULL_HANDLE ? 0 : 1);
+ submitInfo.pSignalSemaphores = AsVkArray(scopedSignalSemaphore.InitializeInto());
VkFence fence = VK_NULL_HANDLE;
DAWN_TRY_ASSIGN(fence, GetUnusedFence());
@@ -293,10 +339,6 @@ MaybeError Device::SubmitPendingCommands() {
for (VkSemaphore semaphore : mRecordingContext.waitSemaphores) {
mDeleter->DeleteWhenUnused(semaphore);
}
- for (VkSemaphore semaphore : mRecordingContext.signalSemaphores) {
- mDeleter->DeleteWhenUnused(semaphore);
- }
-
IncrementLastSubmittedCommandSerial();
ExecutionSerial lastSubmittedSerial = GetLastSubmittedCommandSerial();
mFencesInFlight.emplace(fence, lastSubmittedSerial);
@@ -304,6 +346,26 @@ MaybeError Device::SubmitPendingCommands() {
CommandPoolAndBuffer submittedCommands = {mRecordingContext.commandPool,
mRecordingContext.commandBuffer};
mCommandsInFlight.Enqueue(submittedCommands, lastSubmittedSerial);
+
+ if (mRecordingContext.externalTexturesForEagerTransition.size() > 0) {
+ // Export the signal semaphore.
+ ExternalSemaphoreHandle semaphoreHandle;
+ DAWN_TRY_ASSIGN(semaphoreHandle,
+ mExternalSemaphoreService->ExportSemaphore(scopedSignalSemaphore.Get()));
+ // The ownership of signal semaphore has been transferred, we no longer need to track it.
+ scopedSignalSemaphore.Detach();
+ // Update all external textures, eagerly transitioned in the submit, with the exported
+ // handle, and the duplicated handles.
+ bool first = true;
+ for (auto* texture : mRecordingContext.externalTexturesForEagerTransition) {
+ ExternalSemaphoreHandle handle =
+ (first ? semaphoreHandle
+ : mExternalSemaphoreService->DuplicateHandle(semaphoreHandle));
+ first = false;
+ texture->UpdateExternalSemaphoreHandle(handle);
+ }
+ }
+
mRecordingContext = CommandRecordingContext();
DAWN_TRY(PrepareRecordingContext());
@@ -409,6 +471,16 @@ ResultOrError<VulkanDeviceKnobs> Device::CreateDevice(VkPhysicalDevice physicalD
usedKnobs.features.pipelineStatisticsQuery = VK_TRUE;
}
+ if (IsFeatureEnabled(Feature::DepthClipControl)) {
+ const VulkanDeviceInfo& deviceInfo = ToBackend(GetAdapter())->GetDeviceInfo();
+ ASSERT(deviceInfo.HasExt(DeviceExt::DepthClipEnable) &&
+ deviceInfo.depthClipEnableFeatures.depthClipEnable == VK_TRUE);
+
+ usedKnobs.depthClipEnableFeatures.depthClipEnable = VK_TRUE;
+ featuresChain.Add(&usedKnobs.depthClipEnableFeatures,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT);
+ }
+
if (IsFeatureEnabled(Feature::ShaderFloat16)) {
const VulkanDeviceInfo& deviceInfo = ToBackend(GetAdapter())->GetDeviceInfo();
ASSERT(deviceInfo.HasExt(DeviceExt::ShaderFloat16Int8) &&
@@ -427,11 +499,6 @@ ResultOrError<VulkanDeviceKnobs> Device::CreateDevice(VkPhysicalDevice physicalD
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES);
}
- if (IsFeatureEnabled(Feature::DepthClamping)) {
- ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.depthClamp == VK_TRUE);
- usedKnobs.features.depthClamp = VK_TRUE;
- }
-
// Find a universal queue family
{
// Note that GRAPHICS and COMPUTE imply TRANSFER so we don't need to check for it.
@@ -765,7 +832,6 @@ MaybeError Device::ImportExternalImage(const ExternalImageDescriptorVk* descript
ExternalMemoryHandle memoryHandle,
VkImage image,
const std::vector<ExternalSemaphoreHandle>& waitHandles,
- VkSemaphore* outSignalSemaphore,
VkDeviceMemory* outAllocation,
std::vector<VkSemaphore>* outWaitSemaphores) {
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
@@ -789,9 +855,6 @@ MaybeError Device::ImportExternalImage(const ExternalImageDescriptorVk* descript
VK_IMAGE_CREATE_ALIAS_BIT_KHR),
"External memory usage not supported");
- // Create an external semaphore to signal when the texture is done being used
- DAWN_TRY_ASSIGN(*outSignalSemaphore, mExternalSemaphoreService->CreateExportableSemaphore());
-
// Import the external image's memory
external_memory::MemoryImportParams importParams;
DAWN_TRY_ASSIGN(importParams, mExternalMemoryService->GetMemoryImportParams(descriptor, image));
@@ -816,15 +879,12 @@ bool Device::SignalAndExportExternalTexture(
return !ConsumedError([&]() -> MaybeError {
DAWN_TRY(ValidateObject(texture));
- VkSemaphore signalSemaphore;
+ ExternalSemaphoreHandle semaphoreHandle;
VkImageLayout releasedOldLayout;
VkImageLayout releasedNewLayout;
- DAWN_TRY(texture->ExportExternalTexture(desiredLayout, &signalSemaphore, &releasedOldLayout,
+ DAWN_TRY(texture->ExportExternalTexture(desiredLayout, &semaphoreHandle, &releasedOldLayout,
&releasedNewLayout));
- ExternalSemaphoreHandle semaphoreHandle;
- DAWN_TRY_ASSIGN(semaphoreHandle,
- mExternalSemaphoreService->ExportSemaphore(signalSemaphore));
semaphoreHandles->push_back(semaphoreHandle);
info->releasedOldLayout = releasedOldLayout;
info->releasedNewLayout = releasedNewLayout;
@@ -851,7 +911,6 @@ TextureBase* Device::CreateTextureWrappingVulkanImage(
return nullptr;
}
- VkSemaphore signalSemaphore = VK_NULL_HANDLE;
VkDeviceMemory allocation = VK_NULL_HANDLE;
std::vector<VkSemaphore> waitSemaphores;
waitSemaphores.reserve(waitHandles.size());
@@ -864,18 +923,13 @@ TextureBase* Device::CreateTextureWrappingVulkanImage(
mExternalMemoryService.get()),
&result) ||
ConsumedError(ImportExternalImage(descriptor, memoryHandle, result->GetHandle(),
- waitHandles, &signalSemaphore, &allocation,
- &waitSemaphores)) ||
- ConsumedError(
- result->BindExternalMemory(descriptor, signalSemaphore, allocation, waitSemaphores))) {
+ waitHandles, &allocation, &waitSemaphores)) ||
+ ConsumedError(result->BindExternalMemory(descriptor, allocation, waitSemaphores))) {
// Delete the Texture if it was created
if (result != nullptr) {
result->Release();
}
- // Clear the signal semaphore
- fn.DestroySemaphore(GetVkDevice(), signalSemaphore, nullptr);
-
// Clear image memory
fn.FreeMemory(GetVkDevice(), allocation, nullptr);
@@ -1010,11 +1064,6 @@ void Device::DestroyImpl() {
}
mRecordingContext.waitSemaphores.clear();
- for (VkSemaphore semaphore : mRecordingContext.signalSemaphores) {
- fn.DestroySemaphore(mVkDevice, semaphore, nullptr);
- }
- mRecordingContext.signalSemaphores.clear();
-
// Some commands might still be marked as in-flight if we shut down because of a device
// loss. Recycle them as unused so that we free them below.
RecycleCompletedCommands();
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.h b/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.h
index b0638379bc6..6e88d4cf864 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/DeviceVk.h
@@ -61,6 +61,7 @@ class Device final : public DeviceBase {
FencedDeleter* GetFencedDeleter() const;
RenderPassCache* GetRenderPassCache() const;
ResourceMemoryAllocator* GetResourceMemoryAllocator() const;
+ external_semaphore::Service* GetExternalSemaphoreService() const;
CommandRecordingContext* GetPendingRecordingContext();
MaybeError SubmitPendingCommands();
@@ -216,7 +217,6 @@ class Device final : public DeviceBase {
ExternalMemoryHandle memoryHandle,
VkImage image,
const std::vector<ExternalSemaphoreHandle>& waitHandles,
- VkSemaphore* outSignalSemaphore,
VkDeviceMemory* outAllocation,
std::vector<VkSemaphore>* outWaitSemaphores);
};
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/ExternalHandle.h b/chromium/third_party/dawn/src/dawn/native/vulkan/ExternalHandle.h
index c2d1433e4ca..7b3ed9d291c 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/ExternalHandle.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/ExternalHandle.h
@@ -24,15 +24,18 @@ namespace dawn::native::vulkan {
using ExternalMemoryHandle = int;
// File descriptor
using ExternalSemaphoreHandle = int;
+const ExternalSemaphoreHandle kNullExternalSemaphoreHandle = -1;
#elif DAWN_PLATFORM_IS(FUCHSIA)
// Really a Zircon vmo handle.
using ExternalMemoryHandle = zx_handle_t;
// Really a Zircon event handle.
using ExternalSemaphoreHandle = zx_handle_t;
+const ExternalSemaphoreHandle kNullExternalSemaphoreHandle = ZX_HANDLE_INVALID;
#else
// Generic types so that the Null service can compile, not used for real handles
using ExternalMemoryHandle = void*;
using ExternalSemaphoreHandle = void*;
+const ExternalSemaphoreHandle kNullExternalSemaphoreHandle = nullptr;
#endif
} // namespace dawn::native::vulkan
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.cpp
index 48ffc0f0008..a47c4eda27d 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.cpp
@@ -56,7 +56,7 @@ MaybeError PipelineLayout::Initialize() {
createInfo.pPushConstantRanges = nullptr;
// Record cache key information now since the createInfo is not stored.
- mCacheKey.RecordIterable(cachedObjects.data(), numSetLayouts).Record(createInfo);
+ StreamIn(&mCacheKey, stream::Iterable(cachedObjects.data(), numSetLayouts), createInfo);
Device* device = ToBackend(GetDevice());
DAWN_TRY(CheckVkSuccess(
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.h b/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.h
index ca157f8d3d1..2b8f5cf72ab 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/PipelineLayoutVk.h
@@ -31,6 +31,11 @@ class PipelineLayout final : public PipelineLayoutBase {
VkPipelineLayout GetHandle() const;
+ // Friend definition of StreamIn which can be found by ADL to override stream::StreamIn<T>.
+ friend void StreamIn(stream::Sink* sink, const PipelineLayout& obj) {
+ StreamIn(sink, static_cast<const CachedObject&>(obj));
+ }
+
private:
~PipelineLayout() override;
void DestroyImpl() override;
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/RenderPipelineVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/RenderPipelineVk.cpp
index 47c3c850769..372abb515b7 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/RenderPipelineVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/RenderPipelineVk.cpp
@@ -40,8 +40,9 @@ VkVertexInputRate VulkanInputRate(wgpu::VertexStepMode stepMode) {
case wgpu::VertexStepMode::Instance:
return VK_VERTEX_INPUT_RATE_INSTANCE;
case wgpu::VertexStepMode::VertexBufferNotUsed:
- UNREACHABLE();
+ break;
}
+ UNREACHABLE();
}
VkFormat VulkanVertexFormat(wgpu::VertexFormat format) {
@@ -336,11 +337,11 @@ MaybeError RenderPipeline::Initialize() {
const PipelineLayout* layout = ToBackend(GetLayout());
// Vulkan devices need cache UUID field to be serialized into pipeline cache keys.
- mCacheKey.Record(device->GetDeviceInfo().properties.pipelineCacheUUID);
+ StreamIn(&mCacheKey, device->GetDeviceInfo().properties.pipelineCacheUUID);
// There are at most 2 shader stages in render pipeline, i.e. vertex and fragment
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
- std::array<std::vector<OverridableConstantScalar>, 2> specializationDataEntriesPerStages;
+ std::array<std::vector<OverrideScalar>, 2> specializationDataEntriesPerStages;
std::array<std::vector<VkSpecializationMapEntry>, 2> specializationMapEntriesPerStages;
std::array<VkSpecializationInfo, 2> specializationInfoPerStages;
uint32_t stageCount = 0;
@@ -350,10 +351,12 @@ MaybeError RenderPipeline::Initialize() {
const ProgrammableStage& programmableStage = GetStage(stage);
ShaderModule* module = ToBackend(programmableStage.module.Get());
- const ShaderModule::Spirv* spirv;
- DAWN_TRY_ASSIGN(std::tie(shaderStage.module, spirv),
+
+ ShaderModule::ModuleAndSpirv moduleAndSpirv;
+ DAWN_TRY_ASSIGN(moduleAndSpirv,
module->GetHandleAndSpirv(programmableStage.entryPoint.c_str(), layout));
+ shaderStage.module = moduleAndSpirv.module;
shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStage.pNext = nullptr;
shaderStage.flags = 0;
@@ -386,7 +389,7 @@ MaybeError RenderPipeline::Initialize() {
stageCount++;
// Record cache key for each shader since it will become inaccessible later on.
- mCacheKey.Record(stage).RecordIterable(*spirv);
+ StreamIn(&mCacheKey, stream::Iterable(moduleAndSpirv.spirv, moduleAndSpirv.wordCount));
}
PipelineVertexInputStateCreateInfoTemporaryAllocations tempAllocations;
@@ -427,7 +430,7 @@ MaybeError RenderPipeline::Initialize() {
rasterization.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterization.pNext = nullptr;
rasterization.flags = 0;
- rasterization.depthClampEnable = ShouldClampDepth() ? VK_TRUE : VK_FALSE;
+ rasterization.depthClampEnable = VK_FALSE;
rasterization.rasterizerDiscardEnable = VK_FALSE;
rasterization.polygonMode = VK_POLYGON_MODE_FILL;
rasterization.cullMode = VulkanCullMode(GetCullMode());
@@ -438,6 +441,18 @@ MaybeError RenderPipeline::Initialize() {
rasterization.depthBiasSlopeFactor = GetDepthBiasSlopeScale();
rasterization.lineWidth = 1.0f;
+ PNextChainBuilder rasterizationChain(&rasterization);
+ VkPipelineRasterizationDepthClipStateCreateInfoEXT depthClipState;
+ if (HasUnclippedDepth()) {
+ ASSERT(device->IsFeatureEnabled(Feature::DepthClipControl));
+ depthClipState.pNext = nullptr;
+ depthClipState.depthClipEnable = VK_FALSE;
+ depthClipState.flags = 0;
+ rasterizationChain.Add(
+ &depthClipState,
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT);
+ }
+
VkPipelineMultisampleStateCreateInfo multisample;
multisample.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisample.pNext = nullptr;
@@ -533,7 +548,7 @@ MaybeError RenderPipeline::Initialize() {
query.SetSampleCount(GetSampleCount());
- mCacheKey.Record(query);
+ StreamIn(&mCacheKey, query);
DAWN_TRY_ASSIGN(renderPass, device->GetRenderPassCache()->GetRenderPass(query));
}
@@ -562,7 +577,7 @@ MaybeError RenderPipeline::Initialize() {
createInfo.basePipelineIndex = -1;
// Record cache key information now since createInfo is not stored.
- mCacheKey.Record(createInfo, layout->GetCacheKey());
+ StreamIn(&mCacheKey, createInfo, layout->GetCacheKey());
// Try to see if we have anything in the blob cache.
Ref<PipelineCache> cache = ToBackend(GetDevice()->GetOrCreatePipelineCache(GetCacheKey()));
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.cpp
index 28e295dfa88..5477d84784c 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -17,7 +17,10 @@
#include <spirv-tools/libspirv.hpp>
#include <map>
+#include <string>
+#include <vector>
+#include "dawn/native/CacheRequest.h"
#include "dawn/native/SpirvValidation.h"
#include "dawn/native/TintUtils.h"
#include "dawn/native/vulkan/BindGroupLayoutVk.h"
@@ -32,6 +35,50 @@
namespace dawn::native::vulkan {
+// Spirv is a wrapper around Blob that exposes the data as uint32_t words.
+class ShaderModule::Spirv : private Blob {
+ public:
+ static Spirv FromBlob(Blob&& blob) {
+ // Vulkan drivers expect the SPIRV to be aligned like an array of uint32_t values.
+ blob.AlignTo(alignof(uint32_t));
+ return static_cast<Spirv&&>(blob);
+ }
+
+ const Blob& ToBlob() const { return *this; }
+
+ static Spirv Create(std::vector<uint32_t> code) {
+ Blob blob = CreateBlob(std::move(code));
+ ASSERT(IsPtrAligned(blob.Data(), alignof(uint32_t)));
+ return static_cast<Spirv&&>(std::move(blob));
+ }
+
+ const uint32_t* Code() const { return reinterpret_cast<const uint32_t*>(Data()); }
+ size_t WordCount() const { return Size() / sizeof(uint32_t); }
+};
+
+} // namespace dawn::native::vulkan
+
+namespace dawn::native::vulkan {
+
+class ShaderModule::ConcurrentTransformedShaderModuleCache {
+ public:
+ explicit ConcurrentTransformedShaderModuleCache(Device* device);
+ ~ConcurrentTransformedShaderModuleCache();
+
+ std::optional<ModuleAndSpirv> Find(const PipelineLayoutEntryPointPair& key);
+ ModuleAndSpirv AddOrGet(const PipelineLayoutEntryPointPair& key,
+ VkShaderModule module,
+ Spirv&& spirv);
+
+ private:
+ using Entry = std::pair<VkShaderModule, Spirv>;
+
+ Device* mDevice;
+ std::mutex mMutex;
+ std::unordered_map<PipelineLayoutEntryPointPair, Entry, PipelineLayoutEntryPointPairHashFunc>
+ mTransformedShaderModuleCache;
+};
+
ShaderModule::ConcurrentTransformedShaderModuleCache::ConcurrentTransformedShaderModuleCache(
Device* device)
: mDevice(device) {}
@@ -49,7 +96,11 @@ ShaderModule::ConcurrentTransformedShaderModuleCache::Find(
std::lock_guard<std::mutex> lock(mMutex);
auto iter = mTransformedShaderModuleCache.find(key);
if (iter != mTransformedShaderModuleCache.end()) {
- return std::make_pair(iter->second.first, iter->second.second.get());
+ return ModuleAndSpirv{
+ iter->second.first,
+ iter->second.second.Code(),
+ iter->second.second.WordCount(),
+ };
}
return {};
}
@@ -57,19 +108,22 @@ ShaderModule::ConcurrentTransformedShaderModuleCache::Find(
ShaderModule::ModuleAndSpirv ShaderModule::ConcurrentTransformedShaderModuleCache::AddOrGet(
const PipelineLayoutEntryPointPair& key,
VkShaderModule module,
- std::vector<uint32_t>&& spirv) {
+ Spirv&& spirv) {
ASSERT(module != VK_NULL_HANDLE);
std::lock_guard<std::mutex> lock(mMutex);
auto iter = mTransformedShaderModuleCache.find(key);
if (iter == mTransformedShaderModuleCache.end()) {
- mTransformedShaderModuleCache.emplace(
- key, std::make_pair(module, std::unique_ptr<Spirv>(new Spirv(spirv))));
+ mTransformedShaderModuleCache.emplace(key, std::make_pair(module, std::move(spirv)));
} else {
mDevice->GetFencedDeleter()->DeleteWhenUnused(module);
}
// Now the key should exist in the map, so find it again and return it.
iter = mTransformedShaderModuleCache.find(key);
- return std::make_pair(iter->second.first, iter->second.second.get());
+ return ModuleAndSpirv{
+ iter->second.first,
+ iter->second.second.Code(),
+ iter->second.second.WordCount(),
+ };
}
// static
@@ -114,6 +168,18 @@ void ShaderModule::DestroyImpl() {
ShaderModule::~ShaderModule() = default;
+#define SPIRV_COMPILATION_REQUEST_MEMBERS(X) \
+ X(const tint::Program*, inputProgram) \
+ X(tint::transform::BindingRemapper::BindingPoints, bindingPoints) \
+ X(tint::transform::MultiplanarExternalTexture::BindingsMap, newBindingsMap) \
+ X(std::string_view, entryPointName) \
+ X(bool, disableWorkgroupInit) \
+ X(bool, useZeroInitializeWorkgroupMemoryExtension) \
+ X(CacheKey::UnsafeUnkeyedValue<dawn::platform::Platform*>, tracePlatform)
+
+DAWN_MAKE_CACHE_REQUEST(SpirvCompilationRequest, SPIRV_COMPILATION_REQUEST_MEMBERS);
+#undef SPIRV_COMPILATION_REQUEST_MEMBERS
+
ResultOrError<ShaderModule::ModuleAndSpirv> ShaderModule::GetHandleAndSpirv(
const char* entryPointName,
const PipelineLayout* layout) {
@@ -137,15 +203,13 @@ ResultOrError<ShaderModule::ModuleAndSpirv> ShaderModule::GetHandleAndSpirv(
using BindingRemapper = tint::transform::BindingRemapper;
using BindingPoint = tint::transform::BindingPoint;
BindingRemapper::BindingPoints bindingPoints;
- BindingRemapper::AccessControls accessControls;
const BindingInfoArray& moduleBindingInfo = GetEntryPoint(entryPointName).bindings;
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
const auto& groupBindingInfo = moduleBindingInfo[group];
- for (const auto& it : groupBindingInfo) {
- BindingNumber binding = it.first;
+ for (const auto& [binding, _] : groupBindingInfo) {
BindingIndex bindingIndex = bgl->GetBindingIndex(binding);
BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
static_cast<uint32_t>(binding)};
@@ -158,79 +222,84 @@ ResultOrError<ShaderModule::ModuleAndSpirv> ShaderModule::GetHandleAndSpirv(
}
}
- tint::transform::Manager transformManager;
- // Many Vulkan drivers can't handle multi-entrypoint shader modules.
- transformManager.append(std::make_unique<tint::transform::SingleEntryPoint>());
- // Run the binding remapper after SingleEntryPoint to avoid collisions with unused entryPoints.
- transformManager.append(std::make_unique<tint::transform::BindingRemapper>());
-
- tint::transform::DataMap transformInputs;
- transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
- transformInputs.Add<BindingRemapper::Remappings>(std::move(bindingPoints),
- std::move(accessControls),
- /* mayCollide */ false);
-
// Transform external textures into the binding locations specified in the bgl
- // TODO(dawn:1082): Replace this block with ShaderModuleBase::AddExternalTextureTransform.
+ // TODO(dawn:1082): Replace this block with BuildExternalTextureTransformBindings.
tint::transform::MultiplanarExternalTexture::BindingsMap newBindingsMap;
for (BindGroupIndex i : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(i);
- ExternalTextureBindingExpansionMap expansions =
- bgl->GetExternalTextureBindingExpansionMap();
-
- std::map<BindingNumber, dawn_native::ExternalTextureBindingExpansion>::iterator it =
- expansions.begin();
-
- while (it != expansions.end()) {
+ for (const auto& [_, expansion] : bgl->GetExternalTextureBindingExpansionMap()) {
newBindingsMap[{static_cast<uint32_t>(i),
- static_cast<uint32_t>(bgl->GetBindingIndex(it->second.plane0))}] = {
+ static_cast<uint32_t>(bgl->GetBindingIndex(expansion.plane0))}] = {
{static_cast<uint32_t>(i),
- static_cast<uint32_t>(bgl->GetBindingIndex(it->second.plane1))},
+ static_cast<uint32_t>(bgl->GetBindingIndex(expansion.plane1))},
{static_cast<uint32_t>(i),
- static_cast<uint32_t>(bgl->GetBindingIndex(it->second.params))}};
- it++;
+ static_cast<uint32_t>(bgl->GetBindingIndex(expansion.params))}};
}
}
- if (!newBindingsMap.empty()) {
- transformManager.Add<tint::transform::MultiplanarExternalTexture>();
- transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
- newBindingsMap);
- }
-
- tint::Program program;
- {
- TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms");
- DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(), transformInputs,
- nullptr, nullptr));
- }
-
#if TINT_BUILD_SPV_WRITER
- tint::writer::spirv::Options options;
- options.emit_vertex_point_size = true;
- options.disable_workgroup_init = GetDevice()->IsToggleEnabled(Toggle::DisableWorkgroupInit);
- options.use_zero_initialize_workgroup_memory_extension =
+ SpirvCompilationRequest req = {};
+ req.inputProgram = GetTintProgram();
+ req.bindingPoints = std::move(bindingPoints);
+ req.newBindingsMap = std::move(newBindingsMap);
+ req.entryPointName = entryPointName;
+ req.disableWorkgroupInit = GetDevice()->IsToggleEnabled(Toggle::DisableWorkgroupInit);
+ req.useZeroInitializeWorkgroupMemoryExtension =
GetDevice()->IsToggleEnabled(Toggle::VulkanUseZeroInitializeWorkgroupMemoryExtension);
+ req.tracePlatform = UnsafeUnkeyedValue(GetDevice()->GetPlatform());
+
+ CacheResult<Spirv> spirv;
+ DAWN_TRY_LOAD_OR_RUN(
+ spirv, GetDevice(), std::move(req), Spirv::FromBlob,
+ [](SpirvCompilationRequest r) -> ResultOrError<Spirv> {
+ tint::transform::Manager transformManager;
+ // Many Vulkan drivers can't handle multi-entrypoint shader modules.
+ transformManager.append(std::make_unique<tint::transform::SingleEntryPoint>());
+ // Run the binding remapper after SingleEntryPoint to avoid collisions with
+ // unused entryPoints.
+ transformManager.append(std::make_unique<tint::transform::BindingRemapper>());
+ tint::transform::DataMap transformInputs;
+ transformInputs.Add<tint::transform::SingleEntryPoint::Config>(
+ std::string(r.entryPointName));
+ transformInputs.Add<BindingRemapper::Remappings>(std::move(r.bindingPoints),
+ BindingRemapper::AccessControls{},
+ /* mayCollide */ false);
+ if (!r.newBindingsMap.empty()) {
+ transformManager.Add<tint::transform::MultiplanarExternalTexture>();
+ transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
+ r.newBindingsMap);
+ }
+ tint::Program program;
+ {
+ TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "RunTransforms");
+ DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, r.inputProgram,
+ transformInputs, nullptr, nullptr));
+ }
+ tint::writer::spirv::Options options;
+ options.emit_vertex_point_size = true;
+ options.disable_workgroup_init = r.disableWorkgroupInit;
+ options.use_zero_initialize_workgroup_memory_extension =
+ r.useZeroInitializeWorkgroupMemoryExtension;
- Spirv spirv;
- {
- TRACE_EVENT0(GetDevice()->GetPlatform(), General, "tint::writer::spirv::Generate()");
- auto result = tint::writer::spirv::Generate(&program, options);
- DAWN_INVALID_IF(!result.success, "An error occured while generating SPIR-V: %s.",
- result.error);
+ TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General,
+ "tint::writer::spirv::Generate()");
+ auto result = tint::writer::spirv::Generate(&program, options);
+ DAWN_INVALID_IF(!result.success, "An error occured while generating SPIR-V: %s.",
+ result.error);
- spirv = std::move(result.spirv);
- }
+ return Spirv::Create(std::move(result.spirv));
+ });
- DAWN_TRY(ValidateSpirv(GetDevice(), spirv, GetDevice()->IsToggleEnabled(Toggle::DumpShaders)));
+ DAWN_TRY(ValidateSpirv(GetDevice(), spirv->Code(), spirv->WordCount(),
+ GetDevice()->IsToggleEnabled(Toggle::DumpShaders)));
VkShaderModuleCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
- createInfo.codeSize = spirv.size() * sizeof(uint32_t);
- createInfo.pCode = spirv.data();
+ createInfo.codeSize = spirv->WordCount() * sizeof(uint32_t);
+ createInfo.pCode = spirv->Code();
Device* device = ToBackend(GetDevice());
@@ -241,13 +310,17 @@ ResultOrError<ShaderModule::ModuleAndSpirv> ShaderModule::GetHandleAndSpirv(
device->fn.CreateShaderModule(device->GetVkDevice(), &createInfo, nullptr, &*newHandle),
"CreateShaderModule"));
}
+
ModuleAndSpirv moduleAndSpirv;
if (newHandle != VK_NULL_HANDLE) {
+ if (BlobCache* cache = device->GetBlobCache()) {
+ cache->EnsureStored(spirv);
+ }
moduleAndSpirv =
- mTransformedShaderModuleCache->AddOrGet(cacheKey, newHandle, std::move(spirv));
+ mTransformedShaderModuleCache->AddOrGet(cacheKey, newHandle, spirv.Acquire());
}
- SetDebugName(ToBackend(GetDevice()), moduleAndSpirv.first, "Dawn_ShaderModule", GetLabel());
+ SetDebugName(ToBackend(GetDevice()), moduleAndSpirv.module, "Dawn_ShaderModule", GetLabel());
return std::move(moduleAndSpirv);
#else
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.h b/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.h
index bd1c686b8ba..c0741eff6e8 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/ShaderModuleVk.h
@@ -17,16 +17,13 @@
#include <memory>
#include <mutex>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <optional> // NOLINT(build/include_order))
+#include <optional>
#include <unordered_map>
#include <utility>
-#include <vector>
-
-#include "dawn/native/ShaderModule.h"
#include "dawn/common/vulkan_platform.h"
#include "dawn/native/Error.h"
+#include "dawn/native/ShaderModule.h"
namespace dawn::native::vulkan {
@@ -35,8 +32,12 @@ class PipelineLayout;
class ShaderModule final : public ShaderModuleBase {
public:
- using Spirv = std::vector<uint32_t>;
- using ModuleAndSpirv = std::pair<VkShaderModule, const Spirv*>;
+ class Spirv;
+ struct ModuleAndSpirv {
+ VkShaderModule module;
+ const uint32_t* spirv;
+ size_t wordCount;
+ };
static ResultOrError<Ref<ShaderModule>> Create(Device* device,
const ShaderModuleDescriptor* descriptor,
@@ -54,25 +55,7 @@ class ShaderModule final : public ShaderModuleBase {
void DestroyImpl() override;
// New handles created by GetHandleAndSpirv at pipeline creation time.
- class ConcurrentTransformedShaderModuleCache {
- public:
- explicit ConcurrentTransformedShaderModuleCache(Device* device);
- ~ConcurrentTransformedShaderModuleCache();
-
- std::optional<ModuleAndSpirv> Find(const PipelineLayoutEntryPointPair& key);
- ModuleAndSpirv AddOrGet(const PipelineLayoutEntryPointPair& key,
- VkShaderModule module,
- std::vector<uint32_t>&& spirv);
-
- private:
- using Entry = std::pair<VkShaderModule, std::unique_ptr<Spirv>>;
-
- Device* mDevice;
- std::mutex mMutex;
- std::
- unordered_map<PipelineLayoutEntryPointPair, Entry, PipelineLayoutEntryPointPairHashFunc>
- mTransformedShaderModuleCache;
- };
+ class ConcurrentTransformedShaderModuleCache;
std::unique_ptr<ConcurrentTransformedShaderModuleCache> mTransformedShaderModuleCache;
};
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/StreamImplVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/StreamImplVk.cpp
new file mode 100644
index 00000000000..4ed4aec46bc
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/StreamImplVk.cpp
@@ -0,0 +1,339 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstring>
+#include <map>
+
+#include "dawn/common/Assert.h"
+#include "dawn/common/vulkan_platform.h"
+#include "dawn/native/stream/Stream.h"
+#include "dawn/native/vulkan/RenderPassCache.h"
+
+#include "icd/generated/vk_typemap_helper.h"
+
+namespace dawn::native {
+
+namespace {
+
+namespace detail {
+
+template <typename... VK_STRUCT_TYPES>
+void ValidatePnextImpl(const VkBaseOutStructure* root) {
+ const VkBaseOutStructure* next = reinterpret_cast<const VkBaseOutStructure*>(root->pNext);
+ while (next != nullptr) {
+ // Assert that the type of each pNext struct is exactly one of the specified
+ // templates.
+ ASSERT(((LvlTypeMap<VK_STRUCT_TYPES>::kSType == next->sType ? 1 : 0) + ... + 0) == 1);
+ next = reinterpret_cast<const VkBaseOutStructure*>(next->pNext);
+ }
+}
+
+template <typename VK_STRUCT_TYPE>
+void SerializePnextImpl(stream::Sink* sink, const VkBaseOutStructure* root) {
+ const VkBaseOutStructure* next = reinterpret_cast<const VkBaseOutStructure*>(root->pNext);
+ const VK_STRUCT_TYPE* found = nullptr;
+ while (next != nullptr) {
+ if (LvlTypeMap<VK_STRUCT_TYPE>::kSType == next->sType) {
+ if (found == nullptr) {
+ found = reinterpret_cast<const VK_STRUCT_TYPE*>(next);
+ } else {
+ // Fail an assert here since that means that the chain had more than one of
+ // the same typed chained object.
+ ASSERT(false);
+ }
+ }
+ next = reinterpret_cast<const VkBaseOutStructure*>(next->pNext);
+ }
+ if (found != nullptr) {
+ StreamIn(sink, found);
+ }
+}
+
+template <typename VK_STRUCT_TYPE,
+ typename... VK_STRUCT_TYPES,
+ typename = std::enable_if_t<(sizeof...(VK_STRUCT_TYPES) > 0)>>
+void SerializePnextImpl(stream::Sink* sink, const VkBaseOutStructure* root) {
+ SerializePnextImpl<VK_STRUCT_TYPE>(sink, root);
+ SerializePnextImpl<VK_STRUCT_TYPES...>(sink, root);
+}
+
+template <typename VK_STRUCT_TYPE>
+const VkBaseOutStructure* ToVkBaseOutStructure(const VK_STRUCT_TYPE* t) {
+ // Checks to ensure proper type safety.
+ static_assert(offsetof(VK_STRUCT_TYPE, sType) == offsetof(VkBaseOutStructure, sType) &&
+ offsetof(VK_STRUCT_TYPE, pNext) == offsetof(VkBaseOutStructure, pNext),
+ "Argument type is not a proper Vulkan structure type");
+ return reinterpret_cast<const VkBaseOutStructure*>(t);
+}
+
+} // namespace detail
+
+template <typename... VK_STRUCT_TYPES,
+ typename VK_STRUCT_TYPE,
+ typename = std::enable_if_t<(sizeof...(VK_STRUCT_TYPES) > 0)>>
+void SerializePnext(stream::Sink* sink, const VK_STRUCT_TYPE* t) {
+ const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t);
+ detail::ValidatePnextImpl<VK_STRUCT_TYPES...>(root);
+ detail::SerializePnextImpl<VK_STRUCT_TYPES...>(sink, root);
+}
+
+// Empty template specialization so that we can put this in to ensure failures occur if new
+// extensions are added without updating serialization.
+template <typename VK_STRUCT_TYPE>
+void SerializePnext(stream::Sink* sink, const VK_STRUCT_TYPE* t) {
+ const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t);
+ detail::ValidatePnextImpl<>(root);
+}
+
+} // namespace
+
+template <>
+void stream::Stream<VkDescriptorSetLayoutBinding>::Write(stream::Sink* sink,
+ const VkDescriptorSetLayoutBinding& t) {
+ StreamIn(sink, t.binding, t.descriptorType, t.descriptorCount, t.stageFlags);
+}
+
+template <>
+void stream::Stream<VkDescriptorSetLayoutCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkDescriptorSetLayoutCreateInfo& t) {
+ StreamIn(sink, t.flags, Iterable(t.pBindings, t.bindingCount));
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPushConstantRange>::Write(stream::Sink* sink, const VkPushConstantRange& t) {
+ StreamIn(sink, t.stageFlags, t.offset, t.size);
+}
+
+template <>
+void stream::Stream<VkPipelineLayoutCreateInfo>::Write(stream::Sink* sink,
+ const VkPipelineLayoutCreateInfo& t) {
+ // The set layouts are not serialized here because they are pointers to backend objects.
+ // They need to be cross-referenced with the frontend objects and serialized from there.
+ StreamIn(sink, t.flags, Iterable(t.pPushConstantRanges, t.pushConstantRangeCount));
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>::Write(
+ stream::Sink* sink,
+ const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT& t) {
+ StreamIn(sink, t.requiredSubgroupSize);
+}
+
+template <>
+void stream::Stream<VkPipelineRasterizationDepthClipStateCreateInfoEXT>::Write(
+ stream::Sink* sink,
+ const VkPipelineRasterizationDepthClipStateCreateInfoEXT& t) {
+ StreamIn(sink, t.depthClipEnable, t.flags);
+}
+
+template <>
+void stream::Stream<VkSpecializationMapEntry>::Write(stream::Sink* sink,
+ const VkSpecializationMapEntry& t) {
+ StreamIn(sink, t.constantID, t.offset, t.size);
+}
+
+template <>
+void stream::Stream<VkSpecializationInfo>::Write(stream::Sink* sink,
+ const VkSpecializationInfo& t) {
+ StreamIn(sink, Iterable(t.pMapEntries, t.mapEntryCount),
+ Iterable(static_cast<const uint8_t*>(t.pData), t.dataSize));
+}
+
+template <>
+void stream::Stream<VkPipelineShaderStageCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineShaderStageCreateInfo& t) {
+ // The shader module is not serialized here because it is a pointer to a backend object.
+ StreamIn(sink, t.flags, t.stage, Iterable(t.pName, strlen(t.pName)), t.pSpecializationInfo);
+ SerializePnext<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(sink, &t);
+}
+
+template <>
+void stream::Stream<VkComputePipelineCreateInfo>::Write(stream::Sink* sink,
+ const VkComputePipelineCreateInfo& t) {
+ // The pipeline layout is not serialized here because it is a pointer to a backend object.
+ // It needs to be cross-referenced with the frontend objects and serialized from there. The
+ // base pipeline information is also currently not serialized since we do not use them in our
+ // backend implementation. If we decide to use them later on, they also need to be
+ // cross-referenced from the frontend.
+ StreamIn(sink, t.flags, t.stage);
+}
+
+template <>
+void stream::Stream<VkVertexInputBindingDescription>::Write(
+ stream::Sink* sink,
+ const VkVertexInputBindingDescription& t) {
+ StreamIn(sink, t.binding, t.stride, t.inputRate);
+}
+
+template <>
+void stream::Stream<VkVertexInputAttributeDescription>::Write(
+ stream::Sink* sink,
+ const VkVertexInputAttributeDescription& t) {
+ StreamIn(sink, t.location, t.binding, t.format, t.offset);
+}
+
+template <>
+void stream::Stream<VkPipelineVertexInputStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineVertexInputStateCreateInfo& t) {
+ StreamIn(sink, t.flags, Iterable(t.pVertexBindingDescriptions, t.vertexBindingDescriptionCount),
+ Iterable(t.pVertexAttributeDescriptions, t.vertexAttributeDescriptionCount));
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPipelineInputAssemblyStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineInputAssemblyStateCreateInfo& t) {
+ StreamIn(sink, t.flags, t.topology, t.primitiveRestartEnable);
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPipelineTessellationStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineTessellationStateCreateInfo& t) {
+ StreamIn(sink, t.flags, t.patchControlPoints);
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkViewport>::Write(stream::Sink* sink, const VkViewport& t) {
+ StreamIn(sink, t.x, t.y, t.width, t.height, t.minDepth, t.maxDepth);
+}
+
+template <>
+void stream::Stream<VkOffset2D>::Write(stream::Sink* sink, const VkOffset2D& t) {
+ StreamIn(sink, t.x, t.y);
+}
+
+template <>
+void stream::Stream<VkExtent2D>::Write(stream::Sink* sink, const VkExtent2D& t) {
+ StreamIn(sink, t.width, t.height);
+}
+
+template <>
+void stream::Stream<VkRect2D>::Write(stream::Sink* sink, const VkRect2D& t) {
+ StreamIn(sink, t.offset, t.extent);
+}
+
+template <>
+void stream::Stream<VkPipelineViewportStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineViewportStateCreateInfo& t) {
+ StreamIn(sink, t.flags, Iterable(t.pViewports, t.viewportCount),
+ Iterable(t.pScissors, t.scissorCount));
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPipelineRasterizationStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineRasterizationStateCreateInfo& t) {
+ StreamIn(sink, t.flags, t.depthClampEnable, t.rasterizerDiscardEnable, t.polygonMode,
+ t.cullMode, t.frontFace, t.depthBiasEnable, t.depthBiasConstantFactor,
+ t.depthBiasClamp, t.depthBiasSlopeFactor, t.lineWidth);
+ SerializePnext<VkPipelineRasterizationDepthClipStateCreateInfoEXT>(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPipelineMultisampleStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineMultisampleStateCreateInfo& t) {
+ StreamIn(sink, t.flags, t.rasterizationSamples, t.sampleShadingEnable, t.minSampleShading,
+ t.pSampleMask, t.alphaToCoverageEnable, t.alphaToOneEnable);
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkStencilOpState>::Write(stream::Sink* sink, const VkStencilOpState& t) {
+ StreamIn(sink, t.failOp, t.passOp, t.depthFailOp, t.compareOp, t.compareMask, t.writeMask,
+ t.reference);
+}
+
+template <>
+void stream::Stream<VkPipelineDepthStencilStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineDepthStencilStateCreateInfo& t) {
+ StreamIn(sink, t.flags, t.depthTestEnable, t.depthWriteEnable, t.depthCompareOp,
+ t.depthBoundsTestEnable, t.stencilTestEnable, t.front, t.back, t.minDepthBounds,
+ t.maxDepthBounds);
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPipelineColorBlendAttachmentState>::Write(
+ stream::Sink* sink,
+ const VkPipelineColorBlendAttachmentState& t) {
+ StreamIn(sink, t.blendEnable, t.srcColorBlendFactor, t.dstColorBlendFactor, t.colorBlendOp,
+ t.srcAlphaBlendFactor, t.dstAlphaBlendFactor, t.alphaBlendOp, t.colorWriteMask);
+}
+
+template <>
+void stream::Stream<VkPipelineColorBlendStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineColorBlendStateCreateInfo& t) {
+ StreamIn(sink, t.flags, t.logicOpEnable, t.logicOp, Iterable(t.pAttachments, t.attachmentCount),
+ t.blendConstants);
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<VkPipelineDynamicStateCreateInfo>::Write(
+ stream::Sink* sink,
+ const VkPipelineDynamicStateCreateInfo& t) {
+ StreamIn(sink, t.flags, Iterable(t.pDynamicStates, t.dynamicStateCount));
+ SerializePnext(sink, &t);
+}
+
+template <>
+void stream::Stream<vulkan::RenderPassCacheQuery>::Write(stream::Sink* sink,
+ const vulkan::RenderPassCacheQuery& t) {
+ StreamIn(sink, t.colorMask.to_ulong(), t.resolveTargetMask.to_ulong(), t.sampleCount);
+
+ // Manually iterate the color attachment indices and their corresponding format/load/store
+ // ops because the data is sparse and may be uninitialized. Since we serialize the colorMask
+ // member above, serializing sparse data should be fine here.
+ for (ColorAttachmentIndex i : IterateBitSet(t.colorMask)) {
+ StreamIn(sink, t.colorFormats[i], t.colorLoadOp[i], t.colorStoreOp[i]);
+ }
+
+ // Serialize the depth-stencil toggle bit, and the parameters if applicable.
+ StreamIn(sink, t.hasDepthStencil);
+ if (t.hasDepthStencil) {
+ StreamIn(sink, t.depthStencilFormat, t.depthLoadOp, t.depthStoreOp, t.stencilLoadOp,
+ t.stencilStoreOp, t.readOnlyDepthStencil);
+ }
+}
+
+template <>
+void stream::Stream<VkGraphicsPipelineCreateInfo>::Write(stream::Sink* sink,
+ const VkGraphicsPipelineCreateInfo& t) {
+ // The pipeline layout and render pass are not serialized here because they are pointers to
+ // backend objects. They need to be cross-referenced with the frontend objects and
+ // serialized from there. The base pipeline information is also currently not serialized since
+ // we do not use them in our backend implementation. If we decide to use them later on, they
+ // also need to be cross-referenced from the frontend.
+ StreamIn(sink, t.flags, Iterable(t.pStages, t.stageCount), t.pVertexInputState,
+ t.pInputAssemblyState, t.pTessellationState, t.pViewportState, t.pRasterizationState,
+ t.pMultisampleState, t.pDepthStencilState, t.pColorBlendState, t.pDynamicState,
+ t.subpass);
+ SerializePnext(sink, &t);
+}
+
+} // namespace dawn::native
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.cpp
index 404815dca5c..49df3ed7f00 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.cpp
@@ -314,8 +314,6 @@ VkFormat VulkanImageFormat(const Device* device, wgpu::TextureFormat format) {
} else {
return VK_FORMAT_D24_UNORM_S8_UINT;
}
- case wgpu::TextureFormat::Depth24UnormStencil8:
- return VK_FORMAT_D24_UNORM_S8_UINT;
case wgpu::TextureFormat::Depth32FloatStencil8:
return VK_FORMAT_D32_SFLOAT_S8_UINT;
case wgpu::TextureFormat::Stencil8:
@@ -785,7 +783,6 @@ void Texture::InitializeForSwapChain(VkImage nativeImage) {
}
MaybeError Texture::BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
- VkSemaphore signalSemaphore,
VkDeviceMemory externalMemoryAllocation,
std::vector<VkSemaphore> waitSemaphores) {
Device* device = ToBackend(GetDevice());
@@ -800,17 +797,53 @@ MaybeError Texture::BindExternalMemory(const ExternalImageDescriptorVk* descript
// Success, acquire all the external objects.
mExternalAllocation = externalMemoryAllocation;
- mSignalSemaphore = signalSemaphore;
mWaitRequirements = std::move(waitSemaphores);
return {};
}
+void Texture::TransitionEagerlyForExport(CommandRecordingContext* recordingContext) {
+ mExternalState = ExternalState::EagerlyTransitioned;
+
+ Aspect aspects = ComputeAspectsForSubresourceStorage();
+ ASSERT(GetNumMipLevels() == 1 && GetArrayLayers() == 1);
+ SubresourceRange range = {aspects, {0, 1}, {0, 1}};
+
+ wgpu::TextureUsage usage = mSubresourceLastUsages->Get(aspects, 0, 0);
+
+ std::vector<VkImageMemoryBarrier> barriers;
+ VkPipelineStageFlags srcStages = 0;
+ VkPipelineStageFlags dstStages = 0;
+
+ // Same usage as last.
+ TransitionUsageAndGetResourceBarrier(usage, range, &barriers, &srcStages, &dstStages);
+
+ ASSERT(barriers.size() == 1);
+ VkImageMemoryBarrier& barrier = barriers[0];
+ // The barrier must be paired with another barrier that will specify the dst access mask on the
+ // importing queue.
+ barrier.dstAccessMask = 0;
+
+ if (mDesiredExportLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
+ barrier.newLayout = mDesiredExportLayout;
+ }
+
+ Device* device = ToBackend(GetDevice());
+ barrier.srcQueueFamilyIndex = device->GetGraphicsQueueFamily();
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR;
+
+ // We don't know when the importing queue will need the texture, so pass
+ // VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure the barrier happens-before any usage in the
+ // importing queue.
+ dstStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+
+ device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
+ nullptr, 0, nullptr, 1, &barrier);
+}
+
MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
- VkSemaphore* signalSemaphore,
+ ExternalSemaphoreHandle* handle,
VkImageLayout* releasedOldLayout,
VkImageLayout* releasedNewLayout) {
- Device* device = ToBackend(GetDevice());
-
DAWN_INVALID_IF(mExternalState == ExternalState::Released,
"Can't export a signal semaphore from signaled texture %s.", this);
@@ -818,8 +851,6 @@ MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
"Can't export a signal semaphore from destroyed or non-external texture %s.",
this);
- ASSERT(mSignalSemaphore != VK_NULL_HANDLE);
-
// Release the texture
mExternalState = ExternalState::Released;
@@ -827,54 +858,28 @@ MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
ASSERT(GetNumMipLevels() == 1 && GetArrayLayers() == 1);
wgpu::TextureUsage usage = mSubresourceLastUsages->Get(aspects, 0, 0);
- VkImageMemoryBarrier barrier;
- barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- barrier.pNext = nullptr;
- barrier.image = GetHandle();
- barrier.subresourceRange.aspectMask = VulkanAspectMask(aspects);
- barrier.subresourceRange.baseMipLevel = 0;
- barrier.subresourceRange.levelCount = 1;
- barrier.subresourceRange.baseArrayLayer = 0;
- barrier.subresourceRange.layerCount = 1;
-
- barrier.srcAccessMask = VulkanAccessFlags(usage, GetFormat());
- barrier.dstAccessMask = 0; // The barrier must be paired with another barrier that will
- // specify the dst access mask on the importing queue.
-
- barrier.oldLayout = VulkanImageLayout(this, usage);
- if (desiredLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
- // VK_IMAGE_LAYOUT_UNDEFINED is invalid here. We use it as a
- // special value to indicate no layout transition should be done.
- barrier.newLayout = barrier.oldLayout;
- } else {
- barrier.newLayout = desiredLayout;
- }
+ VkImageLayout layout = VulkanImageLayout(this, usage);
- barrier.srcQueueFamilyIndex = device->GetGraphicsQueueFamily();
- barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR;
-
- VkPipelineStageFlags srcStages = VulkanPipelineStage(usage, GetFormat());
- VkPipelineStageFlags dstStages =
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // We don't know when the importing queue will need
- // the texture, so pass
- // VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure
- // the barrier happens-before any usage in the
- // importing queue.
-
- CommandRecordingContext* recordingContext = device->GetPendingRecordingContext();
- device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
- nullptr, 0, nullptr, 1, &barrier);
+ // Write out the layouts and signal semaphore
+ *releasedOldLayout = layout;
+ *releasedNewLayout = (desiredLayout == VK_IMAGE_LAYOUT_UNDEFINED ? layout : desiredLayout);
- // Queue submit to signal we are done with the texture
- recordingContext->signalSemaphores.push_back(mSignalSemaphore);
- DAWN_TRY(device->SubmitPendingCommands());
+ mDesiredExportLayout = desiredLayout;
- // Write out the layouts and signal semaphore
- *releasedOldLayout = barrier.oldLayout;
- *releasedNewLayout = barrier.newLayout;
- *signalSemaphore = mSignalSemaphore;
+ // We have to manually trigger a transition if the texture hasn't been actually used, or the
+ // desired layout is not VK_IMAGE_LAYOUT_UNDEFINED.
+ // TODO(dawn:1509): Avoid the empty submit.
+ if (mExternalSemaphoreHandle == kNullExternalSemaphoreHandle ||
+ desiredLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
+ Device* device = ToBackend(GetDevice());
+ CommandRecordingContext* recordingContext = device->GetPendingRecordingContext();
+ recordingContext->externalTexturesForEagerTransition.insert(this);
+ DAWN_TRY(device->SubmitPendingCommands());
+ }
+ ASSERT(mExternalSemaphoreHandle != kNullExternalSemaphoreHandle);
- mSignalSemaphore = VK_NULL_HANDLE;
+ *handle = mExternalSemaphoreHandle;
+ mExternalSemaphoreHandle = kNullExternalSemaphoreHandle;
// Destroy the texture so it can't be used again
Destroy();
@@ -909,8 +914,11 @@ void Texture::DestroyImpl() {
mHandle = VK_NULL_HANDLE;
mExternalAllocation = VK_NULL_HANDLE;
- // If a signal semaphore exists it should be requested before we delete the texture
- ASSERT(mSignalSemaphore == VK_NULL_HANDLE);
+
+ if (mExternalSemaphoreHandle != kNullExternalSemaphoreHandle) {
+ device->GetExternalSemaphoreService()->CloseHandle(mExternalSemaphoreHandle);
+ }
+ mExternalSemaphoreHandle = kNullExternalSemaphoreHandle;
}
// For Vulkan, we currently run the base destruction code after the internal changes because
// of the dependency on the texture state which the base code overwrites too early.
@@ -931,7 +939,9 @@ void Texture::TweakTransitionForExternalUsage(CommandRecordingContext* recording
// have already added into the vector during current transition.
ASSERT(barriers->size() - transitionBarrierStart <= 1);
- if (mExternalState == ExternalState::PendingAcquire) {
+ if (mExternalState == ExternalState::PendingAcquire ||
+ mExternalState == ExternalState::EagerlyTransitioned) {
+ recordingContext->externalTexturesForEagerTransition.insert(this);
if (barriers->size() == transitionBarrierStart) {
barriers->push_back(BuildMemoryBarrier(
this, wgpu::TextureUsage::None, wgpu::TextureUsage::None,
@@ -948,27 +958,35 @@ void Texture::TweakTransitionForExternalUsage(CommandRecordingContext* recording
// this.
barrier->srcAccessMask = 0;
- // This should be the first barrier after import.
- ASSERT(barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED);
-
// Save the desired layout. We may need to transition through an intermediate
// |mPendingAcquireLayout| first.
VkImageLayout desiredLayout = barrier->newLayout;
- bool isInitialized = IsSubresourceContentInitialized(GetAllSubresources());
-
- // We don't care about the pending old layout if the texture is uninitialized. The
- // driver is free to discard it. Also it is invalid to transition to layout UNDEFINED or
- // PREINITIALIZED. If the embedder provided no new layout, or we don't care about the
- // previous contents, we can skip the layout transition.
- // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkImageMemoryBarrier-newLayout-01198
- if (!isInitialized || mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
- mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
- barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- barrier->newLayout = desiredLayout;
+ if (mExternalState == ExternalState::PendingAcquire) {
+ bool isInitialized = IsSubresourceContentInitialized(GetAllSubresources());
+
+ // We don't care about the pending old layout if the texture is uninitialized. The
+ // driver is free to discard it. Also it is invalid to transition to layout UNDEFINED or
+ // PREINITIALIZED. If the embedder provided no new layout, or we don't care about the
+ // previous contents, we can skip the layout transition.
+ // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkImageMemoryBarrier-newLayout-01198
+ if (!isInitialized || mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
+ mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
+ barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ barrier->newLayout = desiredLayout;
+ } else {
+ barrier->oldLayout = mPendingAcquireOldLayout;
+ barrier->newLayout = mPendingAcquireNewLayout;
+ }
} else {
- barrier->oldLayout = mPendingAcquireOldLayout;
- barrier->newLayout = mPendingAcquireNewLayout;
+ // In case of ExternalState::EagerlyTransitioned, the layouts of the texture's queue
+ // release were always same. So we exactly match that here for the queue acquire.
+ // The spec text:
+ // If the transfer is via an image memory barrier, and an image layout transition is
+ // desired, then the values of oldLayout and newLayout in the release operation's memory
+ // barrier must be equal to values of oldLayout and newLayout in the acquire operation's
+ // memory barrier.
+ barrier->newLayout = barrier->oldLayout;
}
// If these are unequal, we need an another barrier to transition the layout.
@@ -983,9 +1001,8 @@ void Texture::TweakTransitionForExternalUsage(CommandRecordingContext* recording
layoutBarrier.oldLayout = barrier->newLayout;
layoutBarrier.newLayout = desiredLayout;
- // We already transitioned these.
layoutBarrier.srcAccessMask = 0;
- layoutBarrier.dstAccessMask = 0;
+ layoutBarrier.dstAccessMask = barrier->dstAccessMask;
layoutBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
layoutBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@@ -1324,6 +1341,14 @@ void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* recor
}
}
+void Texture::UpdateExternalSemaphoreHandle(ExternalSemaphoreHandle handle) {
+ if (mExternalSemaphoreHandle != kNullExternalSemaphoreHandle) {
+ Device* device = ToBackend(GetDevice());
+ device->GetExternalSemaphoreService()->CloseHandle(mExternalSemaphoreHandle);
+ }
+ mExternalSemaphoreHandle = handle;
+}
+
VkImageLayout Texture::GetCurrentLayoutForSwapChain() const {
ASSERT(GetFormat().aspects == Aspect::Color);
return VulkanImageLayout(this, mSubresourceLastUsages->Get(Aspect::Color, 0, 0));
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.h b/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.h
index 4be64775c59..4caf11b7748 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/TextureVk.h
@@ -24,6 +24,7 @@
#include "dawn/native/Texture.h"
#include "dawn/native/vulkan/ExternalHandle.h"
#include "dawn/native/vulkan/external_memory/MemoryService.h"
+#include "dawn/native/vulkan/external_semaphore/SemaphoreService.h"
namespace dawn::native::vulkan {
@@ -77,6 +78,9 @@ class Texture final : public TextureBase {
VkPipelineStageFlags* srcStages,
VkPipelineStageFlags* dstStages);
+ // Eagerly transition the texture for export.
+ void TransitionEagerlyForExport(CommandRecordingContext* recordingContext);
+
void EnsureSubresourceContentInitialized(CommandRecordingContext* recordingContext,
const SubresourceRange& range);
@@ -85,12 +89,12 @@ class Texture final : public TextureBase {
// Binds externally allocated memory to the VkImage and on success, takes ownership of
// semaphores.
MaybeError BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
- VkSemaphore signalSemaphore,
VkDeviceMemory externalMemoryAllocation,
std::vector<VkSemaphore> waitSemaphores);
-
+ // Update the 'ExternalSemaphoreHandle' to be used for export with the newly submitted one.
+ void UpdateExternalSemaphoreHandle(ExternalSemaphoreHandle handle);
MaybeError ExportExternalTexture(VkImageLayout desiredLayout,
- VkSemaphore* signalSemaphore,
+ ExternalSemaphoreHandle* handle,
VkImageLayout* releasedOldLayout,
VkImageLayout* releasedNewLayout);
@@ -156,14 +160,30 @@ class Texture final : public TextureBase {
ResourceMemoryAllocation mMemoryAllocation;
VkDeviceMemory mExternalAllocation = VK_NULL_HANDLE;
- enum class ExternalState { InternalOnly, PendingAcquire, Acquired, Released };
+ // The states of an external texture:
+ // InternalOnly: Not initialized as an external texture yet.
+ // PendingAcquire: Intialized as an external texture already, but unavailable for access yet.
+ // Acquired: Ready for access.
+ // EagerlyTransitioned: The texture has ever been used, and eagerly transitioned for export.
+ // Now it can be acquired for access again, or directly exported. Released: The texture has
+ // been destoried, and should no longer be used.
+ enum class ExternalState {
+ InternalOnly,
+ PendingAcquire,
+ Acquired,
+ EagerlyTransitioned,
+ Released
+ };
ExternalState mExternalState = ExternalState::InternalOnly;
ExternalState mLastExternalState = ExternalState::InternalOnly;
VkImageLayout mPendingAcquireOldLayout;
VkImageLayout mPendingAcquireNewLayout;
- VkSemaphore mSignalSemaphore = VK_NULL_HANDLE;
+ VkImageLayout mDesiredExportLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ ExternalSemaphoreHandle mExternalSemaphoreHandle = kNullExternalSemaphoreHandle;
+
std::vector<VkSemaphore> mWaitRequirements;
// Note that in early Vulkan versions it is not possible to transition depth and stencil
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.cpp
index 2595112faa5..ca8b4052cae 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.cpp
@@ -261,7 +261,7 @@ std::string GetDeviceDebugPrefixFromDebugName(const char* debugName) {
VkSpecializationInfo* GetVkSpecializationInfo(
const ProgrammableStage& programmableStage,
VkSpecializationInfo* specializationInfo,
- std::vector<OverridableConstantScalar>* specializationDataEntries,
+ std::vector<OverrideScalar>* specializationDataEntries,
std::vector<VkSpecializationMapEntry>* specializationMapEntries) {
ASSERT(specializationInfo);
ASSERT(specializationDataEntries);
@@ -279,26 +279,25 @@ VkSpecializationInfo* GetVkSpecializationInfo(
double value = pipelineConstant.second;
// This is already validated so `identifier` must exist
- const auto& moduleConstant = entryPointMetaData.overridableConstants.at(identifier);
+ const auto& moduleConstant = entryPointMetaData.overrides.at(identifier);
- specializationMapEntries->push_back(
- VkSpecializationMapEntry{moduleConstant.id,
- static_cast<uint32_t>(specializationDataEntries->size() *
- sizeof(OverridableConstantScalar)),
- sizeof(OverridableConstantScalar)});
+ specializationMapEntries->push_back(VkSpecializationMapEntry{
+ moduleConstant.id,
+ static_cast<uint32_t>(specializationDataEntries->size() * sizeof(OverrideScalar)),
+ sizeof(OverrideScalar)});
- OverridableConstantScalar entry{};
+ OverrideScalar entry{};
switch (moduleConstant.type) {
- case EntryPointMetadata::OverridableConstant::Type::Boolean:
+ case EntryPointMetadata::Override::Type::Boolean:
entry.b = static_cast<int32_t>(value);
break;
- case EntryPointMetadata::OverridableConstant::Type::Float32:
+ case EntryPointMetadata::Override::Type::Float32:
entry.f32 = static_cast<float>(value);
break;
- case EntryPointMetadata::OverridableConstant::Type::Int32:
+ case EntryPointMetadata::Override::Type::Int32:
entry.i32 = static_cast<int32_t>(value);
break;
- case EntryPointMetadata::OverridableConstant::Type::Uint32:
+ case EntryPointMetadata::Override::Type::Uint32:
entry.u32 = static_cast<uint32_t>(value);
break;
default:
@@ -309,8 +308,7 @@ VkSpecializationInfo* GetVkSpecializationInfo(
specializationInfo->mapEntryCount = static_cast<uint32_t>(specializationMapEntries->size());
specializationInfo->pMapEntries = specializationMapEntries->data();
- specializationInfo->dataSize =
- specializationDataEntries->size() * sizeof(OverridableConstantScalar);
+ specializationInfo->dataSize = specializationDataEntries->size() * sizeof(OverrideScalar);
specializationInfo->pData = specializationDataEntries->data();
return specializationInfo;
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.h b/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.h
index 7c63b1dfcdd..3e2748e1738 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.h
@@ -24,7 +24,7 @@
namespace dawn::native {
struct ProgrammableStage;
-union OverridableConstantScalar;
+union OverrideScalar;
} // namespace dawn::native
namespace dawn::native::vulkan {
@@ -150,7 +150,7 @@ std::string GetDeviceDebugPrefixFromDebugName(const char* debugName);
VkSpecializationInfo* GetVkSpecializationInfo(
const ProgrammableStage& programmableStage,
VkSpecializationInfo* specializationInfo,
- std::vector<OverridableConstantScalar>* specializationDataEntries,
+ std::vector<OverrideScalar>* specializationDataEntries,
std::vector<VkSpecializationMapEntry>* specializationMapEntries);
} // namespace dawn::native::vulkan
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.cpp
index 439e95d1291..aaf3e658302 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.cpp
@@ -162,6 +162,7 @@ static constexpr std::array<DeviceExtInfo, kDeviceExtCount> sDeviceExtInfos{{
{DeviceExt::ExternalSemaphoreFD, "VK_KHR_external_semaphore_fd", NeverPromoted},
{DeviceExt::ExternalSemaphoreZirconHandle, "VK_FUCHSIA_external_semaphore", NeverPromoted},
+ {DeviceExt::DepthClipEnable, "VK_EXT_depth_clip_enable", NeverPromoted},
{DeviceExt::ImageDrmFormatModifier, "VK_EXT_image_drm_format_modifier", NeverPromoted},
{DeviceExt::Swapchain, "VK_KHR_swapchain", NeverPromoted},
{DeviceExt::SubgroupSizeControl, "VK_EXT_subgroup_size_control", NeverPromoted},
@@ -283,6 +284,7 @@ DeviceExtSet EnsureDependencies(const DeviceExtSet& advertisedExts,
hasDependencies = icdVersion >= VulkanVersion_1_1;
break;
+ case DeviceExt::DepthClipEnable:
case DeviceExt::ShaderIntegerDotProduct:
case DeviceExt::ZeroInitializeWorkgroupMemory:
hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2);
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.h b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.h
index 6912528404e..eb6ef49a42c 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanExtensions.h
@@ -103,6 +103,7 @@ enum class DeviceExt {
ExternalSemaphoreZirconHandle,
// Others
+ DepthClipEnable,
ImageDrmFormatModifier,
Swapchain,
SubgroupSizeControl,
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.cpp
index 116fd7222d6..d033e291ca5 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.cpp
@@ -254,6 +254,11 @@ ResultOrError<VulkanDeviceInfo> GatherDeviceInfo(const Adapter& adapter) {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR);
}
+ if (info.extensions[DeviceExt::DepthClipEnable]) {
+ featuresChain.Add(&info.depthClipEnableFeatures,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT);
+ }
+
// If we have DeviceExt::GetPhysicalDeviceProperties2, use features2 and properties2 so
// that features no covered by VkPhysicalDevice{Features,Properties} can be queried.
//
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.h b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.h
index 39dd12d66c3..5bb925736c5 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/VulkanInfo.h
@@ -53,6 +53,7 @@ struct VulkanDeviceKnobs {
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroupSizeControlFeatures;
VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR zeroInitializeWorkgroupMemoryFeatures;
VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR shaderIntegerDotProductFeatures;
+ VkPhysicalDeviceDepthClipEnableFeaturesEXT depthClipEnableFeatures;
bool HasExt(DeviceExt ext) const;
DeviceExtSet extensions;
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreService.h b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreService.h
index e27689fbf4e..18043e405d2 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreService.h
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreService.h
@@ -48,6 +48,12 @@ class Service {
// Export a VkSemaphore into an external handle
ResultOrError<ExternalSemaphoreHandle> ExportSemaphore(VkSemaphore semaphore);
+ // Duplicate a new external handle from the given one.
+ ExternalSemaphoreHandle DuplicateHandle(ExternalSemaphoreHandle handle);
+
+ // Close an external handle.
+ void CloseHandle(ExternalSemaphoreHandle handle);
+
private:
Device* mDevice = nullptr;
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceFD.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceFD.cpp
index 9c1d923daec..d424e625374 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceFD.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceFD.cpp
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <unistd.h>
#include <utility>
#include "dawn/native/vulkan/AdapterVk.h"
@@ -135,4 +136,15 @@ ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore sema
return fd;
}
+ExternalSemaphoreHandle Service::DuplicateHandle(ExternalSemaphoreHandle handle) {
+ int fd = dup(handle);
+ ASSERT(fd >= 0);
+ return fd;
+}
+
+void Service::CloseHandle(ExternalSemaphoreHandle handle) {
+ int ret = close(handle);
+ ASSERT(ret == 0);
+}
+
} // namespace dawn::native::vulkan::external_semaphore
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceNull.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceNull.cpp
index 1963524c820..370db872afa 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceNull.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceNull.cpp
@@ -47,4 +47,10 @@ ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore sema
return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan");
}
+ExternalSemaphoreHandle Service::DuplicateHandle(ExternalSemaphoreHandle handle) {
+ return kNullExternalSemaphoreHandle;
+}
+
+void Service::CloseHandle(ExternalSemaphoreHandle handle) {}
+
} // namespace dawn::native::vulkan::external_semaphore
diff --git a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp
index af1f3f3e779..12d776e311a 100644
--- a/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <zircon/syscalls.h>
#include <utility>
#include "dawn/native/vulkan/AdapterVk.h"
@@ -129,4 +130,16 @@ ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore sema
return handle;
}
+ExternalSemaphoreHandle Service::DuplicateHandle(ExternalSemaphoreHandle handle) {
+ zx_handle_t out_handle = ZX_HANDLE_INVALID;
+ zx_status_t status = zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, &out_handle);
+ ASSERT(status == ZX_OK);
+ return out_handle;
+}
+
+void Service::CloseHandle(ExternalSemaphoreHandle handle) {
+ zx_status_t status = zx_handle_close(handle);
+ ASSERT(status == ZX_OK);
+}
+
} // namespace dawn::native::vulkan::external_semaphore
diff --git a/chromium/third_party/dawn/src/dawn/native/webgpu_absl_format.cpp b/chromium/third_party/dawn/src/dawn/native/webgpu_absl_format.cpp
index 2550f4b1f5b..8eddf467bb5 100644
--- a/chromium/third_party/dawn/src/dawn/native/webgpu_absl_format.cpp
+++ b/chromium/third_party/dawn/src/dawn/native/webgpu_absl_format.cpp
@@ -181,16 +181,16 @@ absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConv
bool needsComma = false;
for (ColorAttachmentIndex i : IterateBitSet(value->GetColorAttachmentsMask())) {
+ if (needsComma) {
+ s->Append(", ");
+ }
+
while (nextColorIndex < i) {
s->Append(absl::StrFormat("%s, ", wgpu::TextureFormat::Undefined));
nextColorIndex++;
needsComma = false;
}
- if (needsComma) {
- s->Append(", ");
- }
-
s->Append(absl::StrFormat("%s", value->GetColorAttachmentFormat(i)));
nextColorIndex++;
diff --git a/chromium/third_party/dawn/src/dawn/node/README.md b/chromium/third_party/dawn/src/dawn/node/README.md
index 8e492a7fbe1..623d35bf38f 100644
--- a/chromium/third_party/dawn/src/dawn/node/README.md
+++ b/chromium/third_party/dawn/src/dawn/node/README.md
@@ -17,7 +17,7 @@ Dawn uses the Chromium build system and dependency management so you need to [in
### Fetch dependencies
-First, the steps are similar to [`doc/building.md`](../../docs/dawn/building.md), but instead of the `Get the code` step, run:
+First, the steps are similar to [`docs/building.md`](../../../docs/building.md), but instead of the `Get the code` step, run:
```sh
# Clone the repo as "dawn"
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/Converter.cpp b/chromium/third_party/dawn/src/dawn/node/binding/Converter.cpp
index cad53f67e4b..f06a6af70c6 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/Converter.cpp
+++ b/chromium/third_party/dawn/src/dawn/node/binding/Converter.cpp
@@ -459,11 +459,309 @@ bool Converter::Convert(wgpu::TextureFormat& out, const interop::GPUTextureForma
return false;
}
+bool Converter::Convert(interop::GPUTextureFormat& out, wgpu::TextureFormat in) {
+ switch (in) {
+ case wgpu::TextureFormat::R8Unorm:
+ out = interop::GPUTextureFormat::kR8Unorm;
+ return true;
+ case wgpu::TextureFormat::R8Snorm:
+ out = interop::GPUTextureFormat::kR8Snorm;
+ return true;
+ case wgpu::TextureFormat::R8Uint:
+ out = interop::GPUTextureFormat::kR8Uint;
+ return true;
+ case wgpu::TextureFormat::R8Sint:
+ out = interop::GPUTextureFormat::kR8Sint;
+ return true;
+ case wgpu::TextureFormat::R16Uint:
+ out = interop::GPUTextureFormat::kR16Uint;
+ return true;
+ case wgpu::TextureFormat::R16Sint:
+ out = interop::GPUTextureFormat::kR16Sint;
+ return true;
+ case wgpu::TextureFormat::R16Float:
+ out = interop::GPUTextureFormat::kR16Float;
+ return true;
+ case wgpu::TextureFormat::RG8Unorm:
+ out = interop::GPUTextureFormat::kRg8Unorm;
+ return true;
+ case wgpu::TextureFormat::RG8Snorm:
+ out = interop::GPUTextureFormat::kRg8Snorm;
+ return true;
+ case wgpu::TextureFormat::RG8Uint:
+ out = interop::GPUTextureFormat::kRg8Uint;
+ return true;
+ case wgpu::TextureFormat::RG8Sint:
+ out = interop::GPUTextureFormat::kRg8Sint;
+ return true;
+ case wgpu::TextureFormat::R32Uint:
+ out = interop::GPUTextureFormat::kR32Uint;
+ return true;
+ case wgpu::TextureFormat::R32Sint:
+ out = interop::GPUTextureFormat::kR32Sint;
+ return true;
+ case wgpu::TextureFormat::R32Float:
+ out = interop::GPUTextureFormat::kR32Float;
+ return true;
+ case wgpu::TextureFormat::RG16Uint:
+ out = interop::GPUTextureFormat::kRg16Uint;
+ return true;
+ case wgpu::TextureFormat::RG16Sint:
+ out = interop::GPUTextureFormat::kRg16Sint;
+ return true;
+ case wgpu::TextureFormat::RG16Float:
+ out = interop::GPUTextureFormat::kRg16Float;
+ return true;
+ case wgpu::TextureFormat::RGBA8Unorm:
+ out = interop::GPUTextureFormat::kRgba8Unorm;
+ return true;
+ case wgpu::TextureFormat::RGBA8UnormSrgb:
+ out = interop::GPUTextureFormat::kRgba8UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::RGBA8Snorm:
+ out = interop::GPUTextureFormat::kRgba8Snorm;
+ return true;
+ case wgpu::TextureFormat::RGBA8Uint:
+ out = interop::GPUTextureFormat::kRgba8Uint;
+ return true;
+ case wgpu::TextureFormat::RGBA8Sint:
+ out = interop::GPUTextureFormat::kRgba8Sint;
+ return true;
+ case wgpu::TextureFormat::BGRA8Unorm:
+ out = interop::GPUTextureFormat::kBgra8Unorm;
+ return true;
+ case wgpu::TextureFormat::BGRA8UnormSrgb:
+ out = interop::GPUTextureFormat::kBgra8UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::RGB9E5Ufloat:
+ out = interop::GPUTextureFormat::kRgb9E5Ufloat;
+ return true;
+ case wgpu::TextureFormat::RGB10A2Unorm:
+ out = interop::GPUTextureFormat::kRgb10A2Unorm;
+ return true;
+ case wgpu::TextureFormat::RG11B10Ufloat:
+ out = interop::GPUTextureFormat::kRg11B10Ufloat;
+ return true;
+ case wgpu::TextureFormat::RG32Uint:
+ out = interop::GPUTextureFormat::kRg32Uint;
+ return true;
+ case wgpu::TextureFormat::RG32Sint:
+ out = interop::GPUTextureFormat::kRg32Sint;
+ return true;
+ case wgpu::TextureFormat::RG32Float:
+ out = interop::GPUTextureFormat::kRg32Float;
+ return true;
+ case wgpu::TextureFormat::RGBA16Uint:
+ out = interop::GPUTextureFormat::kRgba16Uint;
+ return true;
+ case wgpu::TextureFormat::RGBA16Sint:
+ out = interop::GPUTextureFormat::kRgba16Sint;
+ return true;
+ case wgpu::TextureFormat::RGBA16Float:
+ out = interop::GPUTextureFormat::kRgba16Float;
+ return true;
+ case wgpu::TextureFormat::RGBA32Uint:
+ out = interop::GPUTextureFormat::kRgba32Uint;
+ return true;
+ case wgpu::TextureFormat::RGBA32Sint:
+ out = interop::GPUTextureFormat::kRgba32Sint;
+ return true;
+ case wgpu::TextureFormat::RGBA32Float:
+ out = interop::GPUTextureFormat::kRgba32Float;
+ return true;
+ case wgpu::TextureFormat::Stencil8:
+ out = interop::GPUTextureFormat::kStencil8;
+ return true;
+ case wgpu::TextureFormat::Depth16Unorm:
+ out = interop::GPUTextureFormat::kDepth16Unorm;
+ return true;
+ case wgpu::TextureFormat::Depth24Plus:
+ out = interop::GPUTextureFormat::kDepth24Plus;
+ return true;
+ case wgpu::TextureFormat::Depth24PlusStencil8:
+ out = interop::GPUTextureFormat::kDepth24PlusStencil8;
+ return true;
+ case wgpu::TextureFormat::Depth32Float:
+ out = interop::GPUTextureFormat::kDepth32Float;
+ return true;
+ case wgpu::TextureFormat::Depth32FloatStencil8:
+ out = interop::GPUTextureFormat::kDepth32FloatStencil8;
+ return true;
+ case wgpu::TextureFormat::BC1RGBAUnorm:
+ out = interop::GPUTextureFormat::kBc1RgbaUnorm;
+ return true;
+ case wgpu::TextureFormat::BC1RGBAUnormSrgb:
+ out = interop::GPUTextureFormat::kBc1RgbaUnormSrgb;
+ return true;
+ case wgpu::TextureFormat::BC2RGBAUnorm:
+ out = interop::GPUTextureFormat::kBc2RgbaUnorm;
+ return true;
+ case wgpu::TextureFormat::BC2RGBAUnormSrgb:
+ out = interop::GPUTextureFormat::kBc2RgbaUnormSrgb;
+ return true;
+ case wgpu::TextureFormat::BC3RGBAUnorm:
+ out = interop::GPUTextureFormat::kBc3RgbaUnorm;
+ return true;
+ case wgpu::TextureFormat::BC3RGBAUnormSrgb:
+ out = interop::GPUTextureFormat::kBc3RgbaUnormSrgb;
+ return true;
+ case wgpu::TextureFormat::BC4RUnorm:
+ out = interop::GPUTextureFormat::kBc4RUnorm;
+ return true;
+ case wgpu::TextureFormat::BC4RSnorm:
+ out = interop::GPUTextureFormat::kBc4RSnorm;
+ return true;
+ case wgpu::TextureFormat::BC5RGUnorm:
+ out = interop::GPUTextureFormat::kBc5RgUnorm;
+ return true;
+ case wgpu::TextureFormat::BC5RGSnorm:
+ out = interop::GPUTextureFormat::kBc5RgSnorm;
+ return true;
+ case wgpu::TextureFormat::BC6HRGBUfloat:
+ out = interop::GPUTextureFormat::kBc6HRgbUfloat;
+ return true;
+ case wgpu::TextureFormat::BC6HRGBFloat:
+ out = interop::GPUTextureFormat::kBc6HRgbFloat;
+ return true;
+ case wgpu::TextureFormat::BC7RGBAUnorm:
+ out = interop::GPUTextureFormat::kBc7RgbaUnorm;
+ return true;
+ case wgpu::TextureFormat::BC7RGBAUnormSrgb:
+ out = interop::GPUTextureFormat::kBc7RgbaUnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ETC2RGB8Unorm:
+ out = interop::GPUTextureFormat::kEtc2Rgb8Unorm;
+ return true;
+ case wgpu::TextureFormat::ETC2RGB8UnormSrgb:
+ out = interop::GPUTextureFormat::kEtc2Rgb8UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ETC2RGB8A1Unorm:
+ out = interop::GPUTextureFormat::kEtc2Rgb8A1Unorm;
+ return true;
+ case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb:
+ out = interop::GPUTextureFormat::kEtc2Rgb8A1UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ETC2RGBA8Unorm:
+ out = interop::GPUTextureFormat::kEtc2Rgba8Unorm;
+ return true;
+ case wgpu::TextureFormat::ETC2RGBA8UnormSrgb:
+ out = interop::GPUTextureFormat::kEtc2Rgba8UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::EACR11Unorm:
+ out = interop::GPUTextureFormat::kEacR11Unorm;
+ return true;
+ case wgpu::TextureFormat::EACR11Snorm:
+ out = interop::GPUTextureFormat::kEacR11Snorm;
+ return true;
+ case wgpu::TextureFormat::EACRG11Unorm:
+ out = interop::GPUTextureFormat::kEacRg11Unorm;
+ return true;
+ case wgpu::TextureFormat::EACRG11Snorm:
+ out = interop::GPUTextureFormat::kEacRg11Snorm;
+ return true;
+ case wgpu::TextureFormat::ASTC4x4Unorm:
+ out = interop::GPUTextureFormat::kAstc4X4Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC4x4UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc4X4UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC5x4Unorm:
+ out = interop::GPUTextureFormat::kAstc5X4Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC5x4UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc5X4UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC5x5Unorm:
+ out = interop::GPUTextureFormat::kAstc5X5Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC5x5UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc5X5UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC6x5Unorm:
+ out = interop::GPUTextureFormat::kAstc6X5Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC6x5UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc6X5UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC6x6Unorm:
+ out = interop::GPUTextureFormat::kAstc6X6Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC6x6UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc6X6UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC8x5Unorm:
+ out = interop::GPUTextureFormat::kAstc8X5Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC8x5UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc8X5UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC8x6Unorm:
+ out = interop::GPUTextureFormat::kAstc8X6Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC8x6UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc8X6UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC8x8Unorm:
+ out = interop::GPUTextureFormat::kAstc8X8Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC8x8UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc8X8UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC10x5Unorm:
+ out = interop::GPUTextureFormat::kAstc10X5Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC10x5UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc10X5UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC10x6Unorm:
+ out = interop::GPUTextureFormat::kAstc10X6Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC10x6UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc10X6UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC10x8Unorm:
+ out = interop::GPUTextureFormat::kAstc10X8Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC10x8UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc10X8UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC10x10Unorm:
+ out = interop::GPUTextureFormat::kAstc10X10Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC10x10UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc10X10UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC12x10Unorm:
+ out = interop::GPUTextureFormat::kAstc12X10Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC12x10UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc12X10UnormSrgb;
+ return true;
+ case wgpu::TextureFormat::ASTC12x12Unorm:
+ out = interop::GPUTextureFormat::kAstc12X12Unorm;
+ return true;
+ case wgpu::TextureFormat::ASTC12x12UnormSrgb:
+ out = interop::GPUTextureFormat::kAstc12X12UnormSrgb;
+ return true;
+
+ case wgpu::TextureFormat::Undefined:
+ case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
+ return false;
+ }
+
+ return false;
+}
+
bool Converter::Convert(wgpu::TextureUsage& out, const interop::GPUTextureUsageFlags& in) {
out = static_cast<wgpu::TextureUsage>(in.value);
return true;
}
+bool Converter::Convert(interop::GPUTextureUsageFlags& out, wgpu::TextureUsage in) {
+ out = interop::GPUTextureUsageFlags(static_cast<uint32_t>(out));
+ return true;
+}
+
bool Converter::Convert(wgpu::ColorWriteMask& out, const interop::GPUColorWriteFlags& in) {
out = static_cast<wgpu::ColorWriteMask>(in.value);
return true;
@@ -474,6 +772,11 @@ bool Converter::Convert(wgpu::BufferUsage& out, const interop::GPUBufferUsageFla
return true;
}
+bool Converter::Convert(interop::GPUBufferUsageFlags& out, wgpu::BufferUsage in) {
+ out = interop::GPUBufferUsageFlags(static_cast<uint32_t>(out));
+ return true;
+}
+
bool Converter::Convert(wgpu::MapMode& out, const interop::GPUMapModeFlags& in) {
out = static_cast<wgpu::MapMode>(in.value);
return true;
@@ -501,6 +804,21 @@ bool Converter::Convert(wgpu::TextureDimension& out, const interop::GPUTextureDi
return false;
}
+bool Converter::Convert(interop::GPUTextureDimension& out, wgpu::TextureDimension in) {
+ switch (in) {
+ case wgpu::TextureDimension::e1D:
+ out = interop::GPUTextureDimension::k1D;
+ return true;
+ case wgpu::TextureDimension::e2D:
+ out = interop::GPUTextureDimension::k2D;
+ return true;
+ case wgpu::TextureDimension::e3D:
+ out = interop::GPUTextureDimension::k3D;
+ return true;
+ }
+ return false;
+}
+
bool Converter::Convert(wgpu::TextureViewDimension& out,
const interop::GPUTextureViewDimension& in) {
out = wgpu::TextureViewDimension::Undefined;
@@ -1150,6 +1468,21 @@ bool Converter::Convert(wgpu::QueryType& out, const interop::GPUQueryType& in) {
return false;
}
+bool Converter::Convert(interop::GPUQueryType& out, wgpu::QueryType in) {
+ switch (in) {
+ case wgpu::QueryType::Occlusion:
+ out = interop::GPUQueryType::kOcclusion;
+ return true;
+ case wgpu::QueryType::Timestamp:
+ out = interop::GPUQueryType::kTimestamp;
+ return true;
+ case wgpu::QueryType::PipelineStatistics:
+ // TODO(dawn:1123): Add support for pipeline statistics if they are in WebGPU one day.
+ return false;
+ }
+ return false;
+}
+
bool Converter::Convert(wgpu::AddressMode& out, const interop::GPUAddressMode& in) {
out = wgpu::AddressMode::Repeat;
switch (in) {
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/Converter.h b/chromium/third_party/dawn/src/dawn/node/binding/Converter.h
index e0ef58c0175..0c8a232a878 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/Converter.h
+++ b/chromium/third_party/dawn/src/dawn/node/binding/Converter.h
@@ -245,6 +245,17 @@ class Converter {
[[nodiscard]] bool Convert(wgpu::PipelineLayout& out, const interop::GPUAutoLayoutMode& in);
+ // Below are the various overloads of Convert() used to convert the Dawn types -> interop.
+ [[nodiscard]] bool Convert(interop::GPUTextureDimension& out, wgpu::TextureDimension in);
+
+ [[nodiscard]] bool Convert(interop::GPUTextureFormat& out, wgpu::TextureFormat in);
+
+ [[nodiscard]] bool Convert(interop::GPUTextureUsageFlags& out, wgpu::TextureUsage in);
+
+ [[nodiscard]] bool Convert(interop::GPUBufferUsageFlags& out, wgpu::BufferUsage in);
+
+ [[nodiscard]] bool Convert(interop::GPUQueryType& out, wgpu::QueryType in);
+
// std::string to C string
inline bool Convert(const char*& out, const std::string& in) {
out = in.c_str();
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/GPUAdapter.cpp b/chromium/third_party/dawn/src/dawn/node/binding/GPUAdapter.cpp
index 511225e2978..a2d7248c0dc 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/GPUAdapter.cpp
+++ b/chromium/third_party/dawn/src/dawn/node/binding/GPUAdapter.cpp
@@ -15,6 +15,7 @@
#include "src/dawn/node/binding/GPUAdapter.h"
#include <unordered_set>
+#include <utility>
#include <vector>
#include "src/dawn/node/binding/Errors.h"
@@ -91,29 +92,35 @@ namespace {
////////////////////////////////////////////////////////////////////////////////
class Features : public interop::GPUSupportedFeatures {
public:
- explicit Features(WGPUDeviceProperties properties) {
- if (properties.depth32FloatStencil8) {
- enabled_.emplace(interop::GPUFeatureName::kDepth32FloatStencil8);
- }
- if (properties.timestampQuery) {
- enabled_.emplace(interop::GPUFeatureName::kTimestampQuery);
- }
- if (properties.textureCompressionBC) {
- enabled_.emplace(interop::GPUFeatureName::kTextureCompressionBc);
- }
- if (properties.textureCompressionETC2) {
- enabled_.emplace(interop::GPUFeatureName::kTextureCompressionEtc2);
- }
- if (properties.textureCompressionASTC) {
- enabled_.emplace(interop::GPUFeatureName::kTextureCompressionAstc);
- }
- if (properties.timestampQuery) {
- enabled_.emplace(interop::GPUFeatureName::kTimestampQuery);
+ explicit Features(std::vector<wgpu::FeatureName> features) {
+ for (wgpu::FeatureName feature : features) {
+ switch (feature) {
+ case wgpu::FeatureName::Depth32FloatStencil8:
+ enabled_.emplace(interop::GPUFeatureName::kDepth32FloatStencil8);
+ break;
+ case wgpu::FeatureName::TimestampQuery:
+ enabled_.emplace(interop::GPUFeatureName::kTimestampQuery);
+ break;
+ case wgpu::FeatureName::TextureCompressionBC:
+ enabled_.emplace(interop::GPUFeatureName::kTextureCompressionBc);
+ break;
+ case wgpu::FeatureName::TextureCompressionETC2:
+ enabled_.emplace(interop::GPUFeatureName::kTextureCompressionEtc2);
+ break;
+ case wgpu::FeatureName::TextureCompressionASTC:
+ enabled_.emplace(interop::GPUFeatureName::kTextureCompressionAstc);
+ break;
+ case wgpu::FeatureName::IndirectFirstInstance:
+ enabled_.emplace(interop::GPUFeatureName::kIndirectFirstInstance);
+ break;
+ case wgpu::FeatureName::DepthClipControl:
+ enabled_.emplace(interop::GPUFeatureName::kDepthClipControl);
+ break;
+ default:
+ break;
+ }
}
-
// TODO(dawn:1123) add support for these extensions when possible.
- // wgpu::interop::GPUFeatureName::kDepthClipControl
- // wgpu::interop::GPUFeatureName::kIndirectFirstInstance
// wgpu::interop::GPUFeatureName::kShaderF16
// wgpu::interop::GPUFeatureName::kBgra8UnormStorage
}
@@ -152,7 +159,11 @@ GPUAdapter::GPUAdapter(dawn::native::Adapter a, const Flags& flags) : adapter_(a
// TODO(dawn:1133): Avoid the extra copy by making the generator make a virtual method with const
// std::string&
interop::Interface<interop::GPUSupportedFeatures> GPUAdapter::getFeatures(Napi::Env env) {
- return interop::GPUSupportedFeatures::Create<Features>(env, adapter_.GetAdapterProperties());
+ wgpu::Adapter adapter(adapter_.Get());
+ size_t count = adapter.EnumerateFeatures(nullptr);
+ std::vector<wgpu::FeatureName> features(count);
+ adapter.EnumerateFeatures(&features[0]);
+ return interop::GPUSupportedFeatures::Create<Features>(env, std::move(features));
}
interop::Interface<interop::GPUSupportedLimits> GPUAdapter::getLimits(Napi::Env env) {
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/GPUBuffer.cpp b/chromium/third_party/dawn/src/dawn/node/binding/GPUBuffer.cpp
index afe0735f68c..0d9718d5749 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/GPUBuffer.cpp
+++ b/chromium/third_party/dawn/src/dawn/node/binding/GPUBuffer.cpp
@@ -163,11 +163,20 @@ void GPUBuffer::destroy(Napi::Env) {
}
interop::GPUSize64 GPUBuffer::getSize(Napi::Env) {
- UNIMPLEMENTED();
+ return buffer_.GetSize();
}
-interop::GPUBufferUsageFlags GPUBuffer::getUsage(Napi::Env) {
- UNIMPLEMENTED();
+interop::GPUBufferUsageFlags GPUBuffer::getUsage(Napi::Env env) {
+ interop::GPUBufferUsageFlags result;
+
+ Converter conv(env);
+ if (!conv(result, buffer_.GetUsage())) {
+ Napi::Error::New(env, "Couldn't convert usage to a JavaScript value.")
+ .ThrowAsJavaScriptException();
+ return {0u}; // Doesn't get used.
+ }
+
+ return result;
}
void GPUBuffer::DetachMappings() {
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.cpp b/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.cpp
index 5239ce16e12..9ac8c2808a5 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.cpp
+++ b/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.cpp
@@ -41,6 +41,53 @@ namespace wgpu::binding {
namespace {
+// Returns a string representation of the WGPULoggingType
+const char* str(WGPULoggingType ty) {
+ switch (ty) {
+ case WGPULoggingType_Verbose:
+ return "verbose";
+ case WGPULoggingType_Info:
+ return "info";
+ case WGPULoggingType_Warning:
+ return "warning";
+ case WGPULoggingType_Error:
+ return "error";
+ default:
+ return "unknown";
+ }
+}
+
+// Returns a string representation of the WGPUErrorType
+const char* str(WGPUErrorType ty) {
+ switch (ty) {
+ case WGPUErrorType_NoError:
+ return "no error";
+ case WGPUErrorType_Validation:
+ return "validation";
+ case WGPUErrorType_OutOfMemory:
+ return "out of memory";
+ case WGPUErrorType_Unknown:
+ return "unknown";
+ case WGPUErrorType_DeviceLost:
+ return "device lost";
+ default:
+ return "unknown";
+ }
+}
+
+// There's something broken with Node when attempting to write more than 65536 bytes to cout.
+// Split the string up into writes of 4k chunks .
+// Likely related: https://github.com/nodejs/node/issues/12921
+void chunkedWrite(const char* msg) {
+ while (true) {
+ auto n = printf("%.4096s", msg);
+ if (n == 0) {
+ break;
+ }
+ msg += n;
+ }
+}
+
class DeviceLostInfo : public interop::GPUDeviceLostInfo {
public:
DeviceLostInfo(interop::GPUDeviceLostReason reason, std::string message)
@@ -88,12 +135,14 @@ GPUDevice::GPUDevice(Napi::Env env, wgpu::Device device)
lost_promise_(env, PROMISE_INFO) {
device_.SetLoggingCallback(
[](WGPULoggingType type, char const* message, void* userdata) {
- std::cout << type << ": " << message << std::endl;
+ printf("%s:\n", str(type));
+ chunkedWrite(message);
},
nullptr);
device_.SetUncapturedErrorCallback(
[](WGPUErrorType type, char const* message, void* userdata) {
- std::cout << type << ": " << message << std::endl;
+ printf("%s:\n", str(type));
+ chunkedWrite(message);
},
nullptr);
@@ -118,7 +167,15 @@ GPUDevice::GPUDevice(Napi::Env env, wgpu::Device device)
this);
}
-GPUDevice::~GPUDevice() {}
+GPUDevice::~GPUDevice() {
+ // A bit of a fudge to work around the fact that the CTS doesn't destroy GPU devices.
+ // Without this, we'll get a 'Promise not resolved or rejected' fatal message as the
+ // lost_promise_ is left hanging. We'll also not clean up any GPU objects before terminating the
+ // process, which is not a good idea.
+ if (!destroyed_) {
+ destroy(env_);
+ }
+}
interop::Interface<interop::GPUSupportedFeatures> GPUDevice::getFeatures(Napi::Env env) {
class Features : public interop::GPUSupportedFeatures {
@@ -147,6 +204,7 @@ void GPUDevice::destroy(Napi::Env env) {
env_, interop::GPUDeviceLostReason::kDestroyed, "device was destroyed"));
}
device_.Destroy();
+ destroyed_ = true;
}
interop::Interface<interop::GPUBuffer> GPUDevice::createBuffer(
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.h b/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.h
index 02a2ea80b13..9c53e9a444e 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.h
+++ b/chromium/third_party/dawn/src/dawn/node/binding/GPUDevice.h
@@ -111,6 +111,8 @@ class GPUDevice final : public interop::GPUDevice {
// This promise's JS object lives as long as the device because it is stored in .lost
// of the wrapper JS object.
interop::Promise<interop::Interface<interop::GPUDeviceLostInfo>> lost_promise_;
+
+ bool destroyed_ = false;
};
} // namespace wgpu::binding
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/GPUQuerySet.cpp b/chromium/third_party/dawn/src/dawn/node/binding/GPUQuerySet.cpp
index 08a8a4700bc..c02bdb6b6a5 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/GPUQuerySet.cpp
+++ b/chromium/third_party/dawn/src/dawn/node/binding/GPUQuerySet.cpp
@@ -16,6 +16,7 @@
#include <utility>
+#include "src/dawn/node/binding/Converter.h"
#include "src/dawn/node/utils/Debug.h"
namespace wgpu::binding {
@@ -29,12 +30,21 @@ void GPUQuerySet::destroy(Napi::Env) {
query_set_.Destroy();
}
-interop::GPUQueryType GPUQuerySet::getType(Napi::Env) {
- UNIMPLEMENTED();
+interop::GPUQueryType GPUQuerySet::getType(Napi::Env env) {
+ interop::GPUQueryType result;
+
+ Converter conv(env);
+ if (!conv(result, query_set_.GetType())) {
+ Napi::Error::New(env, "Couldn't convert type to a JavaScript value.")
+ .ThrowAsJavaScriptException();
+ return interop::GPUQueryType::kOcclusion; // Doesn't get used.
+ }
+
+ return result;
}
interop::GPUSize32 GPUQuerySet::getCount(Napi::Env) {
- UNIMPLEMENTED();
+ return query_set_.GetCount();
}
std::string GPUQuerySet::getLabel(Napi::Env) {
diff --git a/chromium/third_party/dawn/src/dawn/node/binding/GPUTexture.cpp b/chromium/third_party/dawn/src/dawn/node/binding/GPUTexture.cpp
index 38aaac598dc..24c682d87d9 100644
--- a/chromium/third_party/dawn/src/dawn/node/binding/GPUTexture.cpp
+++ b/chromium/third_party/dawn/src/dawn/node/binding/GPUTexture.cpp
@@ -55,35 +55,62 @@ void GPUTexture::destroy(Napi::Env) {
}
interop::GPUIntegerCoordinate GPUTexture::getWidth(Napi::Env) {
- UNIMPLEMENTED();
+ return texture_.GetWidth();
}
interop::GPUIntegerCoordinate GPUTexture::getHeight(Napi::Env) {
- UNIMPLEMENTED();
+ return texture_.GetHeight();
}
interop::GPUIntegerCoordinate GPUTexture::getDepthOrArrayLayers(Napi::Env) {
- UNIMPLEMENTED();
+ return texture_.GetDepthOrArrayLayers();
}
interop::GPUIntegerCoordinate GPUTexture::getMipLevelCount(Napi::Env) {
- UNIMPLEMENTED();
+ return texture_.GetMipLevelCount();
}
interop::GPUSize32 GPUTexture::getSampleCount(Napi::Env) {
- UNIMPLEMENTED();
+ return texture_.GetSampleCount();
}
-interop::GPUTextureDimension GPUTexture::getDimension(Napi::Env) {
- UNIMPLEMENTED();
+interop::GPUTextureDimension GPUTexture::getDimension(Napi::Env env) {
+ interop::GPUTextureDimension result;
+
+ Converter conv(env);
+ if (!conv(result, texture_.GetDimension())) {
+ Napi::Error::New(env, "Couldn't convert dimension to a JavaScript value.")
+ .ThrowAsJavaScriptException();
+ return interop::GPUTextureDimension::k1D; // Doesn't get used.
+ }
+
+ return result;
}
-interop::GPUTextureFormat GPUTexture::getFormat(Napi::Env) {
- UNIMPLEMENTED();
+interop::GPUTextureFormat GPUTexture::getFormat(Napi::Env env) {
+ interop::GPUTextureFormat result;
+
+ Converter conv(env);
+ if (!conv(result, texture_.GetFormat())) {
+ Napi::Error::New(env, "Couldn't convert format to a JavaScript value.")
+ .ThrowAsJavaScriptException();
+ return interop::GPUTextureFormat::kR32Float; // Doesn't get used.
+ }
+
+ return result;
}
-interop::GPUTextureUsageFlags GPUTexture::getUsage(Napi::Env) {
- UNIMPLEMENTED();
+interop::GPUTextureUsageFlags GPUTexture::getUsage(Napi::Env env) {
+ interop::GPUTextureUsageFlags result;
+
+ Converter conv(env);
+ if (!conv(result, texture_.GetUsage())) {
+ Napi::Error::New(env, "Couldn't convert usage to a JavaScript value.")
+ .ThrowAsJavaScriptException();
+ return {0u}; // Doesn't get used.
+ }
+
+ return result;
}
std::string GPUTexture::getLabel(Napi::Env) {
diff --git a/chromium/third_party/dawn/src/dawn/node/interop/Core.h b/chromium/third_party/dawn/src/dawn/node/interop/Core.h
index 4bf9ee79654..be1b4ac495e 100644
--- a/chromium/third_party/dawn/src/dawn/node/interop/Core.h
+++ b/chromium/third_party/dawn/src/dawn/node/interop/Core.h
@@ -20,14 +20,12 @@
#include <cstdint>
#include <limits>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <optional> // NOLINT(build/include_order)
+#include <optional>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <variant> // NOLINT(build/include_order)
+#include <variant>
#include <vector>
#include "src/dawn/node/interop/Napi.h"
diff --git a/chromium/third_party/dawn/src/dawn/node/tools/src/cmd/run-cts/main.go b/chromium/third_party/dawn/src/dawn/node/tools/src/cmd/run-cts/main.go
index afbe830045a..090f2dbe548 100644
--- a/chromium/third_party/dawn/src/dawn/node/tools/src/cmd/run-cts/main.go
+++ b/chromium/third_party/dawn/src/dawn/node/tools/src/cmd/run-cts/main.go
@@ -129,7 +129,7 @@ func run() error {
}
var dawnNode, cts, node, npx, resultsPath, expectationsPath, logFilename, backend string
- var printStdout, verbose, isolated, build bool
+ var printStdout, verbose, isolated, build, dumpShaders bool
var numRunners int
var flags dawnNodeFlags
flag.StringVar(&dawnNode, "dawn-node", "", "path to dawn.node module")
@@ -148,6 +148,7 @@ func run() error {
flag.Var(&flags, "flag", "flag to pass to dawn-node as flag=value. multiple flags must be passed in individually")
flag.StringVar(&backend, "backend", backendDefault, "backend to use: default|null|webgpu|d3d11|d3d12|metal|vulkan|opengl|opengles."+
" set to 'vulkan' if VK_ICD_FILENAMES environment variable is set, 'default' otherwise")
+ flag.BoolVar(&dumpShaders, "dump-shaders", false, "dump WGSL shaders. Enables --verbose")
flag.Parse()
// Create a thread-safe, color supporting stdout wrapper.
@@ -219,6 +220,10 @@ func run() error {
if !disableDawnFeaturesFound {
flags = append(flags, "disable-dawn-features=disallow_unsafe_apis")
}
+ if dumpShaders {
+ flags = append(flags, "enable-dawn-features=dump_shaders")
+ verbose = true
+ }
r := runner{
numRunners: numRunners,
@@ -972,7 +977,9 @@ func (r *runner) runTestcase(query string) result {
msg := buf.String()
switch {
case errors.Is(err, context.DeadlineExceeded):
- return result{testcase: query, status: timeout, message: msg}
+ return result{testcase: query, status: timeout, message: msg, error: err}
+ case err != nil:
+ break
case strings.Contains(msg, "[fail]"):
return result{testcase: query, status: fail, message: msg}
case strings.Contains(msg, "[warn]"):
diff --git a/chromium/third_party/dawn/src/dawn/node/utils/Debug.h b/chromium/third_party/dawn/src/dawn/node/utils/Debug.h
index c68b858c694..66cd4da0e54 100644
--- a/chromium/third_party/dawn/src/dawn/node/utils/Debug.h
+++ b/chromium/third_party/dawn/src/dawn/node/utils/Debug.h
@@ -16,13 +16,11 @@
#define SRC_DAWN_NODE_UTILS_DEBUG_H_
#include <iostream>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <optional> // NOLINT(build/include_order)
+#include <optional>
#include <sstream>
#include <unordered_map>
#include <utility>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <variant> // NOLINT(build/include_order)
+#include <variant>
#include <vector>
#include "dawn/webgpu_cpp_print.h"
diff --git a/chromium/third_party/dawn/src/dawn/platform/DawnPlatform.cpp b/chromium/third_party/dawn/src/dawn/platform/DawnPlatform.cpp
index 0d52a33f4c9..3b22ade0cdc 100644
--- a/chromium/third_party/dawn/src/dawn/platform/DawnPlatform.cpp
+++ b/chromium/third_party/dawn/src/dawn/platform/DawnPlatform.cpp
@@ -53,8 +53,7 @@ uint64_t Platform::AddTraceEvent(char phase,
return 0;
}
-dawn::platform::CachingInterface* Platform::GetCachingInterface(const void* fingerprint,
- size_t fingerprintSize) {
+dawn::platform::CachingInterface* Platform::GetCachingInterface() {
return nullptr;
}
diff --git a/chromium/third_party/dawn/src/dawn/samples/BUILD.gn b/chromium/third_party/dawn/src/dawn/samples/BUILD.gn
index 58874cf623e..f78498eae35 100644
--- a/chromium/third_party/dawn/src/dawn/samples/BUILD.gn
+++ b/chromium/third_party/dawn/src/dawn/samples/BUILD.gn
@@ -36,10 +36,10 @@ static_library("utils") {
"${dawn_root}/src/dawn:cpp",
"${dawn_root}/src/dawn:proc_shared",
"${dawn_root}/src/dawn/common",
+ "${dawn_root}/src/dawn/glfw",
"${dawn_root}/src/dawn/native",
"${dawn_root}/src/dawn/utils",
"${dawn_root}/src/dawn/utils:bindings",
- "${dawn_root}/src/dawn/utils:glfw",
"${dawn_root}/src/dawn/wire",
]
public_configs = [ "${dawn_root}/src/dawn/common:internal_config" ]
diff --git a/chromium/third_party/dawn/src/dawn/samples/CMakeLists.txt b/chromium/third_party/dawn/src/dawn/samples/CMakeLists.txt
index 1a8e007dd9a..9f358681b61 100644
--- a/chromium/third_party/dawn/src/dawn/samples/CMakeLists.txt
+++ b/chromium/third_party/dawn/src/dawn/samples/CMakeLists.txt
@@ -23,6 +23,7 @@ target_link_libraries(dawn_sample_utils PUBLIC
dawncpp
dawn_proc
dawn_common
+ dawn_glfw
dawn_native
dawn_wire
dawn_utils
diff --git a/chromium/third_party/dawn/src/dawn/samples/ManualSwapChainTest.cpp b/chromium/third_party/dawn/src/dawn/samples/ManualSwapChainTest.cpp
index c6e61cc1cec..bed9f121242 100644
--- a/chromium/third_party/dawn/src/dawn/samples/ManualSwapChainTest.cpp
+++ b/chromium/third_party/dawn/src/dawn/samples/ManualSwapChainTest.cpp
@@ -63,10 +63,10 @@
#include "dawn/dawn_proc.h"
#include "dawn/native/DawnNative.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
-#include "dawn/utils/GLFWUtils.h"
#include "dawn/utils/ScopedAutoreleasePool.h"
#include "dawn/utils/WGPUHelpers.h"
#include "dawn/webgpu_cpp.h"
+#include "webgpu/webgpu_glfw.h"
struct WindowData {
GLFWwindow* window = nullptr;
@@ -123,7 +123,7 @@ void AddWindow() {
std::unique_ptr<WindowData> data = std::make_unique<WindowData>();
data->window = window;
data->serial = windowSerial++;
- data->surface = utils::CreateSurfaceForWindow(instance->Get(), window);
+ data->surface = wgpu::glfw::CreateSurfaceForWindow(instance->Get(), window);
data->currentDesc = descriptor;
data->targetDesc = descriptor;
SyncFromWindow(data.get());
diff --git a/chromium/third_party/dawn/src/dawn/samples/SampleUtils.cpp b/chromium/third_party/dawn/src/dawn/samples/SampleUtils.cpp
index ac102a67d66..1aab2498d0a 100644
--- a/chromium/third_party/dawn/src/dawn/samples/SampleUtils.cpp
+++ b/chromium/third_party/dawn/src/dawn/samples/SampleUtils.cpp
@@ -28,10 +28,10 @@
#include "dawn/dawn_proc.h"
#include "dawn/dawn_wsi.h"
#include "dawn/native/DawnNative.h"
-#include "dawn/utils/GLFWUtils.h"
#include "dawn/utils/TerribleCommandBuffer.h"
#include "dawn/wire/WireClient.h"
#include "dawn/wire/WireServer.h"
+#include "webgpu/webgpu_glfw.h"
void PrintDeviceError(WGPUErrorType errorType, const char* message, void*) {
const char* errorTypeName = "";
@@ -103,8 +103,8 @@ wgpu::Device CreateCppDawnDevice() {
return wgpu::Device();
}
- // Create the test window and discover adapters using it (esp. for OpenGL)
- utils::SetupGLFWWindowHintsForBackend(backendType);
+ // Create the test window with no client API.
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
window = glfwCreateWindow(640, 480, "Dawn window", nullptr, nullptr);
if (!window) {
@@ -132,7 +132,7 @@ wgpu::Device CreateCppDawnDevice() {
DawnProcTable backendProcs = dawn::native::GetProcs();
// Create the swapchain
- auto surfaceChainedDesc = utils::SetupWindowAndGetSurfaceDescriptor(window);
+ auto surfaceChainedDesc = wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
WGPUSurfaceDescriptor surfaceDesc;
surfaceDesc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(surfaceChainedDesc.get());
WGPUSurface surface = backendProcs.instanceCreateSurface(instance->Get(), &surfaceDesc);
diff --git a/chromium/third_party/dawn/src/dawn/tests/BUILD.gn b/chromium/third_party/dawn/src/dawn/tests/BUILD.gn
index 69c41a2e1a7..eb1ed6c186b 100644
--- a/chromium/third_party/dawn/src/dawn/tests/BUILD.gn
+++ b/chromium/third_party/dawn/src/dawn/tests/BUILD.gn
@@ -192,6 +192,7 @@ dawn_test("dawn_unittests") {
":gmock_and_gtest",
":mock_webgpu_gen",
":native_mocks_sources",
+ ":platform_mocks_sources",
"${dawn_root}/src/dawn:cpp",
"${dawn_root}/src/dawn:proc",
"${dawn_root}/src/dawn/common",
@@ -204,6 +205,13 @@ dawn_test("dawn_unittests") {
# Add internal dawn native config for internal unittests.
configs = [ "${dawn_root}/src/dawn/native:internal" ]
+ # Add Tint public+common configs so <tint/tint.h> can be included to test
+ # the Dawn/Tint boundary.
+ configs += [
+ "${dawn_root}/src/tint:tint_public_config",
+ "${dawn_root}/src/tint:tint_common_config",
+ ]
+
sources = get_target_outputs(":mock_webgpu_gen")
sources += [
"${dawn_root}/src/dawn/wire/client/ClientMemoryTransferService_mock.cpp",
@@ -251,13 +259,13 @@ dawn_test("dawn_unittests") {
"unittests/SystemUtilsTests.cpp",
"unittests/ToBackendTests.cpp",
"unittests/TypedIntegerTests.cpp",
- "unittests/VersionTests.cpp",
"unittests/native/BlobTests.cpp",
- "unittests/native/CacheKeyTests.cpp",
+ "unittests/native/CacheRequestTests.cpp",
"unittests/native/CommandBufferEncodingTests.cpp",
"unittests/native/CreatePipelineAsyncTaskTests.cpp",
"unittests/native/DestroyObjectTests.cpp",
"unittests/native/DeviceCreationTests.cpp",
+ "unittests/native/StreamTests.cpp",
"unittests/validation/BindGroupValidationTests.cpp",
"unittests/validation/BufferValidationTests.cpp",
"unittests/validation/CommandBufferValidationTests.cpp",
@@ -363,10 +371,12 @@ source_set("test_infra_sources") {
if (dawn_supports_glfw_for_windowing || dawn_enable_opengl) {
assert(dawn_supports_glfw_for_windowing)
- public_deps += [ "${dawn_root}/src/dawn/utils:glfw" ]
+ public_deps += [ "${dawn_root}/src/dawn/glfw" ]
}
sources = [
+ "AdapterTestConfig.cpp",
+ "AdapterTestConfig.h",
"DawnTest.cpp",
"DawnTest.h",
"MockCallback.h",
@@ -380,20 +390,21 @@ source_set("test_infra_sources") {
# Dawn end2end tests targets
###############################################################################
-# Source code for mocks used for end2end testing are separated from the rest of
+# Source code for mocks used for platform testing are separated from the rest of
# sources so that they aren't included in non-test builds.
-source_set("end2end_mocks_sources") {
+source_set("platform_mocks_sources") {
configs += [ "${dawn_root}/src/dawn/native:internal" ]
testonly = true
deps = [
":gmock_and_gtest",
+ "${dawn_root}/src/dawn/common",
"${dawn_root}/src/dawn/platform",
]
sources = [
- "end2end/mocks/CachingInterfaceMock.cpp",
- "end2end/mocks/CachingInterfaceMock.h",
+ "mocks/platform/CachingInterfaceMock.cpp",
+ "mocks/platform/CachingInterfaceMock.h",
]
}
@@ -401,7 +412,7 @@ source_set("end2end_tests_sources") {
testonly = true
deps = [
- ":end2end_mocks_sources",
+ ":platform_mocks_sources",
":test_infra_sources",
"${dawn_root}/src/dawn:cpp",
"${dawn_root}/src/dawn:proc",
@@ -481,6 +492,7 @@ source_set("end2end_tests_sources") {
"end2end/StorageTextureTests.cpp",
"end2end/SubresourceRenderAttachmentTests.cpp",
"end2end/Texture3DTests.cpp",
+ "end2end/TextureCorruptionTests.cpp",
"end2end/TextureFormatTests.cpp",
"end2end/TextureSubresourceTests.cpp",
"end2end/TextureViewTests.cpp",
@@ -596,9 +608,9 @@ source_set("white_box_tests_sources") {
sources += [ "white_box/MetalAutoreleasePoolTests.mm" ]
}
- if (dawn_enable_opengles && defined(dawn_angle_dir)) {
+ if (dawn_enable_opengles) {
sources += [ "white_box/EGLImageWrappingTests.cpp" ]
- include_dirs = [ "${dawn_angle_dir}/include" ]
+ include_dirs = [ "//third_party/khronos" ]
}
libs = []
diff --git a/chromium/third_party/dawn/src/dawn/utils/BUILD.gn b/chromium/third_party/dawn/src/dawn/utils/BUILD.gn
index e281b417127..e74473dd25e 100644
--- a/chromium/third_party/dawn/src/dawn/utils/BUILD.gn
+++ b/chromium/third_party/dawn/src/dawn/utils/BUILD.gn
@@ -17,48 +17,6 @@ import("../../../scripts/dawn_overrides_with_defaults.gni")
import("${dawn_root}/scripts/dawn_features.gni")
###############################################################################
-# GLFW wrapping target
-###############################################################################
-
-# GLFW does not support ChromeOS, Android or Fuchsia, so provide a small mock
-# library that can be linked into the Dawn tests on these platforms. Otherwise,
-# use the real library from third_party/.
-if (dawn_supports_glfw_for_windowing) {
- group("glfw") {
- public_deps = [ "${dawn_root}/third_party/gn/glfw" ]
- }
-} else if (is_fuchsia) {
- # The mock implementation of GLFW on Fuchsia
- config("glfw_public_config") {
- # Allow inclusion of <GLFW/glfw3.h>
- include_dirs = [ "${dawn_glfw_dir}/include" ]
-
- # The GLFW/glfw3.h header includes <GL/gl.h> by default, but the latter
- # does not exist on Fuchsia. Defining GLFW_INCLUDE_NONE helps work around
- # the issue, but it needs to be defined for any file that includes the
- # header.
- defines = [
- "GLFW_INCLUDE_NONE",
- "GLFW_INCLUDE_VULKAN",
- ]
- }
-
- static_library("glfw") {
- sources = [
- # NOTE: The header below is required to pass "gn check".
- "${dawn_glfw_dir}/include/GLFW/glfw3.h",
- "Glfw3Fuchsia.cpp",
- ]
- public_configs = [ ":glfw_public_config" ]
- deps = [ "${dawn_root}/src/dawn/common" ]
- }
-} else {
- # Just skip GLFW on other systems
- group("glfw") {
- }
-}
-
-###############################################################################
# Utils for tests and samples
###############################################################################
@@ -121,19 +79,6 @@ static_library("utils") {
sources += [ "ScopedAutoreleasePool.cpp" ]
}
- if (dawn_supports_glfw_for_windowing) {
- sources += [
- "GLFWUtils.cpp",
- "GLFWUtils.h",
- ]
- deps += [ ":glfw" ]
-
- if (dawn_enable_metal) {
- sources += [ "GLFWUtils_metal.mm" ]
- frameworks += [ "Metal.framework" ]
- }
- }
-
public_deps = [ "${dawn_root}/include/dawn:cpp_headers" ]
}
@@ -154,8 +99,8 @@ if (dawn_standalone) {
public_deps = [ "${dawn_root}/include/dawn:headers" ]
deps = [
- ":glfw",
"${dawn_root}/src/dawn/common",
+ "${dawn_root}/src/dawn/glfw",
"${dawn_root}/src/dawn/native",
]
libs = []
diff --git a/chromium/third_party/dawn/src/dawn/utils/BackendBinding.cpp b/chromium/third_party/dawn/src/dawn/utils/BackendBinding.cpp
index 17bea5f9ff9..2aaa04798dd 100644
--- a/chromium/third_party/dawn/src/dawn/utils/BackendBinding.cpp
+++ b/chromium/third_party/dawn/src/dawn/utils/BackendBinding.cpp
@@ -16,12 +16,6 @@
#include "dawn/common/Compiler.h"
-#include "GLFW/glfw3.h"
-
-#if defined(DAWN_ENABLE_BACKEND_OPENGL)
-#include "dawn/native/OpenGLBackend.h"
-#endif // defined(DAWN_ENABLE_BACKEND_OPENGL)
-
namespace utils {
#if defined(DAWN_ENABLE_BACKEND_D3D12)
@@ -43,29 +37,6 @@ BackendBinding* CreateVulkanBinding(GLFWwindow* window, WGPUDevice device);
BackendBinding::BackendBinding(GLFWwindow* window, WGPUDevice device)
: mWindow(window), mDevice(device) {}
-void DiscoverAdapter(dawn::native::Instance* instance, GLFWwindow* window, wgpu::BackendType type) {
- DAWN_UNUSED(type);
- DAWN_UNUSED(window);
-
- if (type == wgpu::BackendType::OpenGL || type == wgpu::BackendType::OpenGLES) {
-#if defined(DAWN_ENABLE_BACKEND_OPENGL)
- glfwMakeContextCurrent(window);
- auto getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
- if (type == wgpu::BackendType::OpenGL) {
- dawn::native::opengl::AdapterDiscoveryOptions adapterOptions;
- adapterOptions.getProc = getProc;
- instance->DiscoverAdapters(&adapterOptions);
- } else {
- dawn::native::opengl::AdapterDiscoveryOptionsES adapterOptions;
- adapterOptions.getProc = getProc;
- instance->DiscoverAdapters(&adapterOptions);
- }
-#endif // defined(DAWN_ENABLE_BACKEND_OPENGL)
- } else {
- instance->DiscoverDefaultAdapters();
- }
-}
-
BackendBinding* CreateBinding(wgpu::BackendType type, GLFWwindow* window, WGPUDevice device) {
switch (type) {
#if defined(DAWN_ENABLE_BACKEND_D3D12)
diff --git a/chromium/third_party/dawn/src/dawn/utils/CMakeLists.txt b/chromium/third_party/dawn/src/dawn/utils/CMakeLists.txt
index a05bcba97fb..eddbbbec94c 100644
--- a/chromium/third_party/dawn/src/dawn/utils/CMakeLists.txt
+++ b/chromium/third_party/dawn/src/dawn/utils/CMakeLists.txt
@@ -73,8 +73,6 @@ if(DAWN_SUPPORTS_GLFW_FOR_WINDOWING)
target_sources(dawn_utils PRIVATE
"BackendBinding.cpp"
"BackendBinding.h"
- "GLFWUtils.cpp"
- "GLFWUtils.h"
)
target_link_libraries(dawn_utils PRIVATE glfw)
@@ -84,7 +82,6 @@ if(DAWN_SUPPORTS_GLFW_FOR_WINDOWING)
if (DAWN_ENABLE_METAL)
target_sources(dawn_utils PRIVATE
- "GLFWUtils_metal.mm"
"MetalBinding.mm"
)
endif()
diff --git a/chromium/third_party/dawn/src/dawn/utils/GLFWUtils.cpp b/chromium/third_party/dawn/src/dawn/utils/GLFWUtils.cpp
deleted file mode 100644
index 74e8c73f5d8..00000000000
--- a/chromium/third_party/dawn/src/dawn/utils/GLFWUtils.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2020 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <cstdlib>
-#include <utility>
-
-#include "GLFW/glfw3.h"
-#include "dawn/common/Platform.h"
-#include "dawn/utils/GLFWUtils.h"
-
-#if DAWN_PLATFORM_IS(WINDOWS)
-#define GLFW_EXPOSE_NATIVE_WIN32
-#endif
-#if defined(DAWN_USE_X11)
-#define GLFW_EXPOSE_NATIVE_X11
-#endif
-#if defined(DAWN_USE_WAYLAND)
-#define GLFW_EXPOSE_NATIVE_WAYLAND
-#endif
-#include "GLFW/glfw3native.h"
-
-namespace utils {
-
-void SetupGLFWWindowHintsForBackend(wgpu::BackendType type) {
- if (type == wgpu::BackendType::OpenGL) {
- // Ask for OpenGL 4.4 which is what the GL backend requires for compute shaders and
- // texture views.
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
- glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- } else if (type == wgpu::BackendType::OpenGLES) {
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
- glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
- glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
- } else {
- // Without this GLFW will initialize a GL context on the window, which prevents using
- // the window with other APIs (by crashing in weird ways).
- glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- }
-}
-
-wgpu::Surface CreateSurfaceForWindow(const wgpu::Instance& instance, GLFWwindow* window) {
- std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
- SetupWindowAndGetSurfaceDescriptor(window);
-
- wgpu::SurfaceDescriptor descriptor;
- descriptor.nextInChain = chainedDescriptor.get();
- wgpu::Surface surface = instance.CreateSurface(&descriptor);
-
- return surface;
-}
-
-// SetupWindowAndGetSurfaceDescriptorCocoa defined in GLFWUtils_metal.mm
-std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(GLFWwindow* window);
-
-std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window) {
- switch (glfwGetPlatform()) {
-#if DAWN_PLATFORM_IS(WINDOWS)
- case GLFW_PLATFORM_WIN32: {
- std::unique_ptr<wgpu::SurfaceDescriptorFromWindowsHWND> desc =
- std::make_unique<wgpu::SurfaceDescriptorFromWindowsHWND>();
- desc->hwnd = glfwGetWin32Window(window);
- desc->hinstance = GetModuleHandle(nullptr);
- return std::move(desc);
- }
-#endif
-#if defined(DAWN_ENABLE_BACKEND_METAL)
- case GLFW_PLATFORM_COCOA:
- return SetupWindowAndGetSurfaceDescriptorCocoa(window);
-#endif
-#if defined(DAWN_USE_WAYLAND)
- case GLFW_PLATFORM_WAYLAND: {
- std::unique_ptr<wgpu::SurfaceDescriptorFromWaylandSurface> desc =
- std::make_unique<wgpu::SurfaceDescriptorFromWaylandSurface>();
- desc->display = glfwGetWaylandDisplay();
- desc->surface = glfwGetWaylandWindow(window);
- return std::move(desc);
- }
-#endif
-#if defined(DAWN_USE_X11)
- case GLFW_PLATFORM_X11: {
- std::unique_ptr<wgpu::SurfaceDescriptorFromXlibWindow> desc =
- std::make_unique<wgpu::SurfaceDescriptorFromXlibWindow>();
- desc->display = glfwGetX11Display();
- desc->window = glfwGetX11Window(window);
- return std::move(desc);
- }
-#endif
- default:
- return nullptr;
- }
-}
-
-} // namespace utils
diff --git a/chromium/third_party/dawn/src/dawn/utils/GLFWUtils.h b/chromium/third_party/dawn/src/dawn/utils/GLFWUtils.h
deleted file mode 100644
index 2fe5b10ffdd..00000000000
--- a/chromium/third_party/dawn/src/dawn/utils/GLFWUtils.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2020 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_DAWN_UTILS_GLFWUTILS_H_
-#define SRC_DAWN_UTILS_GLFWUTILS_H_
-
-#include <memory>
-
-#include "dawn/webgpu_cpp.h"
-
-struct GLFWwindow;
-
-namespace utils {
-
-// Adds all the necessary glfwWindowHint calls for the next GLFWwindow created to be used with
-// the specified backend.
-void SetupGLFWWindowHintsForBackend(wgpu::BackendType type);
-
-// Does the necessary setup on the GLFWwindow to allow creating a wgpu::Surface with it and
-// calls `instance.CreateSurface` with the correct descriptor for this window.
-// Returns a null wgpu::Surface on failure.
-wgpu::Surface CreateSurfaceForWindow(const wgpu::Instance& instance, GLFWwindow* window);
-
-// Use for testing only. Does everything that CreateSurfaceForWindow does except the call to
-// CreateSurface. Useful to be able to modify the descriptor for testing, or when trying to
-// avoid using the global proc table.
-std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window);
-
-} // namespace utils
-
-#endif // SRC_DAWN_UTILS_GLFWUTILS_H_
diff --git a/chromium/third_party/dawn/src/dawn/utils/Glfw3Fuchsia.cpp b/chromium/third_party/dawn/src/dawn/utils/Glfw3Fuchsia.cpp
deleted file mode 100644
index 198a5fd2ec7..00000000000
--- a/chromium/third_party/dawn/src/dawn/utils/Glfw3Fuchsia.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2019 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// A mock GLFW implementation that supports Fuchsia, but only implements
-// the functions called from Dawn.
-
-#include <dlfcn.h>
-
-// NOTE: This must be included before GLFW/glfw3.h because the latter will
-// include <vulkan/vulkan.h> and "common/vulkan_platform.h" wants to be
-// the first header to do so for validity reasons (e.g. undefining weird
-// macros on Windows and Linux).
-// clang-format off
-#include "dawn/common/vulkan_platform.h"
-#include "dawn/common/Assert.h"
-#include "GLFW/glfw3.h"
-// clang-format on
-
-int glfwInit(void) {
- return GLFW_TRUE;
-}
-
-void glfwDefaultWindowHints(void) {}
-
-void glfwWindowHint(int hint, int value) {
- DAWN_UNUSED(hint);
- DAWN_UNUSED(value);
-}
-
-struct GLFWwindow {
- PFN_vkGetInstanceProcAddr GetInstanceProcAddress = nullptr;
- void* vulkan_loader = nullptr;
-
- GLFWwindow() {
- vulkan_loader = ::dlopen("libvulkan.so", RTLD_NOW);
- ASSERT(vulkan_loader != nullptr);
- GetInstanceProcAddress = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
- dlsym(vulkan_loader, "vkGetInstanceProcAddr"));
- ASSERT(GetInstanceProcAddress != nullptr);
- }
-
- ~GLFWwindow() {
- if (vulkan_loader) {
- ::dlclose(vulkan_loader);
- }
- vulkan_loader = nullptr;
- }
-};
-
-GLFWwindow* glfwCreateWindow(int width,
- int height,
- const char* title,
- GLFWmonitor* monitor,
- GLFWwindow* share) {
- ASSERT(monitor == nullptr);
- ASSERT(share == nullptr);
- DAWN_UNUSED(width);
- DAWN_UNUSED(height);
- DAWN_UNUSED(title);
- return new GLFWwindow();
-}
-
-VkResult glfwCreateWindowSurface(VkInstance instance,
- GLFWwindow* window,
- const VkAllocationCallbacks* allocator,
- VkSurfaceKHR* surface) {
- // IMPORTANT: This assumes that the VkInstance was created with a Fuchsia
- // swapchain layer enabled, as well as the corresponding extension that
- // is queried here to perform the surface creation. Dawn should do all
- // required steps in VulkanInfo.cpp, VulkanFunctions.cpp and BackendVk.cpp.
-
- auto vkCreateImagePipeSurfaceFUCHSIA = reinterpret_cast<PFN_vkCreateImagePipeSurfaceFUCHSIA>(
- window->GetInstanceProcAddress(instance, "vkCreateImagePipeSurfaceFUCHSIA"));
- ASSERT(vkCreateImagePipeSurfaceFUCHSIA != nullptr);
- if (!vkCreateImagePipeSurfaceFUCHSIA) {
- *surface = VK_NULL_HANDLE;
- return VK_ERROR_FEATURE_NOT_PRESENT;
- }
-
- const struct VkImagePipeSurfaceCreateInfoFUCHSIA create_info = {
- VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA,
- nullptr, // pNext
- 0, // flags, ignored for now
- ZX_HANDLE_INVALID, // imagePipeHandle, a null handle matches the framebuffer.
- };
-
- return vkCreateImagePipeSurfaceFUCHSIA(instance, &create_info, nullptr, surface);
-}
diff --git a/chromium/third_party/dawn/src/dawn/utils/TestUtils.cpp b/chromium/third_party/dawn/src/dawn/utils/TestUtils.cpp
index e5b41cf0a9f..3216402abf0 100644
--- a/chromium/third_party/dawn/src/dawn/utils/TestUtils.cpp
+++ b/chromium/third_party/dawn/src/dawn/utils/TestUtils.cpp
@@ -13,6 +13,7 @@
// limitations under the License.
#include <algorithm>
+#include <ostream>
#include <vector>
#include "dawn/common/Assert.h"
@@ -24,6 +25,19 @@
namespace utils {
+const RGBA8 RGBA8::kZero = RGBA8(0, 0, 0, 0);
+const RGBA8 RGBA8::kBlack = RGBA8(0, 0, 0, 255);
+const RGBA8 RGBA8::kRed = RGBA8(255, 0, 0, 255);
+const RGBA8 RGBA8::kGreen = RGBA8(0, 255, 0, 255);
+const RGBA8 RGBA8::kBlue = RGBA8(0, 0, 255, 255);
+const RGBA8 RGBA8::kYellow = RGBA8(255, 255, 0, 255);
+const RGBA8 RGBA8::kWhite = RGBA8(255, 255, 255, 255);
+
+std::ostream& operator<<(std::ostream& stream, const RGBA8& color) {
+ return stream << "RGBA8(" << static_cast<int>(color.r) << ", " << static_cast<int>(color.g)
+ << ", " << static_cast<int>(color.b) << ", " << static_cast<int>(color.a) << ")";
+}
+
uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width) {
const uint32_t bytesPerBlock = utils::GetTexelBlockSizeInBytes(format);
const uint32_t blockWidth = utils::GetTextureFormatBlockWidth(format);
diff --git a/chromium/third_party/dawn/src/dawn/utils/TestUtils.h b/chromium/third_party/dawn/src/dawn/utils/TestUtils.h
index 5e119cf38f3..fa7865d9001 100644
--- a/chromium/third_party/dawn/src/dawn/utils/TestUtils.h
+++ b/chromium/third_party/dawn/src/dawn/utils/TestUtils.h
@@ -19,6 +19,26 @@
namespace utils {
+struct RGBA8 {
+ constexpr RGBA8() : RGBA8(0, 0, 0, 0) {}
+ constexpr RGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) {}
+ bool operator==(const RGBA8& other) const;
+ bool operator!=(const RGBA8& other) const;
+ bool operator<=(const RGBA8& other) const;
+ bool operator>=(const RGBA8& other) const;
+
+ uint8_t r, g, b, a;
+
+ static const RGBA8 kZero;
+ static const RGBA8 kBlack;
+ static const RGBA8 kRed;
+ static const RGBA8 kGreen;
+ static const RGBA8 kBlue;
+ static const RGBA8 kYellow;
+ static const RGBA8 kWhite;
+};
+std::ostream& operator<<(std::ostream& stream, const RGBA8& color);
+
struct TextureDataCopyLayout {
uint64_t byteLength;
uint64_t texelBlockCount;
diff --git a/chromium/third_party/dawn/src/dawn/utils/TextureUtils.cpp b/chromium/third_party/dawn/src/dawn/utils/TextureUtils.cpp
index f0c4505e6cd..b630a0c0e7f 100644
--- a/chromium/third_party/dawn/src/dawn/utils/TextureUtils.cpp
+++ b/chromium/third_party/dawn/src/dawn/utils/TextureUtils.cpp
@@ -130,6 +130,20 @@ bool IsDepthOnlyFormat(wgpu::TextureFormat textureFormat) {
}
}
+bool IsDepthOrStencilFormat(wgpu::TextureFormat textureFormat) {
+ switch (textureFormat) {
+ case wgpu::TextureFormat::Depth16Unorm:
+ case wgpu::TextureFormat::Depth24Plus:
+ case wgpu::TextureFormat::Depth32Float:
+ case wgpu::TextureFormat::Depth24PlusStencil8:
+ case wgpu::TextureFormat::Depth32FloatStencil8:
+ case wgpu::TextureFormat::Stencil8:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat) {
if (IsBCTextureFormat(textureFormat) || IsETC2TextureFormat(textureFormat) ||
IsASTCTextureFormat(textureFormat)) {
@@ -157,45 +171,6 @@ bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat) {
}
}
-bool TextureFormatSupportsRendering(wgpu::TextureFormat textureFormat) {
- switch (textureFormat) {
- case wgpu::TextureFormat::R8Unorm:
- case wgpu::TextureFormat::R8Uint:
- case wgpu::TextureFormat::R8Sint:
- case wgpu::TextureFormat::RG8Unorm:
- case wgpu::TextureFormat::RG8Uint:
- case wgpu::TextureFormat::RG8Sint:
- case wgpu::TextureFormat::RGBA8Unorm:
- case wgpu::TextureFormat::RGBA8Uint:
- case wgpu::TextureFormat::RGBA8Sint:
- case wgpu::TextureFormat::BGRA8Unorm:
- case wgpu::TextureFormat::BGRA8UnormSrgb:
- case wgpu::TextureFormat::R16Uint:
- case wgpu::TextureFormat::R16Sint:
- case wgpu::TextureFormat::R16Float:
- case wgpu::TextureFormat::RG16Uint:
- case wgpu::TextureFormat::RG16Sint:
- case wgpu::TextureFormat::RG16Float:
- case wgpu::TextureFormat::RGBA16Uint:
- case wgpu::TextureFormat::RGBA16Sint:
- case wgpu::TextureFormat::RGBA16Float:
- case wgpu::TextureFormat::R32Uint:
- case wgpu::TextureFormat::R32Sint:
- case wgpu::TextureFormat::R32Float:
- case wgpu::TextureFormat::RG32Uint:
- case wgpu::TextureFormat::RG32Sint:
- case wgpu::TextureFormat::RG32Float:
- case wgpu::TextureFormat::RGBA32Uint:
- case wgpu::TextureFormat::RGBA32Sint:
- case wgpu::TextureFormat::RGBA32Float:
- case wgpu::TextureFormat::RGB10A2Unorm:
- return true;
-
- default:
- return false;
- }
-}
-
bool TextureFormatSupportsResolveTarget(wgpu::TextureFormat textureFormat) {
switch (textureFormat) {
case wgpu::TextureFormat::R8Unorm:
@@ -272,7 +247,6 @@ uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat) {
return 2u;
case wgpu::TextureFormat::Depth24Plus:
- case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth32Float:
return 4u;
@@ -392,7 +366,6 @@ uint32_t GetTextureFormatBlockWidth(wgpu::TextureFormat textureFormat) {
case wgpu::TextureFormat::Depth24Plus:
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth16Unorm:
- case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
return 1u;
@@ -509,7 +482,6 @@ uint32_t GetTextureFormatBlockHeight(wgpu::TextureFormat textureFormat) {
case wgpu::TextureFormat::Depth24Plus:
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth16Unorm:
- case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
return 1u;
diff --git a/chromium/third_party/dawn/src/dawn/utils/TextureUtils.h b/chromium/third_party/dawn/src/dawn/utils/TextureUtils.h
index f92b19b518f..964df100238 100644
--- a/chromium/third_party/dawn/src/dawn/utils/TextureUtils.h
+++ b/chromium/third_party/dawn/src/dawn/utils/TextureUtils.h
@@ -22,7 +22,7 @@
#include "dawn/common/Assert.h"
namespace utils {
-static constexpr std::array<wgpu::TextureFormat, 95> kAllTextureFormats = {
+static constexpr std::array<wgpu::TextureFormat, 94> kAllTextureFormats = {
wgpu::TextureFormat::R8Unorm,
wgpu::TextureFormat::R8Snorm,
wgpu::TextureFormat::R8Uint,
@@ -63,7 +63,6 @@ static constexpr std::array<wgpu::TextureFormat, 95> kAllTextureFormats = {
wgpu::TextureFormat::Depth32Float,
wgpu::TextureFormat::Depth24Plus,
wgpu::TextureFormat::Depth24PlusStencil8,
- wgpu::TextureFormat::Depth24UnormStencil8,
wgpu::TextureFormat::Depth32FloatStencil8,
wgpu::TextureFormat::Stencil8,
wgpu::TextureFormat::BC1RGBAUnorm,
@@ -206,20 +205,18 @@ static_assert(kCompressedFormats.size() ==
kBCFormats.size() + kETC2Formats.size() + kASTCFormats.size(),
"Number of compressed format must equal number of BC, ETC2, and ASTC formats.");
-static constexpr std::array<wgpu::TextureFormat, 6> kDepthFormats = {
+static constexpr std::array<wgpu::TextureFormat, 5> kDepthFormats = {
wgpu::TextureFormat::Depth16Unorm, wgpu::TextureFormat::Depth32Float,
wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Depth24PlusStencil8,
- wgpu::TextureFormat::Depth24UnormStencil8, wgpu::TextureFormat::Depth32FloatStencil8,
+ wgpu::TextureFormat::Depth32FloatStencil8,
};
-static constexpr std::array<wgpu::TextureFormat, 4> kStencilFormats = {
+static constexpr std::array<wgpu::TextureFormat, 3> kStencilFormats = {
wgpu::TextureFormat::Depth24PlusStencil8,
- wgpu::TextureFormat::Depth24UnormStencil8,
wgpu::TextureFormat::Depth32FloatStencil8,
wgpu::TextureFormat::Stencil8,
};
-static constexpr std::array<wgpu::TextureFormat, 3> kDepthAndStencilFormats = {
+static constexpr std::array<wgpu::TextureFormat, 2> kDepthAndStencilFormats = {
wgpu::TextureFormat::Depth24PlusStencil8,
- wgpu::TextureFormat::Depth24UnormStencil8,
wgpu::TextureFormat::Depth32FloatStencil8,
};
@@ -231,10 +228,10 @@ bool IsASTCTextureFormat(wgpu::TextureFormat textureFormat);
bool IsDepthOnlyFormat(wgpu::TextureFormat textureFormat);
bool IsStencilOnlyFormat(wgpu::TextureFormat textureFormat);
+bool IsDepthOrStencilFormat(wgpu::TextureFormat textureFormat);
bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat);
bool TextureFormatSupportsResolveTarget(wgpu::TextureFormat textureFormat);
-bool TextureFormatSupportsRendering(wgpu::TextureFormat textureFormat);
uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat);
uint32_t GetTextureFormatBlockWidth(wgpu::TextureFormat textureFormat);
diff --git a/chromium/third_party/dawn/src/dawn/utils/WireHelper.h b/chromium/third_party/dawn/src/dawn/utils/WireHelper.h
index a81b919e12b..3f529385327 100644
--- a/chromium/third_party/dawn/src/dawn/utils/WireHelper.h
+++ b/chromium/third_party/dawn/src/dawn/utils/WireHelper.h
@@ -21,6 +21,8 @@
#include "dawn/webgpu_cpp.h"
+struct DawnProcTable;
+
namespace utils {
class WireHelper {
diff --git a/chromium/third_party/dawn/src/dawn/wire/BUILD.gn b/chromium/third_party/dawn/src/dawn/wire/BUILD.gn
index 7189bd5fd35..56aa0388790 100644
--- a/chromium/third_party/dawn/src/dawn/wire/BUILD.gn
+++ b/chromium/third_party/dawn/src/dawn/wire/BUILD.gn
@@ -65,6 +65,8 @@ dawn_component("wire") {
"ChunkedCommandHandler.h",
"ChunkedCommandSerializer.cpp",
"ChunkedCommandSerializer.h",
+ "ObjectHandle.cpp",
+ "ObjectHandle.h",
"SupportedFeatures.cpp",
"SupportedFeatures.h",
"Wire.cpp",
@@ -88,9 +90,10 @@ dawn_component("wire") {
"client/Instance.h",
"client/LimitsAndFeatures.cpp",
"client/LimitsAndFeatures.h",
- "client/ObjectAllocator.h",
"client/ObjectBase.cpp",
"client/ObjectBase.h",
+ "client/ObjectStore.cpp",
+ "client/ObjectStore.h",
"client/QuerySet.cpp",
"client/QuerySet.h",
"client/Queue.cpp",
diff --git a/chromium/third_party/dawn/src/dawn/wire/CMakeLists.txt b/chromium/third_party/dawn/src/dawn/wire/CMakeLists.txt
index e389b43c9bc..c470cea0713 100644
--- a/chromium/third_party/dawn/src/dawn/wire/CMakeLists.txt
+++ b/chromium/third_party/dawn/src/dawn/wire/CMakeLists.txt
@@ -38,6 +38,8 @@ target_sources(dawn_wire PRIVATE
"ChunkedCommandHandler.h"
"ChunkedCommandSerializer.cpp"
"ChunkedCommandSerializer.h"
+ "ObjectHandle.cpp"
+ "ObjectHandle.h"
"SupportedFeatures.cpp"
"SupportedFeatures.h"
"Wire.cpp"
@@ -61,7 +63,8 @@ target_sources(dawn_wire PRIVATE
"client/Instance.h"
"client/LimitsAndFeatures.cpp"
"client/LimitsAndFeatures.h"
- "client/ObjectAllocator.h"
+ "client/ObjectStore.cpp"
+ "client/ObjectStore.h"
"client/ObjectBase.cpp"
"client/ObjectBase.h"
"client/QuerySet.cpp"
diff --git a/chromium/third_party/dawn/src/dawn/wire/ObjectHandle.cpp b/chromium/third_party/dawn/src/dawn/wire/ObjectHandle.cpp
new file mode 100644
index 00000000000..62d9f80f8d4
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/wire/ObjectHandle.cpp
@@ -0,0 +1,44 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/wire/ObjectHandle.h"
+
+namespace dawn::wire {
+
+ObjectHandle::ObjectHandle() = default;
+ObjectHandle::ObjectHandle(ObjectId id, ObjectGeneration generation)
+ : id(id), generation(generation) {}
+
+ObjectHandle::ObjectHandle(const volatile ObjectHandle& rhs)
+ : id(rhs.id), generation(rhs.generation) {}
+ObjectHandle& ObjectHandle::operator=(const volatile ObjectHandle& rhs) {
+ id = rhs.id;
+ generation = rhs.generation;
+ return *this;
+}
+
+ObjectHandle::ObjectHandle(const ObjectHandle& rhs) = default;
+ObjectHandle& ObjectHandle::operator=(const ObjectHandle& rhs) = default;
+
+ObjectHandle& ObjectHandle::AssignFrom(const ObjectHandle& rhs) {
+ id = rhs.id;
+ generation = rhs.generation;
+ return *this;
+}
+ObjectHandle& ObjectHandle::AssignFrom(const volatile ObjectHandle& rhs) {
+ id = rhs.id;
+ generation = rhs.generation;
+ return *this;
+}
+} // namespace dawn::wire
diff --git a/chromium/third_party/dawn/src/dawn/wire/ObjectHandle.h b/chromium/third_party/dawn/src/dawn/wire/ObjectHandle.h
new file mode 100644
index 00000000000..3e6cf64e7c8
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/wire/ObjectHandle.h
@@ -0,0 +1,49 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef DAWN_WIRE_OBJECTHANDLE_H_
+#define DAWN_WIRE_OBJECTHANDLE_H_
+
+#include <cstdint>
+
+namespace dawn::wire {
+
+using ObjectId = uint32_t;
+using ObjectGeneration = uint32_t;
+struct ObjectHandle {
+ ObjectId id;
+ ObjectGeneration generation;
+
+ ObjectHandle();
+ ObjectHandle(ObjectId id, ObjectGeneration generation);
+
+ explicit ObjectHandle(const volatile ObjectHandle& rhs);
+ ObjectHandle& operator=(const volatile ObjectHandle& rhs);
+
+ ObjectHandle(const ObjectHandle& rhs);
+ ObjectHandle& operator=(const ObjectHandle& rhs);
+
+ // MSVC has a bug where it thinks the volatile copy assignment is a duplicate.
+ // Workaround this by forwarding to a different function AssignFrom.
+ template <typename T>
+ ObjectHandle& operator=(const T& rhs) {
+ return AssignFrom(rhs);
+ }
+ ObjectHandle& AssignFrom(const ObjectHandle& rhs);
+ ObjectHandle& AssignFrom(const volatile ObjectHandle& rhs);
+};
+
+} // namespace dawn::wire
+
+#endif // DAWN_WIRE_OBJECTHANDLE_H_
diff --git a/chromium/third_party/dawn/src/dawn/wire/SupportedFeatures.cpp b/chromium/third_party/dawn/src/dawn/wire/SupportedFeatures.cpp
index 0e5688a1193..aca064fa9c2 100644
--- a/chromium/third_party/dawn/src/dawn/wire/SupportedFeatures.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/SupportedFeatures.cpp
@@ -24,7 +24,6 @@ bool IsFeatureSupported(WGPUFeatureName feature) {
case WGPUFeatureName_Force32:
case WGPUFeatureName_DawnNative:
return false;
- case WGPUFeatureName_Depth24UnormStencil8:
case WGPUFeatureName_Depth32FloatStencil8:
case WGPUFeatureName_TimestampQuery:
case WGPUFeatureName_PipelineStatisticsQuery:
@@ -32,7 +31,7 @@ bool IsFeatureSupported(WGPUFeatureName feature) {
case WGPUFeatureName_TextureCompressionETC2:
case WGPUFeatureName_TextureCompressionASTC:
case WGPUFeatureName_IndirectFirstInstance:
- case WGPUFeatureName_DepthClamping:
+ case WGPUFeatureName_DepthClipControl:
case WGPUFeatureName_DawnShaderFloat16:
case WGPUFeatureName_DawnInternalUsages:
case WGPUFeatureName_DawnMultiPlanarFormats:
diff --git a/chromium/third_party/dawn/src/dawn/wire/WireClient.cpp b/chromium/third_party/dawn/src/dawn/wire/WireClient.cpp
index 624cc032d85..9845b3844fa 100644
--- a/chromium/third_party/dawn/src/dawn/wire/WireClient.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/WireClient.cpp
@@ -28,8 +28,9 @@ const volatile char* WireClient::HandleCommands(const volatile char* commands, s
return mImpl->HandleCommands(commands, size);
}
-ReservedTexture WireClient::ReserveTexture(WGPUDevice device) {
- return mImpl->ReserveTexture(device);
+ReservedTexture WireClient::ReserveTexture(WGPUDevice device,
+ const WGPUTextureDescriptor* descriptor) {
+ return mImpl->ReserveTexture(device, descriptor);
}
ReservedSwapChain WireClient::ReserveSwapChain(WGPUDevice device) {
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Adapter.cpp b/chromium/third_party/dawn/src/dawn/wire/client/Adapter.cpp
index 3e9cbd2ac75..6edf63c813e 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Adapter.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Adapter.cpp
@@ -19,8 +19,6 @@
namespace dawn::wire::client {
-Adapter::Adapter(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {}
-
Adapter::~Adapter() {
mRequestDeviceRequests.CloseAll([](RequestDeviceData* request) {
request->callback(WGPURequestDeviceStatus_Unknown, nullptr,
@@ -67,18 +65,19 @@ void Adapter::GetProperties(WGPUAdapterProperties* properties) const {
void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback,
void* userdata) {
+ Client* client = GetClient();
if (client->IsDisconnected()) {
callback(WGPURequestDeviceStatus_Error, nullptr, "GPU connection lost", userdata);
return;
}
- auto* allocation = client->DeviceAllocator().New(client);
- uint64_t serial = mRequestDeviceRequests.Add({callback, allocation->object->id, userdata});
+ Device* device = client->Make<Device>();
+ uint64_t serial = mRequestDeviceRequests.Add({callback, device->GetWireId(), userdata});
AdapterRequestDeviceCmd cmd;
- cmd.adapterId = this->id;
+ cmd.adapterId = GetWireId();
cmd.requestSerial = serial;
- cmd.deviceObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
+ cmd.deviceObjectHandle = device->GetWireHandle();
cmd.descriptor = descriptor;
client->SerializeCommand(cmd);
@@ -110,12 +109,13 @@ bool Adapter::OnRequestDeviceCallback(uint64_t requestSerial,
return false;
}
- Device* device = client->DeviceAllocator().GetObject(request.deviceObjectId);
+ Client* client = GetClient();
+ Device* device = client->Get<Device>(request.deviceObjectId);
// If the return status is a failure we should give a null device to the callback and
// free the allocation.
if (status != WGPURequestDeviceStatus_Success) {
- client->DeviceAllocator().Free(device);
+ client->Free(device);
request.callback(status, nullptr, message, request.userdata);
return true;
}
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Adapter.h b/chromium/third_party/dawn/src/dawn/wire/client/Adapter.h
index 024da0b2496..9c4b36fe382 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Adapter.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Adapter.h
@@ -27,8 +27,8 @@ namespace dawn::wire::client {
class Adapter final : public ObjectBase {
public:
- Adapter(Client* client, uint32_t refcount, uint32_t id);
- ~Adapter();
+ using ObjectBase::ObjectBase;
+ ~Adapter() override;
void CancelCallbacksForDisconnect() override;
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Buffer.cpp b/chromium/third_party/dawn/src/dawn/wire/client/Buffer.cpp
index eb9fa617d0d..32da663827f 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Buffer.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Buffer.cpp
@@ -26,7 +26,7 @@ namespace dawn::wire::client {
// static
WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor) {
- Client* wireClient = device->client;
+ Client* wireClient = device->GetClient();
bool mappable =
(descriptor->usage & (WGPUBufferUsage_MapRead | WGPUBufferUsage_MapWrite)) != 0 ||
@@ -40,7 +40,7 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
DeviceCreateBufferCmd cmd;
- cmd.deviceId = device->id;
+ cmd.deviceId = device->GetWireId();
cmd.descriptor = descriptor;
cmd.readHandleCreateInfoLength = 0;
cmd.readHandleCreateInfo = nullptr;
@@ -74,12 +74,7 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
// Create the buffer and send the creation command.
// This must happen after any potential device->CreateErrorBuffer()
// as server expects allocating ids to be monotonically increasing
- auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(wireClient);
- Buffer* buffer = bufferObjectAndSerial->object.get();
- buffer->mDevice = device;
- buffer->mDeviceIsAlive = device->GetAliveWeakPtr();
- buffer->mSize = descriptor->size;
- buffer->mUsage = static_cast<WGPUBufferUsage>(descriptor->usage);
+ Buffer* buffer = wireClient->Make<Buffer>(device, descriptor);
buffer->mDestructWriteHandleOnUnmap = false;
if (descriptor->mappedAtCreation) {
@@ -98,7 +93,7 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
buffer->mMappedData = writeHandle->GetData();
}
- cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->generation};
+ cmd.result = buffer->GetWireHandle();
wireClient->SerializeCommand(
cmd, cmd.readHandleCreateInfoLength + cmd.writeHandleCreateInfoLength,
@@ -126,21 +121,24 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
// static
WGPUBuffer Buffer::CreateError(Device* device, const WGPUBufferDescriptor* descriptor) {
- auto* allocation = device->client->BufferAllocator().New(device->client);
- allocation->object->mDevice = device;
- allocation->object->mDeviceIsAlive = device->GetAliveWeakPtr();
- allocation->object->mSize = descriptor->size;
- allocation->object->mUsage = static_cast<WGPUBufferUsage>(descriptor->usage);
+ Client* client = device->GetClient();
+ Buffer* buffer = client->Make<Buffer>(device, descriptor);
DeviceCreateErrorBufferCmd cmd;
cmd.self = ToAPI(device);
- cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
- device->client->SerializeCommand(cmd);
+ cmd.result = buffer->GetWireHandle();
+ client->SerializeCommand(cmd);
- return ToAPI(allocation->object.get());
+ return ToAPI(buffer);
}
-Buffer::Buffer(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {}
+Buffer::Buffer(const ObjectBaseParams& params,
+ Device* device,
+ const WGPUBufferDescriptor* descriptor)
+ : ObjectBase(params),
+ mSize(descriptor->size),
+ mUsage(static_cast<WGPUBufferUsage>(descriptor->usage)),
+ mDeviceIsAlive(device->GetAliveWeakPtr()) {}
Buffer::~Buffer() {
ClearAllCallbacks(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
@@ -164,6 +162,7 @@ void Buffer::MapAsync(WGPUMapModeFlags mode,
size_t size,
WGPUBufferMapCallback callback,
void* userdata) {
+ Client* client = GetClient();
if (client->IsDisconnected()) {
return callback(WGPUBufferMapAsyncStatus_DeviceLost, userdata);
}
@@ -190,7 +189,7 @@ void Buffer::MapAsync(WGPUMapModeFlags mode,
// Serialize the command to send to the server.
BufferMapAsyncCmd cmd;
- cmd.bufferId = this->id;
+ cmd.bufferId = GetWireId();
cmd.requestSerial = serial;
cmd.mode = mode;
cmd.offset = offset;
@@ -291,6 +290,7 @@ void Buffer::Unmap() {
// - Server -> Client: Result of MapRequest1
// - Unmap locally on the client
// - Server -> Client: Result of MapRequest2
+ Client* client = GetClient();
// mWriteHandle can still be nullptr if buffer has been destroyed before unmap
if ((mMapState == MapState::MappedForWrite || mMapState == MapState::MappedAtCreation) &&
@@ -303,7 +303,7 @@ void Buffer::Unmap() {
mWriteHandle->SizeOfSerializeDataUpdate(mMapOffset, mMapSize);
BufferUpdateMappedDataCmd cmd;
- cmd.bufferId = id;
+ cmd.bufferId = GetWireId();
cmd.writeDataUpdateInfoLength = writeDataUpdateInfoLength;
cmd.writeDataUpdateInfo = nullptr;
cmd.offset = mMapOffset;
@@ -353,6 +353,8 @@ void Buffer::Unmap() {
}
void Buffer::Destroy() {
+ Client* client = GetClient();
+
// Remove the current mapping and destroy Read/WriteHandles.
FreeMappedData();
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Buffer.h b/chromium/third_party/dawn/src/dawn/wire/client/Buffer.h
index 2644a4fe741..8040016233b 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Buffer.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Buffer.h
@@ -31,8 +31,8 @@ class Buffer final : public ObjectBase {
static WGPUBuffer Create(Device* device, const WGPUBufferDescriptor* descriptor);
static WGPUBuffer CreateError(Device* device, const WGPUBufferDescriptor* descriptor);
- Buffer(Client* client, uint32_t refcount, uint32_t id);
- ~Buffer();
+ Buffer(const ObjectBaseParams& params, Device* device, const WGPUBufferDescriptor* descriptor);
+ ~Buffer() override;
bool OnMapAsyncCallback(uint64_t requestSerial,
uint32_t status,
@@ -63,8 +63,6 @@ class Buffer final : public ObjectBase {
void FreeMappedData();
- Device* mDevice;
-
enum class MapRequestType { None, Read, Write };
enum class MapState {
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Client.cpp b/chromium/third_party/dawn/src/dawn/wire/client/Client.cpp
index f5fed4ddc18..57f3c57a8a6 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Client.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Client.cpp
@@ -59,9 +59,9 @@ void Client::DestroyAllObjects() {
DestroyObjectCmd cmd;
cmd.objectType = ObjectType::Device;
- cmd.objectId = object->id;
+ cmd.objectId = object->GetWireId();
SerializeCommand(cmd);
- FreeObject(ObjectType::Device, object);
+ mObjectStores[ObjectType::Device].Free(object);
}
for (auto& objectList : mObjects) {
@@ -74,71 +74,71 @@ void Client::DestroyAllObjects() {
DestroyObjectCmd cmd;
cmd.objectType = objectType;
- cmd.objectId = object->id;
+ cmd.objectId = object->GetWireId();
SerializeCommand(cmd);
- FreeObject(objectType, object);
+ mObjectStores[objectType].Free(object);
}
}
}
-ReservedTexture Client::ReserveTexture(WGPUDevice device) {
- auto* allocation = TextureAllocator().New(this);
+ReservedTexture Client::ReserveTexture(WGPUDevice device, const WGPUTextureDescriptor* descriptor) {
+ Texture* texture = Make<Texture>(descriptor);
ReservedTexture result;
- result.texture = ToAPI(allocation->object.get());
- result.id = allocation->object->id;
- result.generation = allocation->generation;
- result.deviceId = FromAPI(device)->id;
- result.deviceGeneration = DeviceAllocator().GetGeneration(FromAPI(device)->id);
+ result.texture = ToAPI(texture);
+ result.id = texture->GetWireId();
+ result.generation = texture->GetWireGeneration();
+ result.deviceId = FromAPI(device)->GetWireId();
+ result.deviceGeneration = FromAPI(device)->GetWireGeneration();
return result;
}
ReservedSwapChain Client::ReserveSwapChain(WGPUDevice device) {
- auto* allocation = SwapChainAllocator().New(this);
+ SwapChain* swapChain = Make<SwapChain>();
ReservedSwapChain result;
- result.swapchain = ToAPI(allocation->object.get());
- result.id = allocation->object->id;
- result.generation = allocation->generation;
- result.deviceId = FromAPI(device)->id;
- result.deviceGeneration = DeviceAllocator().GetGeneration(FromAPI(device)->id);
+ result.swapchain = ToAPI(swapChain);
+ result.id = swapChain->GetWireId();
+ result.generation = swapChain->GetWireGeneration();
+ result.deviceId = FromAPI(device)->GetWireId();
+ result.deviceGeneration = FromAPI(device)->GetWireGeneration();
return result;
}
ReservedDevice Client::ReserveDevice() {
- auto* allocation = DeviceAllocator().New(this);
+ Device* device = Make<Device>();
ReservedDevice result;
- result.device = ToAPI(allocation->object.get());
- result.id = allocation->object->id;
- result.generation = allocation->generation;
+ result.device = ToAPI(device);
+ result.id = device->GetWireId();
+ result.generation = device->GetWireGeneration();
return result;
}
ReservedInstance Client::ReserveInstance() {
- auto* allocation = InstanceAllocator().New(this);
+ Instance* instance = Make<Instance>();
ReservedInstance result;
- result.instance = ToAPI(allocation->object.get());
- result.id = allocation->object->id;
- result.generation = allocation->generation;
+ result.instance = ToAPI(instance);
+ result.id = instance->GetWireId();
+ result.generation = instance->GetWireGeneration();
return result;
}
void Client::ReclaimTextureReservation(const ReservedTexture& reservation) {
- TextureAllocator().Free(FromAPI(reservation.texture));
+ Free(FromAPI(reservation.texture));
}
void Client::ReclaimSwapChainReservation(const ReservedSwapChain& reservation) {
- SwapChainAllocator().Free(FromAPI(reservation.swapchain));
+ Free(FromAPI(reservation.swapchain));
}
void Client::ReclaimDeviceReservation(const ReservedDevice& reservation) {
- DeviceAllocator().Free(FromAPI(reservation.device));
+ Free(FromAPI(reservation.device));
}
void Client::ReclaimInstanceReservation(const ReservedInstance& reservation) {
- InstanceAllocator().Free(FromAPI(reservation.instance));
+ Free(FromAPI(reservation.instance));
}
void Client::Disconnect() {
@@ -165,4 +165,8 @@ bool Client::IsDisconnected() const {
return mDisconnected;
}
+void Client::Free(ObjectBase* obj, ObjectType type) {
+ mObjectStores[type].Free(obj);
+}
+
} // namespace dawn::wire::client
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Client.h b/chromium/third_party/dawn/src/dawn/wire/client/Client.h
index d045f0c06ed..8648522bd8b 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Client.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Client.h
@@ -16,6 +16,7 @@
#define SRC_DAWN_WIRE_CLIENT_CLIENT_H_
#include <memory>
+#include <utility>
#include "dawn/common/LinkedList.h"
#include "dawn/common/NonCopyable.h"
@@ -26,6 +27,7 @@
#include "dawn/wire/WireCmd_autogen.h"
#include "dawn/wire/WireDeserializeAllocator.h"
#include "dawn/wire/client/ClientBase_autogen.h"
+#include "dawn/wire/client/ObjectStore.h"
namespace dawn::wire::client {
@@ -37,12 +39,38 @@ class Client : public ClientBase {
Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService);
~Client() override;
+ // Make<T>(arg1, arg2, arg3) creates a new T, calling a constructor of the form:
+ //
+ // T::T(ObjectBaseParams, arg1, arg2, arg3)
+ template <typename T, typename... Args>
+ T* Make(Args&&... args) {
+ constexpr ObjectType type = ObjectTypeToTypeEnum<T>;
+
+ ObjectBaseParams params = {this, mObjectStores[type].ReserveHandle()};
+ T* object = new T(params, std::forward<Args>(args)...);
+
+ mObjects[type].Append(object);
+ mObjectStores[type].Insert(std::unique_ptr<T>(object));
+ return object;
+ }
+
+ template <typename T>
+ void Free(T* obj) {
+ Free(obj, ObjectTypeToTypeEnum<T>);
+ }
+ void Free(ObjectBase* obj, ObjectType type);
+
+ template <typename T>
+ T* Get(ObjectId id) {
+ return static_cast<T*>(mObjectStores[ObjectTypeToTypeEnum<T>].Get(id));
+ }
+
// ChunkedCommandHandler implementation
const volatile char* HandleCommandsImpl(const volatile char* commands, size_t size) override;
MemoryTransferService* GetMemoryTransferService() const { return mMemoryTransferService; }
- ReservedTexture ReserveTexture(WGPUDevice device);
+ ReservedTexture ReserveTexture(WGPUDevice device, const WGPUTextureDescriptor* descriptor);
ReservedSwapChain ReserveSwapChain(WGPUDevice device);
ReservedDevice ReserveDevice();
ReservedInstance ReserveInstance();
@@ -67,21 +95,16 @@ class Client : public ClientBase {
void Disconnect();
bool IsDisconnected() const;
- template <typename T>
- void TrackObject(T* object) {
- mObjects[ObjectTypeToTypeEnum<T>::value].Append(object);
- }
-
private:
void DestroyAllObjects();
#include "dawn/wire/client/ClientPrototypes_autogen.inc"
ChunkedCommandSerializer mSerializer;
- WireDeserializeAllocator mAllocator;
+ WireDeserializeAllocator mWireCommandAllocator;
+ PerObjectType<ObjectStore> mObjectStores;
MemoryTransferService* mMemoryTransferService = nullptr;
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
-
PerObjectType<LinkedList<ObjectBase>> mObjects;
bool mDisconnected = false;
};
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Device.cpp b/chromium/third_party/dawn/src/dawn/wire/client/Device.cpp
index 4b86888883f..ace00a1839b 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Device.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Device.cpp
@@ -20,12 +20,11 @@
#include "dawn/common/Log.h"
#include "dawn/wire/client/ApiObjects_autogen.h"
#include "dawn/wire/client/Client.h"
-#include "dawn/wire/client/ObjectAllocator.h"
namespace dawn::wire::client {
-Device::Device(Client* clientIn, uint32_t initialRefcount, uint32_t initialId)
- : ObjectBase(clientIn, initialRefcount, initialId), mIsAlive(std::make_shared<bool>()) {
+Device::Device(const ObjectBaseParams& params)
+ : ObjectBase(params), mIsAlive(std::make_shared<bool>()) {
#if defined(DAWN_ENABLE_ASSERTS)
mErrorCallback = [](WGPUErrorType, char const*, void*) {
static bool calledOnce = false;
@@ -151,6 +150,7 @@ void Device::SetDeviceLostCallback(WGPUDeviceLostCallback callback, void* userda
bool Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
// TODO(crbug.com/dawn/1324) Replace bool return with void when users are updated.
+ Client* client = GetClient();
if (client->IsDisconnected()) {
callback(WGPUErrorType_DeviceLost, "GPU device disconnected", userdata);
return true;
@@ -158,7 +158,7 @@ bool Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
uint64_t serial = mErrorScopes.Add({callback, userdata});
DevicePopErrorScopeCmd cmd;
- cmd.deviceId = this->id;
+ cmd.deviceId = GetWireId();
cmd.requestSerial = serial;
client->SerializeCommand(cmd);
return true;
@@ -192,7 +192,7 @@ void Device::InjectError(WGPUErrorType type, const char* message) {
cmd.self = ToAPI(this);
cmd.type = type;
cmd.message = message;
- client->SerializeCommand(cmd);
+ GetClient()->SerializeCommand(cmd);
}
WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) {
@@ -212,6 +212,10 @@ WGPUTexture Device::CreateTexture(const WGPUTextureDescriptor* descriptor) {
return Texture::Create(this, descriptor);
}
+WGPUTexture Device::CreateErrorTexture(const WGPUTextureDescriptor* descriptor) {
+ return Texture::CreateError(this, descriptor);
+}
+
WGPUQueue Device::GetQueue() {
// The queue is lazily created because if a Device is created by
// Reserve/Inject, we cannot send the GetQueue message until
@@ -219,42 +223,43 @@ WGPUQueue Device::GetQueue() {
// on construction.
if (mQueue == nullptr) {
// Get the primary queue for this device.
- auto* allocation = client->QueueAllocator().New(client);
- mQueue = allocation->object.get();
+ Client* client = GetClient();
+ mQueue = client->Make<Queue>();
DeviceGetQueueCmd cmd;
cmd.self = ToAPI(this);
- cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
+ cmd.result = mQueue->GetWireHandle();
client->SerializeCommand(cmd);
}
- mQueue->refcount++;
+ mQueue->Reference();
return ToAPI(mQueue);
}
void Device::CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
WGPUCreateComputePipelineAsyncCallback callback,
void* userdata) {
+ Client* client = GetClient();
if (client->IsDisconnected()) {
return callback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
"GPU device disconnected", userdata);
}
- auto* allocation = client->ComputePipelineAllocator().New(client);
+ ComputePipeline* pipeline = client->Make<ComputePipeline>();
CreatePipelineAsyncRequest request = {};
request.createComputePipelineAsyncCallback = callback;
request.userdata = userdata;
- request.pipelineObjectID = allocation->object->id;
+ request.pipelineObjectID = pipeline->GetWireId();
uint64_t serial = mCreatePipelineAsyncRequests.Add(std::move(request));
DeviceCreateComputePipelineAsyncCmd cmd;
- cmd.deviceId = this->id;
+ cmd.deviceId = GetWireId();
cmd.descriptor = descriptor;
cmd.requestSerial = serial;
- cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
+ cmd.pipelineObjectHandle = pipeline->GetWireHandle();
client->SerializeCommand(cmd);
}
@@ -267,45 +272,44 @@ bool Device::OnCreateComputePipelineAsyncCallback(uint64_t requestSerial,
return false;
}
- auto* pipelineAllocation =
- client->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
+ Client* client = GetClient();
+ ComputePipeline* pipeline = client->Get<ComputePipeline>(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
// free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
- client->ComputePipelineAllocator().Free(pipelineAllocation);
+ client->Free(pipeline);
request.createComputePipelineAsyncCallback(status, nullptr, message, request.userdata);
return true;
}
- WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation);
- request.createComputePipelineAsyncCallback(status, pipeline, message, request.userdata);
-
+ request.createComputePipelineAsyncCallback(status, ToAPI(pipeline), message, request.userdata);
return true;
}
void Device::CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descriptor,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata) {
+ Client* client = GetClient();
if (client->IsDisconnected()) {
return callback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
"GPU device disconnected", userdata);
}
- auto* allocation = client->RenderPipelineAllocator().New(client);
+ RenderPipeline* pipeline = client->Make<RenderPipeline>();
CreatePipelineAsyncRequest request = {};
request.createRenderPipelineAsyncCallback = callback;
request.userdata = userdata;
- request.pipelineObjectID = allocation->object->id;
+ request.pipelineObjectID = pipeline->GetWireId();
uint64_t serial = mCreatePipelineAsyncRequests.Add(std::move(request));
DeviceCreateRenderPipelineAsyncCmd cmd;
- cmd.deviceId = this->id;
+ cmd.deviceId = GetWireId();
cmd.descriptor = descriptor;
cmd.requestSerial = serial;
- cmd.pipelineObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
+ cmd.pipelineObjectHandle = pipeline->GetWireHandle();
client->SerializeCommand(cmd);
}
@@ -318,20 +322,18 @@ bool Device::OnCreateRenderPipelineAsyncCallback(uint64_t requestSerial,
return false;
}
- auto* pipelineAllocation =
- client->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
+ Client* client = GetClient();
+ RenderPipeline* pipeline = client->Get<RenderPipeline>(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
// free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
- client->RenderPipelineAllocator().Free(pipelineAllocation);
+ client->Free(pipeline);
request.createRenderPipelineAsyncCallback(status, nullptr, message, request.userdata);
return true;
}
- WGPURenderPipeline pipeline = reinterpret_cast<WGPURenderPipeline>(pipelineAllocation);
- request.createRenderPipelineAsyncCallback(status, pipeline, message, request.userdata);
-
+ request.createRenderPipelineAsyncCallback(status, ToAPI(pipeline), message, request.userdata);
return true;
}
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Device.h b/chromium/third_party/dawn/src/dawn/wire/client/Device.h
index f932607cdd6..d1af3432fd4 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Device.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Device.h
@@ -32,8 +32,8 @@ class Queue;
class Device final : public ObjectBase {
public:
- Device(Client* client, uint32_t refcount, uint32_t id);
- ~Device();
+ explicit Device(const ObjectBaseParams& params);
+ ~Device() override;
void SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata);
void SetLoggingCallback(WGPULoggingCallback errorCallback, void* errorUserdata);
@@ -52,6 +52,7 @@ class Device final : public ObjectBase {
void* userdata);
WGPUQuerySet CreateQuerySet(const WGPUQuerySetDescriptor* descriptor);
WGPUTexture CreateTexture(const WGPUTextureDescriptor* descriptor);
+ WGPUTexture CreateErrorTexture(const WGPUTextureDescriptor* descriptor);
void HandleError(WGPUErrorType errorType, const char* message);
void HandleLogging(WGPULoggingType loggingType, const char* message);
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Instance.cpp b/chromium/third_party/dawn/src/dawn/wire/client/Instance.cpp
index 8e441d97276..efd9b74103e 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Instance.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Instance.cpp
@@ -18,8 +18,6 @@
namespace dawn::wire::client {
-Instance::Instance(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {}
-
Instance::~Instance() {
mRequestAdapterRequests.CloseAll([](RequestAdapterData* request) {
request->callback(WGPURequestAdapterStatus_Unknown, nullptr,
@@ -37,18 +35,19 @@ void Instance::CancelCallbacksForDisconnect() {
void Instance::RequestAdapter(const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata) {
+ Client* client = GetClient();
if (client->IsDisconnected()) {
callback(WGPURequestAdapterStatus_Error, nullptr, "GPU connection lost", userdata);
return;
}
- auto* allocation = client->AdapterAllocator().New(client);
- uint64_t serial = mRequestAdapterRequests.Add({callback, allocation->object->id, userdata});
+ Adapter* adapter = client->Make<Adapter>();
+ uint64_t serial = mRequestAdapterRequests.Add({callback, adapter->GetWireId(), userdata});
InstanceRequestAdapterCmd cmd;
- cmd.instanceId = this->id;
+ cmd.instanceId = GetWireId();
cmd.requestSerial = serial;
- cmd.adapterObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
+ cmd.adapterObjectHandle = adapter->GetWireHandle();
cmd.options = options;
client->SerializeCommand(cmd);
@@ -82,12 +81,13 @@ bool Instance::OnRequestAdapterCallback(uint64_t requestSerial,
return false;
}
- Adapter* adapter = client->AdapterAllocator().GetObject(request.adapterObjectId);
+ Client* client = GetClient();
+ Adapter* adapter = client->Get<Adapter>(request.adapterObjectId);
// If the return status is a failure we should give a null adapter to the callback and
// free the allocation.
if (status != WGPURequestAdapterStatus_Success) {
- client->AdapterAllocator().Free(adapter);
+ client->Free(adapter);
request.callback(status, nullptr, message, request.userdata);
return true;
}
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Instance.h b/chromium/third_party/dawn/src/dawn/wire/client/Instance.h
index 625bd96b576..14005658905 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Instance.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Instance.h
@@ -26,8 +26,8 @@ namespace dawn::wire::client {
class Instance final : public ObjectBase {
public:
- Instance(Client* client, uint32_t refcount, uint32_t id);
- ~Instance();
+ using ObjectBase::ObjectBase;
+ ~Instance() override;
void CancelCallbacksForDisconnect() override;
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/ObjectAllocator.h b/chromium/third_party/dawn/src/dawn/wire/client/ObjectAllocator.h
deleted file mode 100644
index 60b8fa875f5..00000000000
--- a/chromium/third_party/dawn/src/dawn/wire/client/ObjectAllocator.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2019 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_DAWN_WIRE_CLIENT_OBJECTALLOCATOR_H_
-#define SRC_DAWN_WIRE_CLIENT_OBJECTALLOCATOR_H_
-
-#include <limits>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "dawn/common/Assert.h"
-#include "dawn/common/Compiler.h"
-#include "dawn/wire/WireCmd_autogen.h"
-
-namespace dawn::wire::client {
-
-template <typename T>
-class ObjectAllocator {
- public:
- struct ObjectAndSerial {
- ObjectAndSerial(std::unique_ptr<T> object, uint32_t generation)
- : object(std::move(object)), generation(generation) {}
- std::unique_ptr<T> object;
- uint32_t generation;
- };
-
- ObjectAllocator() {
- // ID 0 is nullptr
- mObjects.emplace_back(nullptr, 0);
- }
-
- template <typename Client>
- ObjectAndSerial* New(Client* client) {
- uint32_t id = GetNewId();
- auto object = std::make_unique<T>(client, 1, id);
- client->TrackObject(object.get());
-
- if (id >= mObjects.size()) {
- ASSERT(id == mObjects.size());
- mObjects.emplace_back(std::move(object), 0);
- } else {
- ASSERT(mObjects[id].object == nullptr);
-
- mObjects[id].generation++;
- // The generation should never overflow. We don't recycle ObjectIds that would
- // overflow their next generation.
- ASSERT(mObjects[id].generation != 0);
-
- mObjects[id].object = std::move(object);
- }
-
- return &mObjects[id];
- }
- void Free(T* obj) {
- ASSERT(obj->IsInList());
- if (DAWN_LIKELY(mObjects[obj->id].generation != std::numeric_limits<uint32_t>::max())) {
- // Only recycle this ObjectId if the generation won't overflow on the next
- // allocation.
- FreeId(obj->id);
- }
- mObjects[obj->id].object = nullptr;
- }
-
- T* GetObject(uint32_t id) {
- if (id >= mObjects.size()) {
- return nullptr;
- }
- return mObjects[id].object.get();
- }
-
- uint32_t GetGeneration(uint32_t id) {
- if (id >= mObjects.size()) {
- return 0;
- }
- return mObjects[id].generation;
- }
-
- private:
- uint32_t GetNewId() {
- if (mFreeIds.empty()) {
- return mCurrentId++;
- }
- uint32_t id = mFreeIds.back();
- mFreeIds.pop_back();
- return id;
- }
- void FreeId(uint32_t id) { mFreeIds.push_back(id); }
-
- // 0 is an ID reserved to represent nullptr
- uint32_t mCurrentId = 1;
- std::vector<uint32_t> mFreeIds;
- std::vector<ObjectAndSerial> mObjects;
-};
-} // namespace dawn::wire::client
-
-#endif // SRC_DAWN_WIRE_CLIENT_OBJECTALLOCATOR_H_
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.cpp b/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.cpp
index 1d581ef58fa..953a443b55a 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.cpp
@@ -14,13 +14,41 @@
#include "dawn/wire/client/ObjectBase.h"
+#include "dawn/common/Assert.h"
+
namespace dawn::wire::client {
-ObjectBase::ObjectBase(Client* client, uint32_t refcount, uint32_t id)
- : client(client), refcount(refcount), id(id) {}
+ObjectBase::ObjectBase(const ObjectBaseParams& params)
+ : mClient(params.client), mHandle(params.handle), mRefcount(1) {}
ObjectBase::~ObjectBase() {
RemoveFromList();
}
+const ObjectHandle& ObjectBase::GetWireHandle() const {
+ return mHandle;
+}
+
+ObjectId ObjectBase::GetWireId() const {
+ return mHandle.id;
+}
+
+ObjectGeneration ObjectBase::GetWireGeneration() const {
+ return mHandle.generation;
+}
+
+Client* ObjectBase::GetClient() const {
+ return mClient;
+}
+
+void ObjectBase::Reference() {
+ mRefcount++;
+}
+
+bool ObjectBase::Release() {
+ ASSERT(mRefcount != 0);
+ mRefcount--;
+ return mRefcount == 0;
+}
+
} // namespace dawn::wire::client
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.h b/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.h
index 417c7c7b64a..cf5f8ee7a26 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/ObjectBase.h
@@ -18,26 +18,43 @@
#include "dawn/webgpu.h"
#include "dawn/common/LinkedList.h"
-#include "dawn/wire/ObjectType_autogen.h"
+#include "dawn/wire/ObjectHandle.h"
namespace dawn::wire::client {
class Client;
+struct ObjectBaseParams {
+ Client* client;
+ ObjectHandle handle;
+};
+
// All objects on the client side have:
// - A pointer to the Client to get where to serialize commands
-// - The external reference count
+// - The external reference count, starting at 1.
// - An ID that is used to refer to this object when talking with the server side
// - A next/prev pointer. They are part of a linked list of objects of the same type.
-struct ObjectBase : public LinkNode<ObjectBase> {
- ObjectBase(Client* client, uint32_t refcount, uint32_t id);
- ~ObjectBase();
+class ObjectBase : public LinkNode<ObjectBase> {
+ public:
+ explicit ObjectBase(const ObjectBaseParams& params);
+ virtual ~ObjectBase();
virtual void CancelCallbacksForDisconnect() {}
- Client* const client;
- uint32_t refcount;
- const uint32_t id;
+ const ObjectHandle& GetWireHandle() const;
+ ObjectId GetWireId() const;
+ ObjectGeneration GetWireGeneration() const;
+ Client* GetClient() const;
+
+ void Reference();
+ // Returns true if it was the last reference, indicating that the caller must destroy the
+ // object.
+ [[nodiscard]] bool Release();
+
+ private:
+ Client* const mClient;
+ const ObjectHandle mHandle;
+ uint32_t mRefcount;
};
} // namespace dawn::wire::client
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.cpp b/chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.cpp
new file mode 100644
index 00000000000..299a67802f3
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.cpp
@@ -0,0 +1,72 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/wire/client/ObjectStore.h"
+
+#include <limits>
+#include <utility>
+
+namespace dawn::wire::client {
+
+ObjectStore::ObjectStore() {
+ // ID 0 is nullptr
+ mObjects.emplace_back(nullptr);
+ mCurrentId = 1;
+}
+
+ObjectHandle ObjectStore::ReserveHandle() {
+ if (mFreeHandles.empty()) {
+ return {mCurrentId++, 0};
+ }
+ ObjectHandle handle = mFreeHandles.back();
+ mFreeHandles.pop_back();
+ return handle;
+}
+
+void ObjectStore::Insert(std::unique_ptr<ObjectBase> obj) {
+ ObjectId id = obj->GetWireId();
+
+ if (id >= mObjects.size()) {
+ ASSERT(id == mObjects.size());
+ mObjects.emplace_back(std::move(obj));
+ } else {
+ // The generation should never overflow. We don't recycle ObjectIds that would
+ // overflow their next generation.
+ ASSERT(obj->GetWireGeneration() != 0);
+ ASSERT(mObjects[id] == nullptr);
+ mObjects[id] = std::move(obj);
+ }
+}
+
+void ObjectStore::Free(ObjectBase* obj) {
+ ASSERT(obj->IsInList());
+ // The wire reuses ID for objects to keep them in a packed array starting from 0.
+ // To avoid issues with asynchronous server->client communication referring to an ID that's
+ // already reused, each handle also has a generation that's increment by one on each reuse.
+ // Avoid overflows by only reusing the ID if the increment of the generation won't overflow.
+ const ObjectHandle& currentHandle = obj->GetWireHandle();
+ if (DAWN_LIKELY(currentHandle.generation != std::numeric_limits<ObjectGeneration>::max())) {
+ mFreeHandles.push_back({currentHandle.id, currentHandle.generation + 1});
+ }
+ mObjects[currentHandle.id] = nullptr;
+}
+
+ObjectBase* ObjectStore::Get(ObjectId id) const {
+ if (id >= mObjects.size()) {
+ return nullptr;
+ }
+ return mObjects[id].get();
+}
+
+} // namespace dawn::wire::client
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.h b/chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.h
new file mode 100644
index 00000000000..5d9b7415d0d
--- /dev/null
+++ b/chromium/third_party/dawn/src/dawn/wire/client/ObjectStore.h
@@ -0,0 +1,51 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_WIRE_CLIENT_OBJECTSTORE_H_
+#define SRC_DAWN_WIRE_CLIENT_OBJECTSTORE_H_
+
+#include <memory>
+#include <vector>
+
+#include "dawn/wire/client/ObjectBase.h"
+
+namespace dawn::wire::client {
+
+class Client;
+
+// A helper class used in Client, ObjectStore owns the association of some ObjectBase and
+// ObjectHandles. The lifetime of the ObjectBase is then owned by the ObjectStore, destruction
+// happening when Free is called.
+//
+// Since the wire has one "ID" namespace per type of object, each ObjectStore should contain a
+// single type of objects. However no templates are used because Client wraps ObjectStore and is
+// type-generic, so ObjectStore is type-erased to only work on ObjectBase.
+class ObjectStore {
+ public:
+ ObjectStore();
+
+ ObjectHandle ReserveHandle();
+ void Insert(std::unique_ptr<ObjectBase> obj);
+ void Free(ObjectBase* obj);
+ ObjectBase* Get(ObjectId id) const;
+
+ private:
+ uint32_t mCurrentId;
+ std::vector<ObjectHandle> mFreeHandles;
+ std::vector<std::unique_ptr<ObjectBase>> mObjects;
+};
+
+} // namespace dawn::wire::client
+
+#endif // SRC_DAWN_WIRE_CLIENT_OBJECTSTORE_H_
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.cpp b/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.cpp
index c9b1a2dac2b..6ecbaa4343a 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.cpp
@@ -21,26 +21,23 @@ namespace dawn::wire::client {
// static
WGPUQuerySet QuerySet::Create(Device* device, const WGPUQuerySetDescriptor* descriptor) {
- Client* wireClient = device->client;
- auto* objectAndSerial = wireClient->QuerySetAllocator().New(wireClient);
-
- // Copy over descriptor data for reflection.
- QuerySet* querySet = objectAndSerial->object.get();
- querySet->mType = descriptor->type;
- querySet->mCount = descriptor->count;
+ Client* wireClient = device->GetClient();
+ QuerySet* querySet = wireClient->Make<QuerySet>(descriptor);
// Send the Device::CreateQuerySet command without modifications.
DeviceCreateQuerySetCmd cmd;
cmd.self = ToAPI(device);
- cmd.selfId = device->id;
+ cmd.selfId = device->GetWireId();
cmd.descriptor = descriptor;
- cmd.result = ObjectHandle{querySet->id, objectAndSerial->generation};
+ cmd.result = querySet->GetWireHandle();
wireClient->SerializeCommand(cmd);
return ToAPI(querySet);
}
-QuerySet::QuerySet(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {}
+QuerySet::QuerySet(const ObjectBaseParams& params, const WGPUQuerySetDescriptor* descriptor)
+ : ObjectBase(params), mType(descriptor->type), mCount(descriptor->count) {}
+
QuerySet::~QuerySet() = default;
WGPUQueryType QuerySet::GetType() const {
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.h b/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.h
index 4afb9dc7c60..84c80999ab2 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/QuerySet.h
@@ -27,8 +27,8 @@ class QuerySet final : public ObjectBase {
public:
static WGPUQuerySet Create(Device* device, const WGPUQuerySetDescriptor* descriptor);
- QuerySet(Client* client, uint32_t refcount, uint32_t id);
- ~QuerySet();
+ QuerySet(const ObjectBaseParams& params, const WGPUQuerySetDescriptor* descriptor);
+ ~QuerySet() override;
// Note that these values can be arbitrary since they aren't validated in the wire client.
WGPUQueryType GetType() const;
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Queue.cpp b/chromium/third_party/dawn/src/dawn/wire/client/Queue.cpp
index 618f99c65a1..bc5a4bbd281 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Queue.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Queue.cpp
@@ -19,8 +19,6 @@
namespace dawn::wire::client {
-Queue::Queue(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {}
-
Queue::~Queue() {
ClearAllCallbacks(WGPUQueueWorkDoneStatus_Unknown);
}
@@ -38,6 +36,7 @@ bool Queue::OnWorkDoneCallback(uint64_t requestSerial, WGPUQueueWorkDoneStatus s
void Queue::OnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneCallback callback,
void* userdata) {
+ Client* client = GetClient();
if (client->IsDisconnected()) {
callback(WGPUQueueWorkDoneStatus_DeviceLost, userdata);
return;
@@ -46,7 +45,7 @@ void Queue::OnSubmittedWorkDone(uint64_t signalValue,
uint64_t serial = mOnWorkDoneRequests.Add({callback, userdata});
QueueOnSubmittedWorkDoneCmd cmd;
- cmd.queueId = this->id;
+ cmd.queueId = GetWireId();
cmd.signalValue = signalValue;
cmd.requestSerial = serial;
@@ -57,13 +56,13 @@ void Queue::WriteBuffer(WGPUBuffer cBuffer, uint64_t bufferOffset, const void* d
Buffer* buffer = FromAPI(cBuffer);
QueueWriteBufferCmd cmd;
- cmd.queueId = id;
- cmd.bufferId = buffer->id;
+ cmd.queueId = GetWireId();
+ cmd.bufferId = buffer->GetWireId();
cmd.bufferOffset = bufferOffset;
cmd.data = static_cast<const uint8_t*>(data);
cmd.size = size;
- client->SerializeCommand(cmd);
+ GetClient()->SerializeCommand(cmd);
}
void Queue::WriteTexture(const WGPUImageCopyTexture* destination,
@@ -72,14 +71,14 @@ void Queue::WriteTexture(const WGPUImageCopyTexture* destination,
const WGPUTextureDataLayout* dataLayout,
const WGPUExtent3D* writeSize) {
QueueWriteTextureCmd cmd;
- cmd.queueId = id;
+ cmd.queueId = GetWireId();
cmd.destination = destination;
cmd.data = static_cast<const uint8_t*>(data);
cmd.dataSize = dataSize;
cmd.dataLayout = dataLayout;
cmd.writeSize = writeSize;
- client->SerializeCommand(cmd);
+ GetClient()->SerializeCommand(cmd);
}
void Queue::CancelCallbacksForDisconnect() {
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Queue.h b/chromium/third_party/dawn/src/dawn/wire/client/Queue.h
index 35e583ebe41..28424c0b457 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Queue.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Queue.h
@@ -25,8 +25,8 @@ namespace dawn::wire::client {
class Queue final : public ObjectBase {
public:
- Queue(Client* client, uint32_t refcount, uint32_t id);
- ~Queue();
+ using ObjectBase::ObjectBase;
+ ~Queue() override;
bool OnWorkDoneCallback(uint64_t requestSerial, WGPUQueueWorkDoneStatus status);
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.cpp b/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.cpp
index 63bc534b371..bcf1d6fbfa0 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.cpp
@@ -18,13 +18,12 @@
namespace dawn::wire::client {
-ShaderModule::ShaderModule(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {}
-
ShaderModule::~ShaderModule() {
ClearAllCallbacks(WGPUCompilationInfoRequestStatus_Unknown);
}
void ShaderModule::GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata) {
+ Client* client = GetClient();
if (client->IsDisconnected()) {
callback(WGPUCompilationInfoRequestStatus_DeviceLost, nullptr, userdata);
return;
@@ -33,7 +32,7 @@ void ShaderModule::GetCompilationInfo(WGPUCompilationInfoCallback callback, void
uint64_t serial = mCompilationInfoRequests.Add({callback, userdata});
ShaderModuleGetCompilationInfoCmd cmd;
- cmd.shaderModuleId = this->id;
+ cmd.shaderModuleId = GetWireId();
cmd.requestSerial = serial;
client->SerializeCommand(cmd);
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.h b/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.h
index 5ae920d8bc1..c6d4153b638 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/ShaderModule.h
@@ -24,8 +24,8 @@ namespace dawn::wire::client {
class ShaderModule final : public ObjectBase {
public:
- ShaderModule(Client* client, uint32_t refcount, uint32_t id);
- ~ShaderModule();
+ using ObjectBase::ObjectBase;
+ ~ShaderModule() override;
void GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata);
bool GetCompilationInfoCallback(uint64_t requestSerial,
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Texture.cpp b/chromium/third_party/dawn/src/dawn/wire/client/Texture.cpp
index f4c0b972365..69f773e424b 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Texture.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Texture.cpp
@@ -21,30 +21,45 @@ namespace dawn::wire::client {
// static
WGPUTexture Texture::Create(Device* device, const WGPUTextureDescriptor* descriptor) {
- Client* wireClient = device->client;
- auto* textureObjectAndSerial = wireClient->TextureAllocator().New(wireClient);
-
- // Copy over descriptor data for reflection.
- Texture* texture = textureObjectAndSerial->object.get();
- texture->mSize = descriptor->size;
- texture->mMipLevelCount = descriptor->mipLevelCount;
- texture->mSampleCount = descriptor->sampleCount;
- texture->mDimension = descriptor->dimension;
- texture->mFormat = descriptor->format;
- texture->mUsage = static_cast<WGPUTextureUsage>(descriptor->usage);
+ Client* wireClient = device->GetClient();
+ Texture* texture = wireClient->Make<Texture>(descriptor);
// Send the Device::CreateTexture command without modifications.
DeviceCreateTextureCmd cmd;
cmd.self = ToAPI(device);
- cmd.selfId = device->id;
+ cmd.selfId = device->GetWireId();
cmd.descriptor = descriptor;
- cmd.result = ObjectHandle{texture->id, textureObjectAndSerial->generation};
+ cmd.result = texture->GetWireHandle();
wireClient->SerializeCommand(cmd);
return ToAPI(texture);
}
-Texture::Texture(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {}
+// static
+WGPUTexture Texture::CreateError(Device* device, const WGPUTextureDescriptor* descriptor) {
+ Client* wireClient = device->GetClient();
+ Texture* texture = wireClient->Make<Texture>(descriptor);
+
+ // Send the Device::CreateErrorTexture command without modifications.
+ DeviceCreateErrorTextureCmd cmd;
+ cmd.self = ToAPI(device);
+ cmd.selfId = device->GetWireId();
+ cmd.descriptor = descriptor;
+ cmd.result = texture->GetWireHandle();
+ wireClient->SerializeCommand(cmd);
+
+ return ToAPI(texture);
+}
+
+Texture::Texture(const ObjectBaseParams& params, const WGPUTextureDescriptor* descriptor)
+ : ObjectBase(params),
+ mSize(descriptor->size),
+ mMipLevelCount(descriptor->mipLevelCount),
+ mSampleCount(descriptor->sampleCount),
+ mDimension(descriptor->dimension),
+ mFormat(descriptor->format),
+ mUsage(static_cast<WGPUTextureUsage>(descriptor->usage)) {}
+
Texture::~Texture() = default;
uint32_t Texture::GetWidth() const {
diff --git a/chromium/third_party/dawn/src/dawn/wire/client/Texture.h b/chromium/third_party/dawn/src/dawn/wire/client/Texture.h
index 0bce2ea66ca..9798f9174e8 100644
--- a/chromium/third_party/dawn/src/dawn/wire/client/Texture.h
+++ b/chromium/third_party/dawn/src/dawn/wire/client/Texture.h
@@ -26,9 +26,10 @@ class Device;
class Texture final : public ObjectBase {
public:
static WGPUTexture Create(Device* device, const WGPUTextureDescriptor* descriptor);
+ static WGPUTexture CreateError(Device* device, const WGPUTextureDescriptor* descriptor);
- Texture(Client* client, uint32_t refcount, uint32_t id);
- ~Texture();
+ Texture(const ObjectBaseParams& params, const WGPUTextureDescriptor* descriptor);
+ ~Texture() override;
// Note that these values can be arbitrary since they aren't validated in the wire client.
uint32_t GetWidth() const;
diff --git a/chromium/third_party/dawn/src/dawn/wire/server/ServerInlineMemoryTransferService.cpp b/chromium/third_party/dawn/src/dawn/wire/server/ServerInlineMemoryTransferService.cpp
index 6f5884a7984..84ecb7b1825 100644
--- a/chromium/third_party/dawn/src/dawn/wire/server/ServerInlineMemoryTransferService.cpp
+++ b/chromium/third_party/dawn/src/dawn/wire/server/ServerInlineMemoryTransferService.cpp
@@ -55,7 +55,7 @@ class InlineMemoryTransferService : public MemoryTransferService {
deserializePointer == nullptr) {
return false;
}
- if ((offset >= mDataLength && offset > 0) || size > mDataLength - offset) {
+ if (offset > mDataLength || size > mDataLength - offset) {
return false;
}
memcpy(static_cast<uint8_t*>(mTargetData) + offset, deserializePointer, size);
diff --git a/chromium/third_party/dawn/src/dawn_native/BUILD.gn b/chromium/third_party/dawn/src/dawn_native/BUILD.gn
deleted file mode 100644
index e811642bccc..00000000000
--- a/chromium/third_party/dawn/src/dawn_native/BUILD.gn
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2022 The Dawn Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-################################################################################
-# Build target aliases
-# TODO(crbug.com/dawn/1275) - remove these
-################################################################################
-group("dawn_native") {
- public_deps = [ "../dawn/native" ]
-}
-group("webgpu_dawn") {
- public_deps = [ "../dawn/native:webgpu_dawn" ]
-}
diff --git a/chromium/third_party/dawn/src/dawn_platform/BUILD.gn b/chromium/third_party/dawn/src/dawn_platform/BUILD.gn
deleted file mode 100644
index 92df854432c..00000000000
--- a/chromium/third_party/dawn/src/dawn_platform/BUILD.gn
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2022 The Dawn Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-################################################################################
-# Build target aliases
-# TODO(crbug.com/dawn/1275) - remove these
-################################################################################
-group("dawn_platform") {
- public_deps = [ "../dawn/platform" ]
-}
diff --git a/chromium/third_party/dawn/src/dawn_wire/BUILD.gn b/chromium/third_party/dawn/src/dawn_wire/BUILD.gn
deleted file mode 100644
index 13a9a903d33..00000000000
--- a/chromium/third_party/dawn/src/dawn_wire/BUILD.gn
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2022 The Dawn Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-################################################################################
-# Build target aliases
-# TODO(crbug.com/dawn/1275) - remove these
-################################################################################
-group("dawn_wire") {
- public_deps = [ "../dawn/wire" ]
-}
-group("dawn_wire_headers") {
- public_deps = [ "../dawn/wire:headers" ]
-}
diff --git a/chromium/third_party/dawn/src/fuzzers/dawn/BUILD.gn b/chromium/third_party/dawn/src/fuzzers/dawn/BUILD.gn
deleted file mode 100644
index a2756c70c42..00000000000
--- a/chromium/third_party/dawn/src/fuzzers/dawn/BUILD.gn
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2022 The Dawn Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-################################################################################
-# Build target aliases
-# TODO(crbug.com/dawn/1275) - remove these
-################################################################################
-group("dawn_fuzzers") {
- public_deps = [ "../../dawn/fuzzers" ]
- testonly = true
-}
diff --git a/chromium/third_party/dawn/src/include/README.md b/chromium/third_party/dawn/src/include/README.md
deleted file mode 100644
index 8111f628c57..00000000000
--- a/chromium/third_party/dawn/src/include/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# TODO(crbug.com/dawn/1275) - remove this directory
-
-This directory exists as a temporary include directory while migrating Chromium source to the new Dawn include layout.
-All headers in the subdirectories simply #include to the new location for the header.
diff --git a/chromium/third_party/dawn/src/include/dawn/webgpu.h b/chromium/third_party/dawn/src/include/dawn/webgpu.h
deleted file mode 100644
index 2fec78c3c27..00000000000
--- a/chromium/third_party/dawn/src/include/dawn/webgpu.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_WEBGPU_H_
-#define SRC_INCLUDE_DAWN_WEBGPU_H_
-
-#include "dawn/webgpu.h"
-
-#endif // SRC_INCLUDE_DAWN_WEBGPU_H_
diff --git a/chromium/third_party/dawn/src/include/dawn/webgpu_cpp.h b/chromium/third_party/dawn/src/include/dawn/webgpu_cpp.h
deleted file mode 100644
index 45ca2b211ab..00000000000
--- a/chromium/third_party/dawn/src/include/dawn/webgpu_cpp.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_WEBGPU_CPP_H_
-#define SRC_INCLUDE_DAWN_WEBGPU_CPP_H_
-
-#include "dawn/webgpu_cpp.h"
-
-#endif // SRC_INCLUDE_DAWN_WEBGPU_CPP_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_native/D3D12Backend.h b/chromium/third_party/dawn/src/include/dawn_native/D3D12Backend.h
deleted file mode 100644
index c740c81b0d9..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_native/D3D12Backend.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_NATIVE_D3D12BACKEND_H_
-#define SRC_INCLUDE_DAWN_NATIVE_D3D12BACKEND_H_
-
-#include "dawn/native/D3D12Backend.h"
-
-#endif // SRC_INCLUDE_DAWN_NATIVE_D3D12BACKEND_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_native/DawnNative.h b/chromium/third_party/dawn/src/include/dawn_native/DawnNative.h
deleted file mode 100644
index 197187f21bf..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_native/DawnNative.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_NATIVE_DAWNNATIVE_H_
-#define SRC_INCLUDE_DAWN_NATIVE_DAWNNATIVE_H_
-
-#include "dawn/native/DawnNative.h"
-
-#endif // SRC_INCLUDE_DAWN_NATIVE_DAWNNATIVE_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_native/MetalBackend.h b/chromium/third_party/dawn/src/include/dawn_native/MetalBackend.h
deleted file mode 100644
index 38ce8748f84..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_native/MetalBackend.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_NATIVE_METALBACKEND_H_
-#define SRC_INCLUDE_DAWN_NATIVE_METALBACKEND_H_
-
-#include "dawn/native/MetalBackend.h"
-
-#endif // SRC_INCLUDE_DAWN_NATIVE_METALBACKEND_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_native/NullBackend.h b/chromium/third_party/dawn/src/include/dawn_native/NullBackend.h
deleted file mode 100644
index e09f36b6514..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_native/NullBackend.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_NATIVE_NULLBACKEND_H_
-#define SRC_INCLUDE_DAWN_NATIVE_NULLBACKEND_H_
-
-#include "dawn/native/NullBackend.h"
-
-#endif // SRC_INCLUDE_DAWN_NATIVE_NULLBACKEND_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_native/OpenGLBackend.h b/chromium/third_party/dawn/src/include/dawn_native/OpenGLBackend.h
deleted file mode 100644
index 73800a0d943..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_native/OpenGLBackend.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_NATIVE_OPENGLBACKEND_H_
-#define SRC_INCLUDE_DAWN_NATIVE_OPENGLBACKEND_H_
-
-#include "dawn/native/OpenGLBackend.h"
-
-#endif // SRC_INCLUDE_DAWN_NATIVE_OPENGLBACKEND_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_native/VulkanBackend.h b/chromium/third_party/dawn/src/include/dawn_native/VulkanBackend.h
deleted file mode 100644
index 82e2e5304df..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_native/VulkanBackend.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_NATIVE_VULKANBACKEND_H_
-#define SRC_INCLUDE_DAWN_NATIVE_VULKANBACKEND_H_
-
-#include "dawn/native/VulkanBackend.h"
-
-#endif // SRC_INCLUDE_DAWN_NATIVE_VULKANBACKEND_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_native/dawn_native_export.h b/chromium/third_party/dawn/src/include/dawn_native/dawn_native_export.h
deleted file mode 100644
index 7edd9bc4e77..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_native/dawn_native_export.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_NATIVE_DAWN_NATIVE_EXPORT_H_
-#define SRC_INCLUDE_DAWN_NATIVE_DAWN_NATIVE_EXPORT_H_
-
-#include "dawn/native/dawn_native_export.h"
-
-#endif // SRC_INCLUDE_DAWN_NATIVE_DAWN_NATIVE_EXPORT_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_platform/DawnPlatform.h b/chromium/third_party/dawn/src/include/dawn_platform/DawnPlatform.h
deleted file mode 100644
index 75faafc91af..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_platform/DawnPlatform.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_PLATFORM_DAWNPLATFORM_H_
-#define SRC_INCLUDE_DAWN_PLATFORM_DAWNPLATFORM_H_
-
-#include "dawn/platform/DawnPlatform.h"
-
-#endif // SRC_INCLUDE_DAWN_PLATFORM_DAWNPLATFORM_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_wire/Wire.h b/chromium/third_party/dawn/src/include/dawn_wire/Wire.h
deleted file mode 100644
index 65924db21d3..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_wire/Wire.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_WIRE_WIRE_H_
-#define SRC_INCLUDE_DAWN_WIRE_WIRE_H_
-
-#include "dawn/wire/Wire.h"
-
-#endif // SRC_INCLUDE_DAWN_WIRE_WIRE_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_wire/WireClient.h b/chromium/third_party/dawn/src/include/dawn_wire/WireClient.h
deleted file mode 100644
index bf4b589f7ac..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_wire/WireClient.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_WIRE_WIRECLIENT_H_
-#define SRC_INCLUDE_DAWN_WIRE_WIRECLIENT_H_
-
-#include "dawn/wire/WireClient.h"
-
-#endif // SRC_INCLUDE_DAWN_WIRE_WIRECLIENT_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_wire/WireServer.h b/chromium/third_party/dawn/src/include/dawn_wire/WireServer.h
deleted file mode 100644
index d332eaec88f..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_wire/WireServer.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_WIRE_WIRESERVER_H_
-#define SRC_INCLUDE_DAWN_WIRE_WIRESERVER_H_
-
-#include "dawn/wire/WireServer.h"
-
-#endif // SRC_INCLUDE_DAWN_WIRE_WIRESERVER_H_
diff --git a/chromium/third_party/dawn/src/include/dawn_wire/dawn_wire_export.h b/chromium/third_party/dawn/src/include/dawn_wire/dawn_wire_export.h
deleted file mode 100644
index b1a885e502d..00000000000
--- a/chromium/third_party/dawn/src/include/dawn_wire/dawn_wire_export.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_DAWN_WIRE_DAWN_WIRE_EXPORT_H_
-#define SRC_INCLUDE_DAWN_WIRE_DAWN_WIRE_EXPORT_H_
-
-#include "dawn/wire/dawn_wire_export.h"
-
-#endif // SRC_INCLUDE_DAWN_WIRE_DAWN_WIRE_EXPORT_H_
diff --git a/chromium/third_party/dawn/src/include/webgpu/webgpu.h b/chromium/third_party/dawn/src/include/webgpu/webgpu.h
deleted file mode 100644
index afce939e547..00000000000
--- a/chromium/third_party/dawn/src/include/webgpu/webgpu.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_WEBGPU_WEBGPU_H_
-#define SRC_INCLUDE_WEBGPU_WEBGPU_H_
-
-#include "dawn/webgpu.h"
-
-#endif // SRC_INCLUDE_WEBGPU_WEBGPU_H_
diff --git a/chromium/third_party/dawn/src/include/webgpu/webgpu_cpp.h b/chromium/third_party/dawn/src/include/webgpu/webgpu_cpp.h
deleted file mode 100644
index adf4e4440db..00000000000
--- a/chromium/third_party/dawn/src/include/webgpu/webgpu_cpp.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_INCLUDE_WEBGPU_WEBGPU_CPP_H_
-#define SRC_INCLUDE_WEBGPU_WEBGPU_CPP_H_
-
-#include "dawn/webgpu_cpp.h"
-
-#endif // SRC_INCLUDE_WEBGPU_WEBGPU_CPP_H_
diff --git a/chromium/third_party/dawn/src/tint/BUILD.gn b/chromium/third_party/dawn/src/tint/BUILD.gn
index e7171a9e184..8e9a576faaf 100644
--- a/chromium/third_party/dawn/src/tint/BUILD.gn
+++ b/chromium/third_party/dawn/src/tint/BUILD.gn
@@ -13,8 +13,13 @@
# limitations under the License.
import("//build_overrides/build.gni")
+
import("../../tint_overrides_with_defaults.gni")
+if (tint_build_unittests) {
+ import("//testing/test.gni")
+}
+
###############################################################################
# Common - Configs, etc. shared across targets
###############################################################################
@@ -200,10 +205,10 @@ libtint_source_set("libtint_core_all_src") {
"ast/bool_literal_expression.h",
"ast/break_statement.cc",
"ast/break_statement.h",
- "ast/builtin.cc",
- "ast/builtin.h",
"ast/builtin_attribute.cc",
"ast/builtin_attribute.h",
+ "ast/builtin_value.cc",
+ "ast/builtin_value.h",
"ast/call_expression.cc",
"ast/call_expression.h",
"ast/call_statement.cc",
@@ -212,6 +217,8 @@ libtint_source_set("libtint_core_all_src") {
"ast/case_statement.h",
"ast/compound_assignment_statement.cc",
"ast/compound_assignment_statement.h",
+ "ast/const.cc",
+ "ast/const.h",
"ast/continue_statement.cc",
"ast/continue_statement.h",
"ast/depth_multisampled_texture.cc",
@@ -264,6 +271,8 @@ libtint_source_set("libtint_core_all_src") {
"ast/interpolate_attribute.h",
"ast/invariant_attribute.cc",
"ast/invariant_attribute.h",
+ "ast/let.cc",
+ "ast/let.h",
"ast/literal_expression.cc",
"ast/literal_expression.h",
"ast/location_attribute.cc",
@@ -280,6 +289,11 @@ libtint_source_set("libtint_core_all_src") {
"ast/multisampled_texture.h",
"ast/node.cc",
"ast/node.h",
+ "ast/node_id.h",
+ "ast/override.cc",
+ "ast/override.h",
+ "ast/parameter.cc",
+ "ast/parameter.h",
"ast/phony_expression.cc",
"ast/phony_expression.h",
"ast/pipeline_stage.cc",
@@ -296,6 +310,8 @@ libtint_source_set("libtint_core_all_src") {
"ast/stage_attribute.h",
"ast/statement.cc",
"ast/statement.h",
+ "ast/static_assert.cc",
+ "ast/static_assert.h",
"ast/storage_class.cc",
"ast/storage_class.h",
"ast/storage_texture.cc",
@@ -314,6 +330,8 @@ libtint_source_set("libtint_core_all_src") {
"ast/struct_member_size_attribute.h",
"ast/switch_statement.cc",
"ast/switch_statement.h",
+ "ast/texel_format.cc",
+ "ast/texel_format.h",
"ast/texture.cc",
"ast/texture.h",
"ast/traverse_expressions.h",
@@ -328,6 +346,8 @@ libtint_source_set("libtint_core_all_src") {
"ast/unary_op.h",
"ast/unary_op_expression.cc",
"ast/unary_op_expression.h",
+ "ast/var.cc",
+ "ast/var.h",
"ast/variable.cc",
"ast/variable.h",
"ast/variable_decl_statement.cc",
@@ -336,6 +356,8 @@ libtint_source_set("libtint_core_all_src") {
"ast/vector.h",
"ast/void.cc",
"ast/void.h",
+ "ast/while_statement.cc",
+ "ast/while_statement.h",
"ast/workgroup_attribute.cc",
"ast/workgroup_attribute.h",
"castable.cc",
@@ -381,7 +403,6 @@ libtint_source_set("libtint_core_all_src") {
"resolver/intrinsic_table.inl",
"resolver/resolver.cc",
"resolver/resolver.h",
- "resolver/resolver_constants.cc",
"resolver/sem_helper.cc",
"resolver/sem_helper.h",
"resolver/uniformity.cc",
@@ -404,6 +425,7 @@ libtint_source_set("libtint_core_all_src") {
"sem/constant.h",
"sem/depth_multisampled_texture.h",
"sem/depth_texture.h",
+ "sem/evaluation_stage.h",
"sem/expression.h",
"sem/external_texture.h",
"sem/f16.h",
@@ -411,6 +433,7 @@ libtint_source_set("libtint_core_all_src") {
"sem/for_loop_statement.h",
"sem/i32.h",
"sem/if_statement.h",
+ "sem/index_accessor_expression.h",
"sem/info.h",
"sem/loop_statement.h",
"sem/materialize.h",
@@ -436,6 +459,7 @@ libtint_source_set("libtint_core_all_src") {
"sem/u32.h",
"sem/vector.h",
"sem/void.h",
+ "sem/while_statement.h",
"source.cc",
"source.h",
"symbol.cc",
@@ -489,8 +513,8 @@ libtint_source_set("libtint_core_all_src") {
"transform/multiplanar_external_texture.h",
"transform/num_workgroups_from_uniform.cc",
"transform/num_workgroups_from_uniform.h",
- "transform/promote_initializers_to_const_var.cc",
- "transform/promote_initializers_to_const_var.h",
+ "transform/promote_initializers_to_let.cc",
+ "transform/promote_initializers_to_let.h",
"transform/promote_side_effects_to_decl.cc",
"transform/promote_side_effects_to_decl.h",
"transform/remove_continue_in_switch.cc",
@@ -507,6 +531,10 @@ libtint_source_set("libtint_core_all_src") {
"transform/simplify_pointers.h",
"transform/single_entry_point.cc",
"transform/single_entry_point.h",
+ "transform/spirv_atomic.cc",
+ "transform/spirv_atomic.h",
+ "transform/substitute_override.cc",
+ "transform/substitute_override.h",
"transform/transform.cc",
"transform/transform.h",
"transform/unshadow.cc",
@@ -523,11 +551,12 @@ libtint_source_set("libtint_core_all_src") {
"transform/vectorize_scalar_matrix_constructors.h",
"transform/vertex_pulling.cc",
"transform/vertex_pulling.h",
- "transform/wrap_arrays_in_structs.cc",
- "transform/wrap_arrays_in_structs.h",
+ "transform/while_to_loop.cc",
+ "transform/while_to_loop.h",
"transform/zero_init_workgroup_memory.cc",
"transform/zero_init_workgroup_memory.h",
"utils/bitcast.h",
+ "utils/bitset.h",
"utils/block_allocator.h",
"utils/compiler_macros.h",
"utils/concat.h",
@@ -536,12 +565,15 @@ libtint_source_set("libtint_core_all_src") {
"utils/debugger.h",
"utils/enum_set.h",
"utils/hash.h",
+ "utils/hashmap.h",
+ "utils/hashset.h",
"utils/map.h",
"utils/math.h",
"utils/scoped_assignment.h",
"utils/string.h",
"utils/unique_allocator.h",
"utils/unique_vector.h",
+ "utils/vector.h",
"writer/append_vector.cc",
"writer/append_vector.h",
"writer/array_length_from_uniform_options.cc",
@@ -601,6 +633,7 @@ libtint_source_set("libtint_sem_src") {
"sem/depth_multisampled_texture.h",
"sem/depth_texture.cc",
"sem/depth_texture.h",
+ "sem/evaluation_stage.h",
"sem/expression.cc",
"sem/expression.h",
"sem/external_texture.cc",
@@ -616,6 +649,8 @@ libtint_source_set("libtint_sem_src") {
"sem/i32.h",
"sem/if_statement.cc",
"sem/if_statement.h",
+ "sem/index_accessor_expression.cc",
+ "sem/index_accessor_expression.h",
"sem/info.cc",
"sem/info.h",
"sem/loop_statement.cc",
@@ -666,6 +701,8 @@ libtint_source_set("libtint_sem_src") {
"sem/vector.h",
"sem/void.cc",
"sem/void.h",
+ "sem/while_statement.cc",
+ "sem/while_statement.h",
]
public_deps = [ ":libtint_core_all_src" ]
@@ -830,3 +867,841 @@ source_set("libtint") {
configs += [ "//build/config/compiler:no_chromium_code" ]
}
}
+
+if (tint_build_unittests) {
+ ###############################################################################
+ # Gtest Gmock - Handle building inside and outside of Chromium.
+ ###############################################################################
+ # When building outside of Chromium we need to define our own targets for GTest
+ # and GMock. However when compiling inside of Chromium we need to reuse the
+ # existing targets, both because Chromium has a special harness for swarming
+ # and because otherwise the "gn check" fails.
+
+ if (!build_with_chromium) {
+ # When we aren't in Chromium we define out own targets based on the location
+ # of the googletest repo.
+ config("gtest_config") {
+ include_dirs = [
+ "${tint_googletest_dir}/googletest",
+ "${tint_googletest_dir}/googletest/include",
+ ]
+ }
+ static_library("gtest") {
+ testonly = true
+ sources = [ "${tint_googletest_dir}/googletest/src/gtest-all.cc" ]
+ public_configs = [ ":gtest_config" ]
+ }
+
+ config("gmock_config") {
+ include_dirs = [
+ "${tint_googletest_dir}/googlemock",
+ "${tint_googletest_dir}/googlemock/include",
+ "${tint_googletest_dir}/googletest/include",
+ ]
+ }
+
+ static_library("gmock") {
+ testonly = true
+ sources = [ "${tint_googletest_dir}/googlemock/src/gmock-all.cc" ]
+ public_configs = [ ":gmock_config" ]
+ }
+
+ group("gmock_and_gtest") {
+ testonly = true
+ public_deps = [
+ ":gmock",
+ ":gtest",
+ ]
+ }
+ } else {
+ # When we are in Chromium we reuse its targets, and also add some deps that
+ # are needed to launch the test in swarming mode.
+ group("gmock_and_gtest") {
+ testonly = true
+ public_deps = [
+ "//base",
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/googletest:gmock",
+ ]
+ }
+ }
+
+ ###############################################################################
+ # Wrapping of Chromium targets
+ ###############################################################################
+ # These targets are separated because they are Chromium sources files that
+ # can't use the tint_internal config, otherwise Tint's warning flags get
+ # applied while compiling a bunch of Chromium's //base (via header inclusion)
+ source_set("tint_unittests_main") {
+ testonly = true
+ deps = [ ":gmock_and_gtest" ]
+ if (build_with_chromium) {
+ sources = [ "//gpu/tint_unittests_main.cc" ]
+ } else {
+ sources = [ "test_main.cc" ]
+ configs += [ ":tint_unittests_config" ]
+ deps += [
+ ":libtint",
+ ":tint_unittests_hlsl_writer_src",
+ ":tint_unittests_msl_writer_src",
+ ":tint_unittests_spv_reader_src",
+ ]
+ }
+ }
+
+ ###############################################################################
+ # Tests - For libtint core and optional modules
+ ###############################################################################
+ config("tint_unittests_config") {
+ include_dirs = [
+ "${tint_googletest_dir}/googlemock/include",
+ "${tint_googletest_dir}/googletest/include",
+ ]
+
+ configs = [
+ ":tint_common_config",
+ ":tint_public_config",
+ ]
+ }
+
+ template("tint_unittests_source_set") {
+ source_set(target_name) {
+ forward_variables_from(invoker, "*", [ "configs" ])
+
+ if (defined(invoker.configs)) {
+ configs += invoker.configs
+ }
+ configs += [ ":tint_unittests_config" ]
+ if (build_with_chromium) {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
+
+ testonly = true
+
+ if (!defined(invoker.deps)) {
+ deps = []
+ }
+ deps += [
+ ":gmock_and_gtest",
+ ":libtint",
+ ":tint_utils_io",
+ ]
+ }
+ }
+
+ tint_unittests_source_set("tint_unittests_ast_src") {
+ sources = [
+ "ast/alias_test.cc",
+ "ast/array_test.cc",
+ "ast/assignment_statement_test.cc",
+ "ast/atomic_test.cc",
+ "ast/binary_expression_test.cc",
+ "ast/binding_attribute_test.cc",
+ "ast/bitcast_expression_test.cc",
+ "ast/block_statement_test.cc",
+ "ast/bool_literal_expression_test.cc",
+ "ast/bool_test.cc",
+ "ast/break_statement_test.cc",
+ "ast/builtin_attribute_test.cc",
+ "ast/builtin_texture_helper_test.cc",
+ "ast/builtin_texture_helper_test.h",
+ "ast/builtin_value_test.cc",
+ "ast/call_expression_test.cc",
+ "ast/call_statement_test.cc",
+ "ast/case_statement_test.cc",
+ "ast/compound_assignment_statement_test.cc",
+ "ast/continue_statement_test.cc",
+ "ast/depth_multisampled_texture_test.cc",
+ "ast/depth_texture_test.cc",
+ "ast/discard_statement_test.cc",
+ "ast/enable_test.cc",
+ "ast/extension_test.cc",
+ "ast/external_texture_test.cc",
+ "ast/f16_test.cc",
+ "ast/f32_test.cc",
+ "ast/fallthrough_statement_test.cc",
+ "ast/float_literal_expression_test.cc",
+ "ast/for_loop_statement_test.cc",
+ "ast/function_test.cc",
+ "ast/group_attribute_test.cc",
+ "ast/i32_test.cc",
+ "ast/id_attribute_test.cc",
+ "ast/identifier_expression_test.cc",
+ "ast/if_statement_test.cc",
+ "ast/increment_decrement_statement_test.cc",
+ "ast/index_accessor_expression_test.cc",
+ "ast/int_literal_expression_test.cc",
+ "ast/interpolate_attribute_test.cc",
+ "ast/invariant_attribute_test.cc",
+ "ast/location_attribute_test.cc",
+ "ast/loop_statement_test.cc",
+ "ast/matrix_test.cc",
+ "ast/member_accessor_expression_test.cc",
+ "ast/module_clone_test.cc",
+ "ast/module_test.cc",
+ "ast/multisampled_texture_test.cc",
+ "ast/override_test.cc",
+ "ast/phony_expression_test.cc",
+ "ast/pointer_test.cc",
+ "ast/return_statement_test.cc",
+ "ast/sampled_texture_test.cc",
+ "ast/sampler_test.cc",
+ "ast/stage_attribute_test.cc",
+ "ast/static_assert_test.cc",
+ "ast/storage_class_test.cc",
+ "ast/storage_texture_test.cc",
+ "ast/stride_attribute_test.cc",
+ "ast/struct_member_align_attribute_test.cc",
+ "ast/struct_member_offset_attribute_test.cc",
+ "ast/struct_member_size_attribute_test.cc",
+ "ast/struct_member_test.cc",
+ "ast/struct_test.cc",
+ "ast/switch_statement_test.cc",
+ "ast/test_helper.h",
+ "ast/texel_format_test.cc",
+ "ast/texture_test.cc",
+ "ast/traverse_expressions_test.cc",
+ "ast/u32_test.cc",
+ "ast/unary_op_expression_test.cc",
+ "ast/variable_decl_statement_test.cc",
+ "ast/variable_test.cc",
+ "ast/vector_test.cc",
+ "ast/while_statement_test.cc",
+ "ast/workgroup_attribute_test.cc",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_diagnostic_src") {
+ sources = [
+ "diagnostic/diagnostic_test.cc",
+ "diagnostic/formatter_test.cc",
+ "diagnostic/printer_test.cc",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_inspector_src") {
+ sources = [
+ "inspector/inspector_test.cc",
+ "inspector/test_inspector_builder.cc",
+ "inspector/test_inspector_builder.h",
+ "inspector/test_inspector_runner.cc",
+ "inspector/test_inspector_runner.h",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_resolver_src") {
+ sources = [
+ "resolver/array_accessor_test.cc",
+ "resolver/assignment_validation_test.cc",
+ "resolver/atomics_test.cc",
+ "resolver/atomics_validation_test.cc",
+ "resolver/attribute_validation_test.cc",
+ "resolver/bitcast_validation_test.cc",
+ "resolver/builtin_test.cc",
+ "resolver/builtin_validation_test.cc",
+ "resolver/builtins_validation_test.cc",
+ "resolver/call_test.cc",
+ "resolver/call_validation_test.cc",
+ "resolver/compound_assignment_validation_test.cc",
+ "resolver/compound_statement_test.cc",
+ "resolver/const_eval_test.cc",
+ "resolver/control_block_validation_test.cc",
+ "resolver/dependency_graph_test.cc",
+ "resolver/entry_point_validation_test.cc",
+ "resolver/evaluation_stage_test.cc",
+ "resolver/function_validation_test.cc",
+ "resolver/host_shareable_validation_test.cc",
+ "resolver/increment_decrement_validation_test.cc",
+ "resolver/inferred_type_test.cc",
+ "resolver/intrinsic_table_test.cc",
+ "resolver/is_host_shareable_test.cc",
+ "resolver/is_storeable_test.cc",
+ "resolver/materialize_test.cc",
+ "resolver/override_test.cc",
+ "resolver/ptr_ref_test.cc",
+ "resolver/ptr_ref_validation_test.cc",
+ "resolver/resolver_behavior_test.cc",
+ "resolver/resolver_test.cc",
+ "resolver/resolver_test_helper.cc",
+ "resolver/resolver_test_helper.h",
+ "resolver/side_effects_test.cc",
+ "resolver/source_variable_test.cc",
+ "resolver/static_assert_test.cc",
+ "resolver/storage_class_layout_validation_test.cc",
+ "resolver/storage_class_validation_test.cc",
+ "resolver/struct_layout_test.cc",
+ "resolver/struct_pipeline_stage_use_test.cc",
+ "resolver/struct_storage_class_use_test.cc",
+ "resolver/type_constructor_validation_test.cc",
+ "resolver/type_validation_test.cc",
+ "resolver/uniformity_test.cc",
+ "resolver/validation_test.cc",
+ "resolver/validator_is_storeable_test.cc",
+ "resolver/variable_test.cc",
+ "resolver/variable_validation_test.cc",
+ ]
+ deps = [ ":tint_unittests_ast_src" ]
+ }
+
+ tint_unittests_source_set("tint_unittests_sem_src") {
+ sources = [
+ "sem/atomic_test.cc",
+ "sem/bool_test.cc",
+ "sem/builtin_test.cc",
+ "sem/depth_multisampled_texture_test.cc",
+ "sem/depth_texture_test.cc",
+ "sem/expression_test.cc",
+ "sem/external_texture_test.cc",
+ "sem/f16_test.cc",
+ "sem/f32_test.cc",
+ "sem/i32_test.cc",
+ "sem/matrix_test.cc",
+ "sem/multisampled_texture_test.cc",
+ "sem/pointer_test.cc",
+ "sem/reference_test.cc",
+ "sem/sampled_texture_test.cc",
+ "sem/sampler_test.cc",
+ "sem/sem_array_test.cc",
+ "sem/sem_struct_test.cc",
+ "sem/storage_texture_test.cc",
+ "sem/texture_test.cc",
+ "sem/type_manager_test.cc",
+ "sem/type_test.cc",
+ "sem/u32_test.cc",
+ "sem/vector_test.cc",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_text_src") {
+ sources = [ "text/unicode_test.cc" ]
+ }
+
+ tint_unittests_source_set("tint_unittests_transform_src") {
+ sources = [
+ "transform/add_empty_entry_point_test.cc",
+ "transform/add_spirv_block_attribute_test.cc",
+ "transform/array_length_from_uniform_test.cc",
+ "transform/binding_remapper_test.cc",
+ "transform/builtin_polyfill_test.cc",
+ "transform/calculate_array_length_test.cc",
+ "transform/canonicalize_entry_point_io_test.cc",
+ "transform/combine_samplers_test.cc",
+ "transform/decompose_memory_access_test.cc",
+ "transform/decompose_strided_array_test.cc",
+ "transform/decompose_strided_matrix_test.cc",
+ "transform/disable_uniformity_analysis_test.cc",
+ "transform/expand_compound_assignment_test.cc",
+ "transform/first_index_offset_test.cc",
+ "transform/fold_trivial_single_use_lets_test.cc",
+ "transform/for_loop_to_loop_test.cc",
+ "transform/localize_struct_array_assignment_test.cc",
+ "transform/loop_to_for_loop_test.cc",
+ "transform/module_scope_var_to_entry_point_param_test.cc",
+ "transform/multiplanar_external_texture_test.cc",
+ "transform/num_workgroups_from_uniform_test.cc",
+ "transform/promote_initializers_to_let_test.cc",
+ "transform/promote_side_effects_to_decl_test.cc",
+ "transform/remove_continue_in_switch_test.cc",
+ "transform/remove_phonies_test.cc",
+ "transform/remove_unreachable_statements_test.cc",
+ "transform/renamer_test.cc",
+ "transform/robustness_test.cc",
+ "transform/simplify_pointers_test.cc",
+ "transform/single_entry_point_test.cc",
+ "transform/spirv_atomic_test.cc",
+ "transform/substitute_override_test.cc",
+ "transform/test_helper.h",
+ "transform/transform_test.cc",
+ "transform/unshadow_test.cc",
+ "transform/unwind_discard_functions_test.cc",
+ "transform/utils/get_insertion_point_test.cc",
+ "transform/utils/hoist_to_decl_before_test.cc",
+ "transform/var_for_dynamic_index_test.cc",
+ "transform/vectorize_scalar_matrix_constructors_test.cc",
+ "transform/vertex_pulling_test.cc",
+ "transform/while_to_loop_test.cc",
+ "transform/zero_init_workgroup_memory_test.cc",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_utils_src") {
+ sources = [
+ "utils/bitcast_test.cc",
+ "utils/bitset_test.cc",
+ "utils/crc32_test.cc",
+ "utils/defer_test.cc",
+ "utils/enum_set_test.cc",
+ "utils/hash_test.cc",
+ "utils/hashmap_test.cc",
+ "utils/hashset_test.cc",
+ "utils/io/command_test.cc",
+ "utils/io/tmpfile_test.cc",
+ "utils/map_test.cc",
+ "utils/math_test.cc",
+ "utils/result_test.cc",
+ "utils/reverse_test.cc",
+ "utils/scoped_assignment_test.cc",
+ "utils/string_test.cc",
+ "utils/transform_test.cc",
+ "utils/unique_allocator_test.cc",
+ "utils/unique_vector_test.cc",
+ "utils/vector_test.cc",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_writer_src") {
+ sources = [
+ "writer/append_vector_test.cc",
+ "writer/flatten_bindings_test.cc",
+ "writer/float_to_string_test.cc",
+ "writer/generate_external_texture_bindings_test.cc",
+ "writer/text_generator_test.cc",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_spv_reader_src") {
+ sources = [
+ "reader/spirv/enum_converter_test.cc",
+ "reader/spirv/fail_stream_test.cc",
+ "reader/spirv/function_arithmetic_test.cc",
+ "reader/spirv/function_bit_test.cc",
+ "reader/spirv/function_call_test.cc",
+ "reader/spirv/function_cfg_test.cc",
+ "reader/spirv/function_composite_test.cc",
+ "reader/spirv/function_conversion_test.cc",
+ "reader/spirv/function_decl_test.cc",
+ "reader/spirv/function_glsl_std_450_test.cc",
+ "reader/spirv/function_logical_test.cc",
+ "reader/spirv/function_memory_test.cc",
+ "reader/spirv/function_misc_test.cc",
+ "reader/spirv/function_var_test.cc",
+ "reader/spirv/namer_test.cc",
+ "reader/spirv/parser_impl_barrier_test.cc",
+ "reader/spirv/parser_impl_convert_member_decoration_test.cc",
+ "reader/spirv/parser_impl_convert_type_test.cc",
+ "reader/spirv/parser_impl_function_decl_test.cc",
+ "reader/spirv/parser_impl_get_decorations_test.cc",
+ "reader/spirv/parser_impl_handle_test.cc",
+ "reader/spirv/parser_impl_import_test.cc",
+ "reader/spirv/parser_impl_module_var_test.cc",
+ "reader/spirv/parser_impl_named_types_test.cc",
+ "reader/spirv/parser_impl_test.cc",
+ "reader/spirv/parser_impl_test_helper.cc",
+ "reader/spirv/parser_impl_test_helper.h",
+ "reader/spirv/parser_impl_user_name_test.cc",
+ "reader/spirv/parser_test.cc",
+ "reader/spirv/parser_type_test.cc",
+ "reader/spirv/spirv_tools_helpers_test.cc",
+ "reader/spirv/spirv_tools_helpers_test.h",
+ "reader/spirv/usage_test.cc",
+ ]
+
+ deps = [ ":libtint_spv_reader_src" ]
+ }
+
+ tint_unittests_source_set("tint_unittests_spv_writer_src") {
+ sources = [
+ "writer/spirv/binary_writer_test.cc",
+ "writer/spirv/builder_accessor_expression_test.cc",
+ "writer/spirv/builder_assign_test.cc",
+ "writer/spirv/builder_binary_expression_test.cc",
+ "writer/spirv/builder_bitcast_expression_test.cc",
+ "writer/spirv/builder_block_test.cc",
+ "writer/spirv/builder_builtin_test.cc",
+ "writer/spirv/builder_builtin_texture_test.cc",
+ "writer/spirv/builder_call_test.cc",
+ "writer/spirv/builder_constructor_expression_test.cc",
+ "writer/spirv/builder_discard_test.cc",
+ "writer/spirv/builder_entry_point_test.cc",
+ "writer/spirv/builder_format_conversion_test.cc",
+ "writer/spirv/builder_function_attribute_test.cc",
+ "writer/spirv/builder_function_test.cc",
+ "writer/spirv/builder_function_variable_test.cc",
+ "writer/spirv/builder_global_variable_test.cc",
+ "writer/spirv/builder_ident_expression_test.cc",
+ "writer/spirv/builder_if_test.cc",
+ "writer/spirv/builder_literal_test.cc",
+ "writer/spirv/builder_loop_test.cc",
+ "writer/spirv/builder_return_test.cc",
+ "writer/spirv/builder_static_assert_test.cc",
+ "writer/spirv/builder_switch_test.cc",
+ "writer/spirv/builder_test.cc",
+ "writer/spirv/builder_type_test.cc",
+ "writer/spirv/builder_unary_op_expression_test.cc",
+ "writer/spirv/instruction_test.cc",
+ "writer/spirv/operand_test.cc",
+ "writer/spirv/scalar_constant_test.cc",
+ "writer/spirv/spv_dump.cc",
+ "writer/spirv/spv_dump.h",
+ "writer/spirv/test_helper.h",
+ ]
+
+ deps = [
+ ":libtint_spv_writer_src",
+ ":tint_unittests_ast_src",
+ "${tint_spirv_tools_dir}/:spvtools",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_wgsl_reader_src") {
+ sources = [
+ "reader/wgsl/lexer_test.cc",
+ "reader/wgsl/parser_impl_additive_expression_test.cc",
+ "reader/wgsl/parser_impl_and_expression_test.cc",
+ "reader/wgsl/parser_impl_argument_expression_list_test.cc",
+ "reader/wgsl/parser_impl_assignment_stmt_test.cc",
+ "reader/wgsl/parser_impl_bitwise_expression_test.cc",
+ "reader/wgsl/parser_impl_break_stmt_test.cc",
+ "reader/wgsl/parser_impl_bug_cases_test.cc",
+ "reader/wgsl/parser_impl_call_stmt_test.cc",
+ "reader/wgsl/parser_impl_case_body_test.cc",
+ "reader/wgsl/parser_impl_compound_stmt_test.cc",
+ "reader/wgsl/parser_impl_const_literal_test.cc",
+ "reader/wgsl/parser_impl_continue_stmt_test.cc",
+ "reader/wgsl/parser_impl_continuing_stmt_test.cc",
+ "reader/wgsl/parser_impl_core_lhs_expression_test.cc",
+ "reader/wgsl/parser_impl_depth_texture_test.cc",
+ "reader/wgsl/parser_impl_enable_directive_test.cc",
+ "reader/wgsl/parser_impl_equality_expression_test.cc",
+ "reader/wgsl/parser_impl_error_msg_test.cc",
+ "reader/wgsl/parser_impl_error_resync_test.cc",
+ "reader/wgsl/parser_impl_exclusive_or_expression_test.cc",
+ "reader/wgsl/parser_impl_external_texture_test.cc",
+ "reader/wgsl/parser_impl_for_stmt_test.cc",
+ "reader/wgsl/parser_impl_function_attribute_list_test.cc",
+ "reader/wgsl/parser_impl_function_attribute_test.cc",
+ "reader/wgsl/parser_impl_function_decl_test.cc",
+ "reader/wgsl/parser_impl_function_header_test.cc",
+ "reader/wgsl/parser_impl_global_constant_decl_test.cc",
+ "reader/wgsl/parser_impl_global_decl_test.cc",
+ "reader/wgsl/parser_impl_global_variable_decl_test.cc",
+ "reader/wgsl/parser_impl_if_stmt_test.cc",
+ "reader/wgsl/parser_impl_inclusive_or_expression_test.cc",
+ "reader/wgsl/parser_impl_increment_decrement_stmt_test.cc",
+ "reader/wgsl/parser_impl_lhs_expression_test.cc",
+ "reader/wgsl/parser_impl_logical_and_expression_test.cc",
+ "reader/wgsl/parser_impl_logical_or_expression_test.cc",
+ "reader/wgsl/parser_impl_loop_stmt_test.cc",
+ "reader/wgsl/parser_impl_multiplicative_expression_test.cc",
+ "reader/wgsl/parser_impl_param_list_test.cc",
+ "reader/wgsl/parser_impl_paren_expression_test.cc",
+ "reader/wgsl/parser_impl_pipeline_stage_test.cc",
+ "reader/wgsl/parser_impl_primary_expression_test.cc",
+ "reader/wgsl/parser_impl_relational_expression_test.cc",
+ "reader/wgsl/parser_impl_reserved_keyword_test.cc",
+ "reader/wgsl/parser_impl_sampled_texture_test.cc",
+ "reader/wgsl/parser_impl_sampler_test.cc",
+ "reader/wgsl/parser_impl_shift_expression_test.cc",
+ "reader/wgsl/parser_impl_singular_expression_test.cc",
+ "reader/wgsl/parser_impl_statement_test.cc",
+ "reader/wgsl/parser_impl_statements_test.cc",
+ "reader/wgsl/parser_impl_storage_class_test.cc",
+ "reader/wgsl/parser_impl_storage_texture_test.cc",
+ "reader/wgsl/parser_impl_struct_attribute_decl_test.cc",
+ "reader/wgsl/parser_impl_struct_body_decl_test.cc",
+ "reader/wgsl/parser_impl_struct_decl_test.cc",
+ "reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc",
+ "reader/wgsl/parser_impl_struct_member_attribute_test.cc",
+ "reader/wgsl/parser_impl_struct_member_test.cc",
+ "reader/wgsl/parser_impl_switch_body_test.cc",
+ "reader/wgsl/parser_impl_switch_stmt_test.cc",
+ "reader/wgsl/parser_impl_test.cc",
+ "reader/wgsl/parser_impl_test_helper.cc",
+ "reader/wgsl/parser_impl_test_helper.h",
+ "reader/wgsl/parser_impl_texel_format_test.cc",
+ "reader/wgsl/parser_impl_texture_sampler_test.cc",
+ "reader/wgsl/parser_impl_type_alias_test.cc",
+ "reader/wgsl/parser_impl_type_decl_test.cc",
+ "reader/wgsl/parser_impl_unary_expression_test.cc",
+ "reader/wgsl/parser_impl_variable_attribute_list_test.cc",
+ "reader/wgsl/parser_impl_variable_attribute_test.cc",
+ "reader/wgsl/parser_impl_variable_decl_test.cc",
+ "reader/wgsl/parser_impl_variable_ident_decl_test.cc",
+ "reader/wgsl/parser_impl_variable_qualifier_test.cc",
+ "reader/wgsl/parser_impl_variable_stmt_test.cc",
+ "reader/wgsl/parser_impl_while_stmt_test.cc",
+ "reader/wgsl/parser_test.cc",
+ "reader/wgsl/token_test.cc",
+ ]
+
+ deps = [ ":libtint_wgsl_reader_src" ]
+ }
+
+ tint_unittests_source_set("tint_unittests_wgsl_writer_src") {
+ sources = [
+ "writer/wgsl/generator_impl_alias_type_test.cc",
+ "writer/wgsl/generator_impl_array_accessor_test.cc",
+ "writer/wgsl/generator_impl_assign_test.cc",
+ "writer/wgsl/generator_impl_binary_test.cc",
+ "writer/wgsl/generator_impl_bitcast_test.cc",
+ "writer/wgsl/generator_impl_block_test.cc",
+ "writer/wgsl/generator_impl_break_test.cc",
+ "writer/wgsl/generator_impl_call_test.cc",
+ "writer/wgsl/generator_impl_case_test.cc",
+ "writer/wgsl/generator_impl_cast_test.cc",
+ "writer/wgsl/generator_impl_constructor_test.cc",
+ "writer/wgsl/generator_impl_continue_test.cc",
+ "writer/wgsl/generator_impl_discard_test.cc",
+ "writer/wgsl/generator_impl_enable_test.cc",
+ "writer/wgsl/generator_impl_fallthrough_test.cc",
+ "writer/wgsl/generator_impl_function_test.cc",
+ "writer/wgsl/generator_impl_global_decl_test.cc",
+ "writer/wgsl/generator_impl_identifier_test.cc",
+ "writer/wgsl/generator_impl_if_test.cc",
+ "writer/wgsl/generator_impl_literal_test.cc",
+ "writer/wgsl/generator_impl_loop_test.cc",
+ "writer/wgsl/generator_impl_member_accessor_test.cc",
+ "writer/wgsl/generator_impl_return_test.cc",
+ "writer/wgsl/generator_impl_static_assert_test.cc",
+ "writer/wgsl/generator_impl_switch_test.cc",
+ "writer/wgsl/generator_impl_test.cc",
+ "writer/wgsl/generator_impl_type_test.cc",
+ "writer/wgsl/generator_impl_unary_op_test.cc",
+ "writer/wgsl/generator_impl_variable_decl_statement_test.cc",
+ "writer/wgsl/generator_impl_variable_test.cc",
+ "writer/wgsl/test_helper.h",
+ ]
+
+ deps = [
+ ":libtint_wgsl_writer_src",
+ ":tint_unittests_ast_src",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_msl_writer_src") {
+ sources = [
+ "writer/msl/generator_impl_array_accessor_test.cc",
+ "writer/msl/generator_impl_assign_test.cc",
+ "writer/msl/generator_impl_binary_test.cc",
+ "writer/msl/generator_impl_bitcast_test.cc",
+ "writer/msl/generator_impl_block_test.cc",
+ "writer/msl/generator_impl_break_test.cc",
+ "writer/msl/generator_impl_builtin_test.cc",
+ "writer/msl/generator_impl_builtin_texture_test.cc",
+ "writer/msl/generator_impl_call_test.cc",
+ "writer/msl/generator_impl_case_test.cc",
+ "writer/msl/generator_impl_cast_test.cc",
+ "writer/msl/generator_impl_constructor_test.cc",
+ "writer/msl/generator_impl_continue_test.cc",
+ "writer/msl/generator_impl_discard_test.cc",
+ "writer/msl/generator_impl_function_test.cc",
+ "writer/msl/generator_impl_identifier_test.cc",
+ "writer/msl/generator_impl_if_test.cc",
+ "writer/msl/generator_impl_import_test.cc",
+ "writer/msl/generator_impl_loop_test.cc",
+ "writer/msl/generator_impl_member_accessor_test.cc",
+ "writer/msl/generator_impl_module_constant_test.cc",
+ "writer/msl/generator_impl_return_test.cc",
+ "writer/msl/generator_impl_sanitizer_test.cc",
+ "writer/msl/generator_impl_static_assert_test.cc",
+ "writer/msl/generator_impl_switch_test.cc",
+ "writer/msl/generator_impl_test.cc",
+ "writer/msl/generator_impl_type_test.cc",
+ "writer/msl/generator_impl_unary_op_test.cc",
+ "writer/msl/generator_impl_variable_decl_statement_test.cc",
+ "writer/msl/test_helper.h",
+ ]
+
+ deps = [
+ ":libtint_msl_writer_src",
+ ":tint_unittests_ast_src",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_hlsl_writer_src") {
+ sources = [
+ "writer/hlsl/generator_impl_array_accessor_test.cc",
+ "writer/hlsl/generator_impl_assign_test.cc",
+ "writer/hlsl/generator_impl_binary_test.cc",
+ "writer/hlsl/generator_impl_bitcast_test.cc",
+ "writer/hlsl/generator_impl_block_test.cc",
+ "writer/hlsl/generator_impl_break_test.cc",
+ "writer/hlsl/generator_impl_builtin_test.cc",
+ "writer/hlsl/generator_impl_builtin_texture_test.cc",
+ "writer/hlsl/generator_impl_call_test.cc",
+ "writer/hlsl/generator_impl_case_test.cc",
+ "writer/hlsl/generator_impl_cast_test.cc",
+ "writer/hlsl/generator_impl_constructor_test.cc",
+ "writer/hlsl/generator_impl_continue_test.cc",
+ "writer/hlsl/generator_impl_discard_test.cc",
+ "writer/hlsl/generator_impl_function_test.cc",
+ "writer/hlsl/generator_impl_identifier_test.cc",
+ "writer/hlsl/generator_impl_if_test.cc",
+ "writer/hlsl/generator_impl_import_test.cc",
+ "writer/hlsl/generator_impl_loop_test.cc",
+ "writer/hlsl/generator_impl_member_accessor_test.cc",
+ "writer/hlsl/generator_impl_module_constant_test.cc",
+ "writer/hlsl/generator_impl_return_test.cc",
+ "writer/hlsl/generator_impl_sanitizer_test.cc",
+ "writer/hlsl/generator_impl_static_assert_test.cc",
+ "writer/hlsl/generator_impl_switch_test.cc",
+ "writer/hlsl/generator_impl_test.cc",
+ "writer/hlsl/generator_impl_type_test.cc",
+ "writer/hlsl/generator_impl_unary_op_test.cc",
+ "writer/hlsl/generator_impl_variable_decl_statement_test.cc",
+ "writer/hlsl/generator_impl_workgroup_var_test.cc",
+ "writer/hlsl/test_helper.h",
+ ]
+
+ deps = [
+ ":libtint_hlsl_writer_src",
+ ":tint_unittests_ast_src",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_glsl_writer_src") {
+ sources = [
+ "writer/glsl/generator_impl_array_accessor_test.cc",
+ "writer/glsl/generator_impl_assign_test.cc",
+ "writer/glsl/generator_impl_binary_test.cc",
+ "writer/glsl/generator_impl_bitcast_test.cc",
+ "writer/glsl/generator_impl_block_test.cc",
+ "writer/glsl/generator_impl_break_test.cc",
+ "writer/glsl/generator_impl_builtin_test.cc",
+ "writer/glsl/generator_impl_builtin_texture_test.cc",
+ "writer/glsl/generator_impl_call_test.cc",
+ "writer/glsl/generator_impl_case_test.cc",
+ "writer/glsl/generator_impl_cast_test.cc",
+ "writer/glsl/generator_impl_constructor_test.cc",
+ "writer/glsl/generator_impl_continue_test.cc",
+ "writer/glsl/generator_impl_discard_test.cc",
+ "writer/glsl/generator_impl_function_test.cc",
+ "writer/glsl/generator_impl_identifier_test.cc",
+ "writer/glsl/generator_impl_if_test.cc",
+ "writer/glsl/generator_impl_import_test.cc",
+ "writer/glsl/generator_impl_loop_test.cc",
+ "writer/glsl/generator_impl_member_accessor_test.cc",
+ "writer/glsl/generator_impl_module_constant_test.cc",
+ "writer/glsl/generator_impl_return_test.cc",
+ "writer/glsl/generator_impl_sanitizer_test.cc",
+ "writer/glsl/generator_impl_storage_buffer_test.cc",
+ "writer/glsl/generator_impl_switch_test.cc",
+ "writer/glsl/generator_impl_test.cc",
+ "writer/glsl/generator_impl_type_test.cc",
+ "writer/glsl/generator_impl_unary_op_test.cc",
+ "writer/glsl/generator_impl_uniform_buffer_test.cc",
+ "writer/glsl/generator_impl_variable_decl_statement_test.cc",
+ "writer/glsl/generator_impl_workgroup_var_test.cc",
+ "writer/glsl/test_helper.h",
+ ]
+
+ deps = [
+ ":libtint_glsl_writer_src",
+ ":tint_unittests_ast_src",
+ ":tint_unittests_transform_src",
+ ]
+ }
+
+ tint_unittests_source_set("tint_unittests_core_src") {
+ sources = [
+ "castable_test.cc",
+ "clone_context_test.cc",
+ "debug_test.cc",
+ "demangler_test.cc",
+ "number_test.cc",
+ "program_builder_test.cc",
+ "program_test.cc",
+ "scope_stack_test.cc",
+ "source_test.cc",
+ "symbol_table_test.cc",
+ "symbol_test.cc",
+ "traits_test.cc",
+ "utils/block_allocator_test.cc",
+ ]
+
+ deps = [ ":tint_unittests_ast_src" ]
+ }
+
+ if (build_with_chromium) {
+ tint_unittests_source_set("tint_unittests_fuzzer_src") {
+ sources = [ "fuzzers/random_generator_test.cc" ]
+
+ deps = [
+ ":tint_unittests_core_src",
+ "fuzzers:tint_fuzzer_common_src",
+ ]
+ }
+ }
+
+ source_set("tint_unittests_src") {
+ testonly = true
+
+ deps = [
+ ":libtint_wgsl_reader_src",
+ ":libtint_wgsl_writer_src",
+ ":tint_unittests_ast_src",
+ ":tint_unittests_core_src",
+ ":tint_unittests_diagnostic_src",
+ ":tint_unittests_inspector_src",
+ ":tint_unittests_resolver_src",
+ ":tint_unittests_sem_src",
+ ":tint_unittests_text_src",
+ ":tint_unittests_transform_src",
+ ":tint_unittests_utils_src",
+ ":tint_unittests_writer_src",
+ ]
+
+ if (tint_build_spv_reader) {
+ deps += [ ":tint_unittests_spv_reader_src" ]
+ }
+
+ if (tint_build_spv_writer) {
+ deps += [ ":tint_unittests_spv_writer_src" ]
+ }
+
+ if (tint_build_wgsl_reader) {
+ deps += [ ":tint_unittests_wgsl_reader_src" ]
+ }
+
+ if (tint_build_wgsl_writer) {
+ deps += [ ":tint_unittests_wgsl_writer_src" ]
+ }
+
+ if (tint_build_msl_writer) {
+ deps += [ ":tint_unittests_msl_writer_src" ]
+ }
+
+ if (tint_build_hlsl_writer) {
+ deps += [ ":tint_unittests_hlsl_writer_src" ]
+ }
+
+ if (tint_build_glsl_writer) {
+ deps += [ ":tint_unittests_glsl_writer_src" ]
+ }
+
+ if (build_with_chromium) {
+ deps += [ ":tint_unittests_fuzzer_src" ]
+ }
+
+ configs += [ ":tint_unittests_config" ]
+
+ if (build_with_chromium) {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
+ }
+
+ test("tint_unittests") {
+ deps = [
+ ":gmock_and_gtest",
+ ":tint_unittests_src",
+ "${tint_spirv_tools_dir}/:spvtools",
+ "${tint_spirv_tools_dir}/:spvtools_opt",
+ "${tint_spirv_tools_dir}/:spvtools_val",
+ ]
+
+ deps += [ ":tint_unittests_main" ]
+
+ configs += [ ":tint_unittests_config" ]
+
+ if (build_with_chromium) {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
+
+ testonly = true
+ }
+}
diff --git a/chromium/third_party/dawn/src/tint/CMakeLists.txt b/chromium/third_party/dawn/src/tint/CMakeLists.txt
index 6ffc36a9c0d..8612975484e 100644
--- a/chromium/third_party/dawn/src/tint/CMakeLists.txt
+++ b/chromium/third_party/dawn/src/tint/CMakeLists.txt
@@ -22,18 +22,6 @@ function(tint_spvtools_compile_options TARGET)
${spirv-tools_SOURCE_DIR}
${spirv-tools_BINARY_DIR}
)
-
- if (${CMAKE_CXX_COMPILER_ID} MATCHES Clang)
- # The SPIRV-Tools code is conditioned against C++ and an older version of Clang.
- # Suppress warnings triggered in our current compilation environment.
- # TODO(dneto): Fix the issues upstream.
- target_compile_options(${TARGET} PRIVATE
- -Wno-newline-eof
- -Wno-sign-conversion
- -Wno-old-style-cast
- -Wno-weak-vtables
- )
- endif()
endfunction()
## Tint diagnostic utilities. Used by libtint and tint_utils_io.
@@ -89,8 +77,8 @@ set(TINT_LIB_SRCS
ast/break_statement.h
ast/builtin_attribute.cc
ast/builtin_attribute.h
- ast/builtin.cc
- ast/builtin.h
+ ast/builtin_value.cc
+ ast/builtin_value.h
ast/call_expression.cc
ast/call_expression.h
ast/call_statement.cc
@@ -99,6 +87,8 @@ set(TINT_LIB_SRCS
ast/case_statement.h
ast/compound_assignment_statement.cc
ast/compound_assignment_statement.h
+ ast/const.cc
+ ast/const.h
ast/continue_statement.cc
ast/continue_statement.h
ast/depth_multisampled_texture.cc
@@ -151,6 +141,8 @@ set(TINT_LIB_SRCS
ast/interpolate_attribute.h
ast/invariant_attribute.cc
ast/invariant_attribute.h
+ ast/let.cc
+ ast/let.h
ast/literal_expression.cc
ast/literal_expression.h
ast/location_attribute.cc
@@ -165,8 +157,13 @@ set(TINT_LIB_SRCS
ast/module.h
ast/multisampled_texture.cc
ast/multisampled_texture.h
+ ast/node_id.h
ast/node.cc
ast/node.h
+ ast/override.cc
+ ast/override.h
+ ast/parameter.cc
+ ast/parameter.h
ast/phony_expression.cc
ast/phony_expression.h
ast/pipeline_stage.cc
@@ -183,6 +180,8 @@ set(TINT_LIB_SRCS
ast/stage_attribute.h
ast/statement.cc
ast/statement.h
+ ast/static_assert.cc
+ ast/static_assert.h
ast/storage_class.cc
ast/storage_class.h
ast/storage_texture.cc
@@ -201,6 +200,8 @@ set(TINT_LIB_SRCS
ast/struct.h
ast/switch_statement.cc
ast/switch_statement.h
+ ast/texel_format.cc
+ ast/texel_format.h
ast/texture.cc
ast/texture.h
ast/traverse_expressions.h
@@ -215,6 +216,8 @@ set(TINT_LIB_SRCS
ast/unary_op_expression.h
ast/unary_op.cc
ast/unary_op.h
+ ast/var.cc
+ ast/var.h
ast/variable_decl_statement.cc
ast/variable_decl_statement.h
ast/variable.cc
@@ -223,6 +226,8 @@ set(TINT_LIB_SRCS
ast/vector.h
ast/void.cc
ast/void.h
+ ast/while_statement.cc
+ ast/while_statement.h
ast/workgroup_attribute.cc
ast/workgroup_attribute.h
castable.cc
@@ -258,7 +263,6 @@ set(TINT_LIB_SRCS
resolver/intrinsic_table.cc
resolver/intrinsic_table.h
resolver/intrinsic_table.inl
- resolver/resolver_constants.cc
resolver/resolver.cc
resolver/resolver.h
resolver/sem_helper.cc
@@ -299,6 +303,7 @@ set(TINT_LIB_SRCS
sem/depth_multisampled_texture.h
sem/depth_texture.cc
sem/depth_texture.h
+ sem/evaluation_stage.h
sem/expression.cc
sem/expression.h
sem/external_texture.cc
@@ -314,6 +319,8 @@ set(TINT_LIB_SRCS
sem/i32.h
sem/if_statement.cc
sem/if_statement.h
+ sem/index_accessor_expression.cc
+ sem/index_accessor_expression.h
sem/info.cc
sem/info.h
sem/loop_statement.cc
@@ -365,6 +372,8 @@ set(TINT_LIB_SRCS
sem/vector.h
sem/void.cc
sem/void.h
+ sem/while_statement.cc
+ sem/while_statement.h
symbol_table.cc
symbol_table.h
symbol.cc
@@ -416,8 +425,8 @@ set(TINT_LIB_SRCS
transform/multiplanar_external_texture.h
transform/num_workgroups_from_uniform.cc
transform/num_workgroups_from_uniform.h
- transform/promote_initializers_to_const_var.cc
- transform/promote_initializers_to_const_var.h
+ transform/promote_initializers_to_let.cc
+ transform/promote_initializers_to_let.h
transform/promote_side_effects_to_decl.cc
transform/promote_side_effects_to_decl.h
transform/remove_continue_in_switch.cc
@@ -434,6 +443,10 @@ set(TINT_LIB_SRCS
transform/simplify_pointers.h
transform/single_entry_point.cc
transform/single_entry_point.h
+ transform/spirv_atomic.cc
+ transform/spirv_atomic.h
+ transform/substitute_override.cc
+ transform/substitute_override.h
transform/transform.cc
transform/transform.h
transform/unshadow.cc
@@ -450,23 +463,27 @@ set(TINT_LIB_SRCS
transform/vectorize_scalar_matrix_constructors.h
transform/vertex_pulling.cc
transform/vertex_pulling.h
- transform/wrap_arrays_in_structs.cc
- transform/wrap_arrays_in_structs.h
+ transform/while_to_loop.cc
+ transform/while_to_loop.h
transform/zero_init_workgroup_memory.cc
transform/zero_init_workgroup_memory.h
utils/bitcast.h
+ utils/bitset.h
utils/block_allocator.h
utils/compiler_macros.h
utils/concat.h
utils/crc32.h
utils/enum_set.h
utils/hash.h
+ utils/hashmap.h
+ utils/hashset.h
utils/map.h
utils/math.h
utils/scoped_assignment.h
utils/string.h
utils/unique_allocator.h
utils/unique_vector.h
+ utils/vector.h
writer/append_vector.cc
writer/append_vector.h
writer/array_length_from_uniform_options.cc
@@ -687,6 +704,7 @@ if(TINT_BUILD_TESTS)
ast/builtin_attribute_test.cc
ast/builtin_texture_helper_test.cc
ast/builtin_texture_helper_test.h
+ ast/builtin_value_test.cc
ast/call_expression_test.cc
ast/call_statement_test.cc
ast/case_statement_test.cc
@@ -721,12 +739,15 @@ if(TINT_BUILD_TESTS)
ast/module_clone_test.cc
ast/module_test.cc
ast/multisampled_texture_test.cc
+ ast/override_test.cc
ast/phony_expression_test.cc
ast/pointer_test.cc
ast/return_statement_test.cc
ast/sampled_texture_test.cc
ast/sampler_test.cc
ast/stage_attribute_test.cc
+ ast/static_assert_test.cc
+ ast/storage_class_test.cc
ast/storage_texture_test.cc
ast/stride_attribute_test.cc
ast/struct_member_align_attribute_test.cc
@@ -736,6 +757,7 @@ if(TINT_BUILD_TESTS)
ast/struct_test.cc
ast/switch_statement_test.cc
ast/test_helper.h
+ ast/texel_format_test.cc
ast/texture_test.cc
ast/traverse_expressions_test.cc
ast/u32_test.cc
@@ -743,6 +765,7 @@ if(TINT_BUILD_TESTS)
ast/variable_decl_statement_test.cc
ast/variable_test.cc
ast/vector_test.cc
+ ast/while_statement_test.cc
ast/workgroup_attribute_test.cc
castable_test.cc
clone_context_test.cc
@@ -767,9 +790,11 @@ if(TINT_BUILD_TESTS)
resolver/call_validation_test.cc
resolver/compound_assignment_validation_test.cc
resolver/compound_statement_test.cc
+ resolver/const_eval_test.cc
resolver/control_block_validation_test.cc
resolver/dependency_graph_test.cc
resolver/entry_point_validation_test.cc
+ resolver/evaluation_stage_test.cc
resolver/function_validation_test.cc
resolver/host_shareable_validation_test.cc
resolver/increment_decrement_validation_test.cc
@@ -778,15 +803,15 @@ if(TINT_BUILD_TESTS)
resolver/is_host_shareable_test.cc
resolver/is_storeable_test.cc
resolver/materialize_test.cc
- resolver/pipeline_overridable_constant_test.cc
+ resolver/override_test.cc
resolver/ptr_ref_test.cc
resolver/ptr_ref_validation_test.cc
resolver/resolver_behavior_test.cc
- resolver/resolver_constants_test.cc
resolver/resolver_test_helper.cc
resolver/resolver_test_helper.h
resolver/resolver_test.cc
resolver/side_effects_test.cc
+ resolver/static_assert_test.cc
resolver/source_variable_test.cc
resolver/storage_class_layout_validation_test.cc
resolver/storage_class_validation_test.cc
@@ -797,13 +822,12 @@ if(TINT_BUILD_TESTS)
resolver/type_validation_test.cc
resolver/validation_test.cc
resolver/validator_is_storeable_test.cc
- resolver/var_let_test.cc
- resolver/var_let_validation_test.cc
+ resolver/variable_test.cc
+ resolver/variable_validation_test.cc
scope_stack_test.cc
sem/atomic.cc
sem/bool_test.cc
sem/builtin_test.cc
- sem/constant_test.cc
sem/depth_multisampled_texture_test.cc
sem/depth_texture_test.cc
sem/expression_test.cc
@@ -833,6 +857,7 @@ if(TINT_BUILD_TESTS)
traits_test.cc
transform/transform_test.cc
utils/bitcast_test.cc
+ utils/bitset_test.cc
utils/block_allocator_test.cc
utils/crc32_test.cc
utils/defer_test.cc
@@ -840,6 +865,8 @@ if(TINT_BUILD_TESTS)
utils/hash_test.cc
utils/io/command_test.cc
utils/io/tmpfile_test.cc
+ utils/hashmap_test.cc
+ utils/hashset_test.cc
utils/map_test.cc
utils/math_test.cc
utils/result_test.cc
@@ -849,6 +876,7 @@ if(TINT_BUILD_TESTS)
utils/transform_test.cc
utils/unique_allocator_test.cc
utils/unique_vector_test.cc
+ utils/vector_test.cc
writer/append_vector_test.cc
writer/flatten_bindings_test.cc
writer/float_to_string_test.cc
@@ -920,15 +948,16 @@ if(TINT_BUILD_TESTS)
reader/wgsl/parser_impl_and_expression_test.cc
reader/wgsl/parser_impl_argument_expression_list_test.cc
reader/wgsl/parser_impl_assignment_stmt_test.cc
- reader/wgsl/parser_impl_body_stmt_test.cc
+ reader/wgsl/parser_impl_bitwise_expression_test.cc
reader/wgsl/parser_impl_break_stmt_test.cc
reader/wgsl/parser_impl_bug_cases_test.cc
reader/wgsl/parser_impl_call_stmt_test.cc
reader/wgsl/parser_impl_case_body_test.cc
- reader/wgsl/parser_impl_const_expr_test.cc
+ reader/wgsl/parser_impl_compound_stmt_test.cc
reader/wgsl/parser_impl_const_literal_test.cc
reader/wgsl/parser_impl_continue_stmt_test.cc
reader/wgsl/parser_impl_continuing_stmt_test.cc
+ reader/wgsl/parser_impl_core_lhs_expression_test.cc
reader/wgsl/parser_impl_depth_texture_test.cc
reader/wgsl/parser_impl_enable_directive_test.cc
reader/wgsl/parser_impl_external_texture_test.cc
@@ -947,12 +976,13 @@ if(TINT_BUILD_TESTS)
reader/wgsl/parser_impl_if_stmt_test.cc
reader/wgsl/parser_impl_inclusive_or_expression_test.cc
reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
+ reader/wgsl/parser_impl_lhs_expression_test.cc
reader/wgsl/parser_impl_logical_and_expression_test.cc
reader/wgsl/parser_impl_logical_or_expression_test.cc
reader/wgsl/parser_impl_loop_stmt_test.cc
reader/wgsl/parser_impl_multiplicative_expression_test.cc
reader/wgsl/parser_impl_param_list_test.cc
- reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
+ reader/wgsl/parser_impl_paren_expression_test.cc
reader/wgsl/parser_impl_pipeline_stage_test.cc
reader/wgsl/parser_impl_primary_expression_test.cc
reader/wgsl/parser_impl_relational_expression_test.cc
@@ -987,6 +1017,7 @@ if(TINT_BUILD_TESTS)
reader/wgsl/parser_impl_variable_ident_decl_test.cc
reader/wgsl/parser_impl_variable_stmt_test.cc
reader/wgsl/parser_impl_variable_qualifier_test.cc
+ reader/wgsl/parser_impl_while_stmt_test.cc
reader/wgsl/token_test.cc
)
endif()
@@ -1015,6 +1046,7 @@ if(TINT_BUILD_TESTS)
writer/spirv/builder_literal_test.cc
writer/spirv/builder_loop_test.cc
writer/spirv/builder_return_test.cc
+ writer/spirv/builder_static_assert_test.cc
writer/spirv/builder_switch_test.cc
writer/spirv/builder_test.cc
writer/spirv/builder_type_test.cc
@@ -1054,6 +1086,7 @@ if(TINT_BUILD_TESTS)
writer/wgsl/generator_impl_literal_test.cc
writer/wgsl/generator_impl_member_accessor_test.cc
writer/wgsl/generator_impl_return_test.cc
+ writer/wgsl/generator_impl_static_assert_test.cc
writer/wgsl/generator_impl_switch_test.cc
writer/wgsl/generator_impl_type_test.cc
writer/wgsl/generator_impl_unary_op_test.cc
@@ -1087,7 +1120,7 @@ if(TINT_BUILD_TESTS)
transform/module_scope_var_to_entry_point_param_test.cc
transform/multiplanar_external_texture_test.cc
transform/num_workgroups_from_uniform_test.cc
- transform/promote_initializers_to_const_var_test.cc
+ transform/promote_initializers_to_let_test.cc
transform/promote_side_effects_to_decl_test.cc
transform/remove_continue_in_switch_test.cc
transform/remove_phonies_test.cc
@@ -1096,13 +1129,15 @@ if(TINT_BUILD_TESTS)
transform/robustness_test.cc
transform/simplify_pointers_test.cc
transform/single_entry_point_test.cc
+ transform/spirv_atomic_test.cc
+ transform/substitute_override_test.cc
transform/test_helper.h
transform/unshadow_test.cc
transform/unwind_discard_functions_test.cc
transform/var_for_dynamic_index_test.cc
transform/vectorize_scalar_matrix_constructors_test.cc
transform/vertex_pulling_test.cc
- transform/wrap_arrays_in_structs_test.cc
+ transform/while_to_loop_test.cc
transform/zero_init_workgroup_memory_test.cc
transform/utils/get_insertion_point_test.cc
transform/utils/hoist_to_decl_before_test.cc
@@ -1134,6 +1169,7 @@ if(TINT_BUILD_TESTS)
writer/msl/generator_impl_module_constant_test.cc
writer/msl/generator_impl_return_test.cc
writer/msl/generator_impl_sanitizer_test.cc
+ writer/msl/generator_impl_static_assert_test.cc
writer/msl/generator_impl_switch_test.cc
writer/msl/generator_impl_test.cc
writer/msl/generator_impl_type_test.cc
@@ -1205,6 +1241,7 @@ if(TINT_BUILD_TESTS)
writer/hlsl/generator_impl_module_constant_test.cc
writer/hlsl/generator_impl_return_test.cc
writer/hlsl/generator_impl_sanitizer_test.cc
+ writer/hlsl/generator_impl_static_assert_test.cc
writer/hlsl/generator_impl_switch_test.cc
writer/hlsl/generator_impl_test.cc
writer/hlsl/generator_impl_type_test.cc
@@ -1260,6 +1297,9 @@ if(TINT_BUILD_BENCHMARKS)
set(TINT_BENCHMARK_SRC
"castable_bench.cc"
+ "ast/extension_bench.cc"
+ "ast/storage_class_bench.cc"
+ "ast/texel_format_bench.cc"
"bench/benchmark.cc"
"reader/wgsl/parser_bench.cc"
)
diff --git a/chromium/third_party/dawn/src/tint/ast/alias.cc b/chromium/third_party/dawn/src/tint/ast/alias.cc
index fa98cd486b7..8a23e8f45d2 100644
--- a/chromium/third_party/dawn/src/tint/ast/alias.cc
+++ b/chromium/third_party/dawn/src/tint/ast/alias.cc
@@ -20,8 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Alias);
namespace tint::ast {
-Alias::Alias(ProgramID pid, const Source& src, const Symbol& n, const Type* subtype)
- : Base(pid, src, n), type(subtype) {
+Alias::Alias(ProgramID pid, NodeID nid, const Source& src, const Symbol& n, const Type* subtype)
+ : Base(pid, nid, src, n), type(subtype) {
TINT_ASSERT(AST, type);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/alias.h b/chromium/third_party/dawn/src/tint/ast/alias.h
index 87ce57874de..74d91b04c22 100644
--- a/chromium/third_party/dawn/src/tint/ast/alias.h
+++ b/chromium/third_party/dawn/src/tint/ast/alias.h
@@ -26,10 +26,11 @@ class Alias final : public Castable<Alias, TypeDecl> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param name the symbol for the alias
/// @param subtype the alias'd type
- Alias(ProgramID pid, const Source& src, const Symbol& name, const Type* subtype);
+ Alias(ProgramID pid, NodeID nid, const Source& src, const Symbol& name, const Type* subtype);
/// Move constructor
Alias(Alias&&);
/// Destructor
diff --git a/chromium/third_party/dawn/src/tint/ast/array.cc b/chromium/third_party/dawn/src/tint/ast/array.cc
index 0389ed0d9c4..6a898f43ed0 100644
--- a/chromium/third_party/dawn/src/tint/ast/array.cc
+++ b/chromium/third_party/dawn/src/tint/ast/array.cc
@@ -15,6 +15,7 @@
#include "src/tint/ast/array.h"
#include <cmath>
+#include <utility>
#include "src/tint/program_builder.h"
@@ -38,11 +39,12 @@ std::string SizeExprToString(const Expression* size, const SymbolTable& symbols)
} // namespace
Array::Array(ProgramID pid,
+ NodeID nid,
const Source& src,
const Type* subtype,
const Expression* cnt,
- AttributeList attrs)
- : Base(pid, src), type(subtype), count(cnt), attributes(attrs) {}
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src), type(subtype), count(cnt), attributes(std::move(attrs)) {}
Array::Array(Array&&) = default;
@@ -55,11 +57,14 @@ std::string Array::FriendlyName(const SymbolTable& symbols) const {
out << "@stride(" << stride->stride << ") ";
}
}
- out << "array<" << type->FriendlyName(symbols);
- if (!IsRuntimeArray()) {
- out << ", " << SizeExprToString(count, symbols);
+ out << "array";
+ if (type) {
+ out << "<" << type->FriendlyName(symbols);
+ if (count) {
+ out << ", " << SizeExprToString(count, symbols);
+ }
+ out << ">";
}
- out << ">";
return out.str();
}
@@ -69,7 +74,7 @@ const Array* Array::Clone(CloneContext* ctx) const {
auto* ty = ctx->Clone(type);
auto* cnt = ctx->Clone(count);
auto attrs = ctx->Clone(attributes);
- return ctx->dst->create<Array>(src, ty, cnt, attrs);
+ return ctx->dst->create<Array>(src, ty, cnt, std::move(attrs));
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/array.h b/chromium/third_party/dawn/src/tint/ast/array.h
index e92902d4cb1..19e806ee82c 100644
--- a/chromium/third_party/dawn/src/tint/ast/array.h
+++ b/chromium/third_party/dawn/src/tint/ast/array.h
@@ -32,23 +32,25 @@ class Array final : public Castable<Array, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param subtype the type of the array elements
- /// @param count the number of elements in the array. nullptr represents a
- /// runtime-sized array.
+ /// @param count the number of elements in the array
/// @param attributes the array attributes
+ /// @note a runtime-sized array is represented by a null count and a non-null type
Array(ProgramID pid,
+ NodeID nid,
const Source& src,
const Type* subtype,
const Expression* count,
- AttributeList attributes);
+ utils::VectorRef<const Attribute*> attributes);
/// Move constructor
Array(Array&&);
~Array() override;
/// @returns true if this is a runtime array.
/// i.e. the size is determined at runtime
- bool IsRuntimeArray() const { return count == nullptr; }
+ bool IsRuntimeArray() const { return type != nullptr && count == nullptr; }
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be
@@ -67,7 +69,7 @@ class Array final : public Castable<Array, Type> {
const Expression* const count;
/// the array attributes
- const AttributeList attributes;
+ const utils::Vector<const Attribute*, 1> attributes;
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/array_test.cc b/chromium/third_party/dawn/src/tint/ast/array_test.cc
index baed0791e71..e2ce77b9d5c 100644
--- a/chromium/third_party/dawn/src/tint/ast/array_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/array_test.cc
@@ -26,7 +26,7 @@ using AstArrayTest = TestHelper;
TEST_F(AstArrayTest, CreateSizedArray) {
auto* u32 = create<U32>();
auto* count = Expr(3_u);
- auto* arr = create<Array>(u32, count, AttributeList{});
+ auto* arr = create<Array>(u32, count, utils::Empty);
EXPECT_EQ(arr->type, u32);
EXPECT_EQ(arr->count, count);
EXPECT_TRUE(arr->Is<Array>());
@@ -35,36 +35,54 @@ TEST_F(AstArrayTest, CreateSizedArray) {
TEST_F(AstArrayTest, CreateRuntimeArray) {
auto* u32 = create<U32>();
- auto* arr = create<Array>(u32, nullptr, AttributeList{});
+ auto* arr = create<Array>(u32, nullptr, utils::Empty);
EXPECT_EQ(arr->type, u32);
EXPECT_EQ(arr->count, nullptr);
EXPECT_TRUE(arr->Is<Array>());
EXPECT_TRUE(arr->IsRuntimeArray());
}
+TEST_F(AstArrayTest, CreateInferredTypeArray) {
+ auto* arr = create<Array>(nullptr, nullptr, utils::Empty);
+ EXPECT_EQ(arr->type, nullptr);
+ EXPECT_EQ(arr->count, nullptr);
+ EXPECT_TRUE(arr->Is<Array>());
+ EXPECT_FALSE(arr->IsRuntimeArray());
+}
+
TEST_F(AstArrayTest, FriendlyName_RuntimeSized) {
auto* i32 = create<I32>();
- auto* arr = create<Array>(i32, nullptr, AttributeList{});
+ auto* arr = create<Array>(i32, nullptr, utils::Empty);
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
}
TEST_F(AstArrayTest, FriendlyName_LiteralSized) {
auto* i32 = create<I32>();
- auto* arr = create<Array>(i32, Expr(5_u), AttributeList{});
+ auto* arr = create<Array>(i32, Expr(5_u), utils::Empty);
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
}
TEST_F(AstArrayTest, FriendlyName_ConstantSized) {
auto* i32 = create<I32>();
- auto* arr = create<Array>(i32, Expr("size"), AttributeList{});
+ auto* arr = create<Array>(i32, Expr("size"), utils::Empty);
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, size>");
}
TEST_F(AstArrayTest, FriendlyName_WithStride) {
auto* i32 = create<I32>();
- auto* arr = create<Array>(i32, Expr(5_u), AttributeList{create<StrideAttribute>(32)});
+ auto* arr = create<Array>(i32, Expr(5_u), utils::Vector{create<StrideAttribute>(32u)});
EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array<i32, 5>");
}
+TEST_F(AstArrayTest, FriendlyName_InferredTypeAndCount) {
+ auto* arr = create<Array>(nullptr, nullptr, utils::Empty);
+ EXPECT_EQ(arr->FriendlyName(Symbols()), "array");
+}
+
+TEST_F(AstArrayTest, FriendlyName_InferredTypeAndCount_WithStrize) {
+ auto* arr = create<Array>(nullptr, nullptr, utils::Vector{create<StrideAttribute>(32u)});
+ EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array");
+}
+
} // namespace
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/assignment_statement.cc b/chromium/third_party/dawn/src/tint/ast/assignment_statement.cc
index d7d7bc582a8..6a835b88eca 100644
--- a/chromium/third_party/dawn/src/tint/ast/assignment_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/assignment_statement.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::AssignmentStatement);
namespace tint::ast {
AssignmentStatement::AssignmentStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* l,
const Expression* r)
- : Base(pid, src), lhs(l), rhs(r) {
+ : Base(pid, nid, src), lhs(l), rhs(r) {
TINT_ASSERT(AST, lhs);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
TINT_ASSERT(AST, rhs);
diff --git a/chromium/third_party/dawn/src/tint/ast/assignment_statement.h b/chromium/third_party/dawn/src/tint/ast/assignment_statement.h
index 9def075e76f..6b8c412f47b 100644
--- a/chromium/third_party/dawn/src/tint/ast/assignment_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/assignment_statement.h
@@ -24,11 +24,13 @@ namespace tint::ast {
class AssignmentStatement final : public Castable<AssignmentStatement, Statement> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the assignment statement source
/// @param lhs the left side of the expression
/// @param rhs the right side of the expression
- AssignmentStatement(ProgramID program_id,
+ AssignmentStatement(ProgramID pid,
+ NodeID nid,
const Source& source,
const Expression* lhs,
const Expression* rhs);
diff --git a/chromium/third_party/dawn/src/tint/ast/ast_type.cc b/chromium/third_party/dawn/src/tint/ast/ast_type.cc
index ec247c94604..768493f90ae 100644
--- a/chromium/third_party/dawn/src/tint/ast/ast_type.cc
+++ b/chromium/third_party/dawn/src/tint/ast/ast_type.cc
@@ -30,7 +30,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Type);
namespace tint::ast {
-Type::Type(ProgramID pid, const Source& src) : Base(pid, src) {}
+Type::Type(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
Type::Type(Type&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/atomic.cc b/chromium/third_party/dawn/src/tint/ast/atomic.cc
index ce7019b8530..9914c6a8bc8 100644
--- a/chromium/third_party/dawn/src/tint/ast/atomic.cc
+++ b/chromium/third_party/dawn/src/tint/ast/atomic.cc
@@ -20,8 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Atomic);
namespace tint::ast {
-Atomic::Atomic(ProgramID pid, const Source& src, const Type* const subtype)
- : Base(pid, src), type(subtype) {}
+Atomic::Atomic(ProgramID pid, NodeID nid, const Source& src, const Type* const subtype)
+ : Base(pid, nid, src), type(subtype) {}
std::string Atomic::FriendlyName(const SymbolTable& symbols) const {
std::ostringstream out;
diff --git a/chromium/third_party/dawn/src/tint/ast/atomic.h b/chromium/third_party/dawn/src/tint/ast/atomic.h
index 5f634222f1e..689871e1cf6 100644
--- a/chromium/third_party/dawn/src/tint/ast/atomic.h
+++ b/chromium/third_party/dawn/src/tint/ast/atomic.h
@@ -26,9 +26,10 @@ class Atomic final : public Castable<Atomic, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param subtype the pointee type
- Atomic(ProgramID pid, const Source& src, const Type* const subtype);
+ Atomic(ProgramID pid, NodeID nid, const Source& src, const Type* const subtype);
/// Move constructor
Atomic(Atomic&&);
~Atomic() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/attribute.h b/chromium/third_party/dawn/src/tint/ast/attribute.h
index cb9bf766d41..180978258f1 100644
--- a/chromium/third_party/dawn/src/tint/ast/attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/attribute.h
@@ -33,19 +33,17 @@ class Attribute : public Castable<Attribute, Node> {
protected:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- Attribute(ProgramID pid, const Source& src) : Base(pid, src) {}
+ Attribute(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
};
-/// A list of attributes
-using AttributeList = std::vector<const Attribute*>;
-
/// @param attributes the list of attributes to search
/// @returns true if `attributes` includes a attribute of type `T`
-template <typename T>
-bool HasAttribute(const AttributeList& attributes) {
+template <typename... Ts>
+bool HasAttribute(utils::VectorRef<const Attribute*> attributes) {
for (auto* attr : attributes) {
- if (attr->Is<T>()) {
+ if (attr->IsAnyOf<Ts...>()) {
return true;
}
}
@@ -55,7 +53,7 @@ bool HasAttribute(const AttributeList& attributes) {
/// @param attributes the list of attributes to search
/// @returns a pointer to `T` from `attributes` if found, otherwise nullptr.
template <typename T>
-const T* GetAttribute(const AttributeList& attributes) {
+const T* GetAttribute(utils::VectorRef<const Attribute*> attributes) {
for (auto* attr : attributes) {
if (attr->Is<T>()) {
return attr->As<T>();
diff --git a/chromium/third_party/dawn/src/tint/ast/binary_expression.cc b/chromium/third_party/dawn/src/tint/ast/binary_expression.cc
index e3ccd8b8824..ebf704eee02 100644
--- a/chromium/third_party/dawn/src/tint/ast/binary_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/binary_expression.cc
@@ -21,11 +21,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::BinaryExpression);
namespace tint::ast {
BinaryExpression::BinaryExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
BinaryOp o,
const Expression* l,
const Expression* r)
- : Base(pid, src), op(o), lhs(l), rhs(r) {
+ : Base(pid, nid, src), op(o), lhs(l), rhs(r) {
TINT_ASSERT(AST, lhs);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
TINT_ASSERT(AST, rhs);
diff --git a/chromium/third_party/dawn/src/tint/ast/binary_expression.h b/chromium/third_party/dawn/src/tint/ast/binary_expression.h
index ad59da401de..cdc5960f3cb 100644
--- a/chromium/third_party/dawn/src/tint/ast/binary_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/binary_expression.h
@@ -46,12 +46,14 @@ enum class BinaryOp {
class BinaryExpression final : public Castable<BinaryExpression, Expression> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the binary expression source
/// @param op the operation type
/// @param lhs the left side of the expression
/// @param rhs the right side of the expression
- BinaryExpression(ProgramID program_id,
+ BinaryExpression(ProgramID pid,
+ NodeID nid,
const Source& source,
BinaryOp op,
const Expression* lhs,
diff --git a/chromium/third_party/dawn/src/tint/ast/binding_attribute.cc b/chromium/third_party/dawn/src/tint/ast/binding_attribute.cc
index b9282f2aeea..8180f99fa12 100644
--- a/chromium/third_party/dawn/src/tint/ast/binding_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/binding_attribute.cc
@@ -22,8 +22,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::BindingAttribute);
namespace tint::ast {
-BindingAttribute::BindingAttribute(ProgramID pid, const Source& src, uint32_t val)
- : Base(pid, src), value(val) {}
+BindingAttribute::BindingAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t val)
+ : Base(pid, nid, src), value(val) {}
BindingAttribute::~BindingAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/binding_attribute.h b/chromium/third_party/dawn/src/tint/ast/binding_attribute.h
index 33c5f695421..b5379b8bb4f 100644
--- a/chromium/third_party/dawn/src/tint/ast/binding_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/binding_attribute.h
@@ -26,9 +26,10 @@ class BindingAttribute final : public Castable<BindingAttribute, Attribute> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param value the binding value
- BindingAttribute(ProgramID pid, const Source& src, uint32_t value);
+ BindingAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t value);
~BindingAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/binding_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/binding_attribute_test.cc
index f51fc25c270..800093360d7 100644
--- a/chromium/third_party/dawn/src/tint/ast/binding_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/binding_attribute_test.cc
@@ -20,7 +20,7 @@ namespace {
using BindingAttributeTest = TestHelper;
TEST_F(BindingAttributeTest, Creation) {
- auto* d = create<BindingAttribute>(2);
+ auto* d = create<BindingAttribute>(2u);
EXPECT_EQ(2u, d->value);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/bitcast_expression.cc b/chromium/third_party/dawn/src/tint/ast/bitcast_expression.cc
index a81c5dd47e3..5cabf67e028 100644
--- a/chromium/third_party/dawn/src/tint/ast/bitcast_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/bitcast_expression.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::BitcastExpression);
namespace tint::ast {
BitcastExpression::BitcastExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
const Type* t,
const Expression* e)
- : Base(pid, src), type(t), expr(e) {
+ : Base(pid, nid, src), type(t), expr(e) {
TINT_ASSERT(AST, type);
TINT_ASSERT(AST, expr);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
diff --git a/chromium/third_party/dawn/src/tint/ast/bitcast_expression.h b/chromium/third_party/dawn/src/tint/ast/bitcast_expression.h
index a231cd286c5..66952b72479 100644
--- a/chromium/third_party/dawn/src/tint/ast/bitcast_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/bitcast_expression.h
@@ -28,11 +28,13 @@ namespace tint::ast {
class BitcastExpression final : public Castable<BitcastExpression, Expression> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the bitcast expression source
/// @param type the type
/// @param expr the expr
- BitcastExpression(ProgramID program_id,
+ BitcastExpression(ProgramID pid,
+ NodeID nid,
const Source& source,
const Type* type,
const Expression* expr);
diff --git a/chromium/third_party/dawn/src/tint/ast/block_statement.cc b/chromium/third_party/dawn/src/tint/ast/block_statement.cc
index 7d4f49237ae..430dbbaa0e8 100644
--- a/chromium/third_party/dawn/src/tint/ast/block_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/block_statement.cc
@@ -20,8 +20,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::BlockStatement);
namespace tint::ast {
-BlockStatement::BlockStatement(ProgramID pid, const Source& src, const StatementList& stmts)
- : Base(pid, src), statements(std::move(stmts)) {
+BlockStatement::BlockStatement(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ utils::VectorRef<const Statement*> stmts)
+ : Base(pid, nid, src), statements(std::move(stmts)) {
for (auto* stmt : statements) {
TINT_ASSERT(AST, stmt);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, stmt, program_id);
@@ -36,7 +39,7 @@ const BlockStatement* BlockStatement::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source);
auto stmts = ctx->Clone(statements);
- return ctx->dst->create<BlockStatement>(src, stmts);
+ return ctx->dst->create<BlockStatement>(src, std::move(stmts));
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/block_statement.h b/chromium/third_party/dawn/src/tint/ast/block_statement.h
index 48ea35a0fed..22d0a65e5b1 100644
--- a/chromium/third_party/dawn/src/tint/ast/block_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/block_statement.h
@@ -25,19 +25,23 @@ namespace tint::ast {
class BlockStatement final : public Castable<BlockStatement, Statement> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the block statement source
/// @param statements the statements
- BlockStatement(ProgramID program_id, const Source& source, const StatementList& statements);
+ BlockStatement(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ utils::VectorRef<const Statement*> statements);
/// Move constructor
BlockStatement(BlockStatement&&);
~BlockStatement() override;
/// @returns true if the block has no statements
- bool Empty() const { return statements.empty(); }
+ bool Empty() const { return statements.IsEmpty(); }
/// @returns the last statement in the block or nullptr if block empty
- const Statement* Last() const { return statements.empty() ? nullptr : statements.back(); }
+ const Statement* Last() const { return statements.IsEmpty() ? nullptr : statements.Back(); }
/// Clones this node and all transitive child nodes using the `CloneContext`
/// `ctx`.
@@ -46,7 +50,7 @@ class BlockStatement final : public Castable<BlockStatement, Statement> {
const BlockStatement* Clone(CloneContext* ctx) const override;
/// the statement list
- const StatementList statements;
+ const utils::Vector<const Statement*, 8> statements;
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/block_statement_test.cc b/chromium/third_party/dawn/src/tint/ast/block_statement_test.cc
index 4097b209acd..ec92c3f9d20 100644
--- a/chromium/third_party/dawn/src/tint/ast/block_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/block_statement_test.cc
@@ -26,21 +26,21 @@ TEST_F(BlockStatementTest, Creation) {
auto* d = create<DiscardStatement>();
auto* ptr = d;
- auto* b = create<BlockStatement>(StatementList{d});
+ auto* b = create<BlockStatement>(utils::Vector{d});
- ASSERT_EQ(b->statements.size(), 1u);
+ ASSERT_EQ(b->statements.Length(), 1u);
EXPECT_EQ(b->statements[0], ptr);
}
TEST_F(BlockStatementTest, Creation_WithSource) {
- auto* b = create<BlockStatement>(Source{Source::Location{20, 2}}, ast::StatementList{});
+ auto* b = create<BlockStatement>(Source{Source::Location{20, 2}}, utils::Empty);
auto src = b->source;
EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u);
}
TEST_F(BlockStatementTest, IsBlock) {
- auto* b = create<BlockStatement>(ast::StatementList{});
+ auto* b = create<BlockStatement>(utils::Empty);
EXPECT_TRUE(b->Is<BlockStatement>());
}
@@ -48,7 +48,7 @@ TEST_F(BlockStatementTest, Assert_Null_Statement) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<BlockStatement>(ast::StatementList{nullptr});
+ b.create<BlockStatement>(utils::Vector<const ast::Statement*, 1>{nullptr});
},
"internal compiler error");
}
@@ -58,7 +58,7 @@ TEST_F(BlockStatementTest, Assert_DifferentProgramID_Statement) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<BlockStatement>(ast::StatementList{b2.create<DiscardStatement>()});
+ b1.create<BlockStatement>(utils::Vector{b2.create<DiscardStatement>()});
},
"internal compiler error");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/bool.cc b/chromium/third_party/dawn/src/tint/ast/bool.cc
index af951e75381..9b326eb044b 100644
--- a/chromium/third_party/dawn/src/tint/ast/bool.cc
+++ b/chromium/third_party/dawn/src/tint/ast/bool.cc
@@ -20,7 +20,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Bool);
namespace tint::ast {
-Bool::Bool(ProgramID pid, const Source& src) : Base(pid, src) {}
+Bool::Bool(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
Bool::Bool(Bool&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/bool.h b/chromium/third_party/dawn/src/tint/ast/bool.h
index bfe3b781233..d61e49d6af0 100644
--- a/chromium/third_party/dawn/src/tint/ast/bool.h
+++ b/chromium/third_party/dawn/src/tint/ast/bool.h
@@ -32,8 +32,9 @@ class Bool final : public Castable<Bool, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- Bool(ProgramID pid, const Source& src);
+ Bool(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
Bool(Bool&&);
~Bool() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.cc b/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.cc
index cfaacb95ae5..10ab4f0723b 100644
--- a/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.cc
@@ -20,8 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::BoolLiteralExpression);
namespace tint::ast {
-BoolLiteralExpression::BoolLiteralExpression(ProgramID pid, const Source& src, bool val)
- : Base(pid, src), value(val) {}
+BoolLiteralExpression::BoolLiteralExpression(ProgramID pid, NodeID nid, const Source& src, bool val)
+ : Base(pid, nid, src), value(val) {}
BoolLiteralExpression::~BoolLiteralExpression() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.h b/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.h
index f2c4c3f84c5..bebd924a7f2 100644
--- a/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/bool_literal_expression.h
@@ -26,9 +26,10 @@ class BoolLiteralExpression final : public Castable<BoolLiteralExpression, Liter
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param value the bool literals value
- BoolLiteralExpression(ProgramID pid, const Source& src, bool value);
+ BoolLiteralExpression(ProgramID pid, NodeID nid, const Source& src, bool value);
~BoolLiteralExpression() override;
/// Clones this node and all transitive child nodes using the `CloneContext`
diff --git a/chromium/third_party/dawn/src/tint/ast/break_statement.cc b/chromium/third_party/dawn/src/tint/ast/break_statement.cc
index 02900141ea6..ecd5f06e698 100644
--- a/chromium/third_party/dawn/src/tint/ast/break_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/break_statement.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::BreakStatement);
namespace tint::ast {
-BreakStatement::BreakStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
+BreakStatement::BreakStatement(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src) {}
BreakStatement::BreakStatement(BreakStatement&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/break_statement.h b/chromium/third_party/dawn/src/tint/ast/break_statement.h
index 29e5eeb012a..92f67b7c635 100644
--- a/chromium/third_party/dawn/src/tint/ast/break_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/break_statement.h
@@ -24,8 +24,9 @@ class BreakStatement final : public Castable<BreakStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- BreakStatement(ProgramID pid, const Source& src);
+ BreakStatement(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
BreakStatement(BreakStatement&&);
~BreakStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin.cc b/chromium/third_party/dawn/src/tint/ast/builtin.cc
deleted file mode 100644
index d215a5c3eef..00000000000
--- a/chromium/third_party/dawn/src/tint/ast/builtin.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/ast/builtin.h"
-
-namespace tint::ast {
-
-std::ostream& operator<<(std::ostream& out, Builtin builtin) {
- switch (builtin) {
- case Builtin::kNone: {
- out << "none";
- break;
- }
- case Builtin::kPosition: {
- out << "position";
- break;
- }
- case Builtin::kVertexIndex: {
- out << "vertex_index";
- break;
- }
- case Builtin::kInstanceIndex: {
- out << "instance_index";
- break;
- }
- case Builtin::kFrontFacing: {
- out << "front_facing";
- break;
- }
- case Builtin::kFragDepth: {
- out << "frag_depth";
- break;
- }
- case Builtin::kLocalInvocationId: {
- out << "local_invocation_id";
- break;
- }
- case Builtin::kLocalInvocationIndex: {
- out << "local_invocation_index";
- break;
- }
- case Builtin::kGlobalInvocationId: {
- out << "global_invocation_id";
- break;
- }
- case Builtin::kWorkgroupId: {
- out << "workgroup_id";
- break;
- }
- case Builtin::kNumWorkgroups: {
- out << "num_workgroups";
- break;
- }
- case Builtin::kSampleIndex: {
- out << "sample_index";
- break;
- }
- case Builtin::kSampleMask: {
- out << "sample_mask";
- break;
- }
- case Builtin::kPointSize: {
- out << "pointsize";
- }
- }
- return out;
-}
-
-} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_attribute.cc b/chromium/third_party/dawn/src/tint/ast/builtin_attribute.cc
index 03e47b60749..d5aace008a0 100644
--- a/chromium/third_party/dawn/src/tint/ast/builtin_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_attribute.cc
@@ -22,8 +22,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::BuiltinAttribute);
namespace tint::ast {
-BuiltinAttribute::BuiltinAttribute(ProgramID pid, const Source& src, Builtin b)
- : Base(pid, src), builtin(b) {}
+BuiltinAttribute::BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, BuiltinValue b)
+ : Base(pid, nid, src), builtin(b) {}
BuiltinAttribute::~BuiltinAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_attribute.h b/chromium/third_party/dawn/src/tint/ast/builtin_attribute.h
index 75898be5964..0aae24b57c4 100644
--- a/chromium/third_party/dawn/src/tint/ast/builtin_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_attribute.h
@@ -18,7 +18,7 @@
#include <string>
#include "src/tint/ast/attribute.h"
-#include "src/tint/ast/builtin.h"
+#include "src/tint/ast/builtin_value.h"
namespace tint::ast {
@@ -27,9 +27,10 @@ class BuiltinAttribute final : public Castable<BuiltinAttribute, Attribute> {
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param builtin the builtin value
- BuiltinAttribute(ProgramID pid, const Source& src, Builtin builtin);
+ BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, BuiltinValue builtin);
~BuiltinAttribute() override;
/// @returns the WGSL name for the attribute
@@ -42,7 +43,7 @@ class BuiltinAttribute final : public Castable<BuiltinAttribute, Attribute> {
const BuiltinAttribute* Clone(CloneContext* ctx) const override;
/// The builtin value
- const Builtin builtin;
+ const BuiltinValue builtin;
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/builtin_attribute_test.cc
index a57f5b1f08e..dba6997faa4 100644
--- a/chromium/third_party/dawn/src/tint/ast/builtin_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_attribute_test.cc
@@ -20,8 +20,8 @@ namespace {
using BuiltinAttributeTest = TestHelper;
TEST_F(BuiltinAttributeTest, Creation) {
- auto* d = create<BuiltinAttribute>(Builtin::kFragDepth);
- EXPECT_EQ(Builtin::kFragDepth, d->builtin);
+ auto* d = create<BuiltinAttribute>(BuiltinValue::kFragDepth);
+ EXPECT_EQ(BuiltinValue::kFragDepth, d->builtin);
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.cc b/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.cc
index 21cbd931d0c..882c0bb0d46 100644
--- a/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.cc
@@ -29,7 +29,7 @@ TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
ast::TextureDimension dims,
TextureDataType datatype,
const char* f,
- std::function<ExpressionList(ProgramBuilder*)> a)
+ std::function<Args(ProgramBuilder*)> a)
: overload(o),
description(desc),
texture_kind(tk),
@@ -44,7 +44,7 @@ TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
ast::TextureDimension dims,
TextureDataType datatype,
const char* f,
- std::function<ExpressionList(ProgramBuilder*)> a)
+ std::function<Args(ProgramBuilder*)> a)
: overload(o),
description(desc),
texture_kind(tk),
@@ -59,7 +59,7 @@ TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
ast::TextureDimension dims,
TextureDataType datatype,
const char* f,
- std::function<ExpressionList(ProgramBuilder*)> a)
+ std::function<Args(ProgramBuilder*)> a)
: overload(o),
description(d),
texture_kind(TextureKind::kStorage),
@@ -141,31 +141,32 @@ const ast::Type* TextureOverloadCase::BuildResultVectorComponentType(ProgramBuil
}
const ast::Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b) const {
- AttributeList attrs = {
- b->create<ast::GroupAttribute>(0),
- b->create<ast::BindingAttribute>(0),
+ utils::Vector attrs{
+ b->create<ast::GroupAttribute>(0u),
+ b->create<ast::BindingAttribute>(0u),
};
switch (texture_kind) {
case ast::builtin::test::TextureKind::kRegular:
- return b->Global(
+ return b->GlobalVar(
"texture",
b->ty.sampled_texture(texture_dimension, BuildResultVectorComponentType(b)), attrs);
case ast::builtin::test::TextureKind::kDepth:
- return b->Global("texture", b->ty.depth_texture(texture_dimension), attrs);
+ return b->GlobalVar("texture", b->ty.depth_texture(texture_dimension), attrs);
case ast::builtin::test::TextureKind::kDepthMultisampled:
- return b->Global("texture", b->ty.depth_multisampled_texture(texture_dimension), attrs);
+ return b->GlobalVar("texture", b->ty.depth_multisampled_texture(texture_dimension),
+ attrs);
case ast::builtin::test::TextureKind::kMultisampled:
- return b->Global(
+ return b->GlobalVar(
"texture",
b->ty.multisampled_texture(texture_dimension, BuildResultVectorComponentType(b)),
attrs);
case ast::builtin::test::TextureKind::kStorage: {
auto* st = b->ty.storage_texture(texture_dimension, texel_format, access);
- return b->Global("texture", st, attrs);
+ return b->GlobalVar("texture", st, attrs);
}
}
@@ -174,11 +175,11 @@ const ast::Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b
}
const ast::Variable* TextureOverloadCase::BuildSamplerVariable(ProgramBuilder* b) const {
- AttributeList attrs = {
- b->create<ast::GroupAttribute>(0),
- b->create<ast::BindingAttribute>(1),
+ utils::Vector attrs = {
+ b->create<ast::GroupAttribute>(0u),
+ b->create<ast::BindingAttribute>(1u),
};
- return b->Global("sampler", b->ty.sampler(sampler_kind), attrs);
+ return b->GlobalVar("sampler", b->ty.sampler(sampler_kind), attrs);
}
std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.h b/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.h
index d2737e194cf..bb61875d00e 100644
--- a/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.h
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_texture_helper_test.h
@@ -177,6 +177,9 @@ bool ReturnsVoid(ValidTextureOverload texture_overload);
/// Describes a texture builtin overload
struct TextureOverloadCase {
+ /// Args is a list of ast::Expression used as arguments to the texture overload case.
+ using Args = utils::Vector<const ast::Expression*, 8>;
+
/// Constructor for textureSample...() functions
TextureOverloadCase(ValidTextureOverload,
const char*,
@@ -185,7 +188,7 @@ struct TextureOverloadCase {
ast::TextureDimension,
TextureDataType,
const char*,
- std::function<ExpressionList(ProgramBuilder*)>);
+ std::function<Args(ProgramBuilder*)>);
/// Constructor for textureLoad() functions with non-storage textures
TextureOverloadCase(ValidTextureOverload,
const char*,
@@ -193,7 +196,7 @@ struct TextureOverloadCase {
ast::TextureDimension,
TextureDataType,
const char*,
- std::function<ExpressionList(ProgramBuilder*)>);
+ std::function<Args(ProgramBuilder*)>);
/// Constructor for textureLoad() with storage textures
TextureOverloadCase(ValidTextureOverload,
const char*,
@@ -202,7 +205,7 @@ struct TextureOverloadCase {
ast::TextureDimension,
TextureDataType,
const char*,
- std::function<ExpressionList(ProgramBuilder*)>);
+ std::function<Args(ProgramBuilder*)>);
/// Copy constructor
TextureOverloadCase(const TextureOverloadCase&);
/// Destructor
@@ -238,7 +241,7 @@ struct TextureOverloadCase {
Access const access = Access::kReadWrite;
/// The image format for the storage texture
/// Used only when texture_kind is kStorage
- ast::TexelFormat const texel_format = ast::TexelFormat::kNone;
+ ast::TexelFormat const texel_format = ast::TexelFormat::kInvalid;
/// The dimensions of the texture parameter
ast::TextureDimension const texture_dimension;
/// The data type of the texture parameter
@@ -246,7 +249,7 @@ struct TextureOverloadCase {
/// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc
const char* const function;
/// A function that builds the AST arguments for the overload
- std::function<ExpressionList(ProgramBuilder*)> const args;
+ std::function<Args(ProgramBuilder*)> const args;
};
std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data);
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_value.cc b/chromium/third_party/dawn/src/tint/ast/builtin_value.cc
new file mode 100644
index 00000000000..e8d64514048
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value.cc
@@ -0,0 +1,104 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/builtin_value.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/builtin_value.h"
+
+namespace tint::ast {
+
+/// ParseBuiltinValue parses a BuiltinValue from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or BuiltinValue::kInvalid if the string could not be parsed.
+BuiltinValue ParseBuiltinValue(std::string_view str) {
+ if (str == "position") {
+ return BuiltinValue::kPosition;
+ }
+ if (str == "vertex_index") {
+ return BuiltinValue::kVertexIndex;
+ }
+ if (str == "instance_index") {
+ return BuiltinValue::kInstanceIndex;
+ }
+ if (str == "front_facing") {
+ return BuiltinValue::kFrontFacing;
+ }
+ if (str == "frag_depth") {
+ return BuiltinValue::kFragDepth;
+ }
+ if (str == "local_invocation_id") {
+ return BuiltinValue::kLocalInvocationId;
+ }
+ if (str == "local_invocation_index") {
+ return BuiltinValue::kLocalInvocationIndex;
+ }
+ if (str == "global_invocation_id") {
+ return BuiltinValue::kGlobalInvocationId;
+ }
+ if (str == "workgroup_id") {
+ return BuiltinValue::kWorkgroupId;
+ }
+ if (str == "num_workgroups") {
+ return BuiltinValue::kNumWorkgroups;
+ }
+ if (str == "sample_index") {
+ return BuiltinValue::kSampleIndex;
+ }
+ if (str == "sample_mask") {
+ return BuiltinValue::kSampleMask;
+ }
+ return BuiltinValue::kInvalid;
+}
+
+std::ostream& operator<<(std::ostream& out, BuiltinValue value) {
+ switch (value) {
+ case BuiltinValue::kInvalid:
+ return out << "invalid";
+ case BuiltinValue::kPosition:
+ return out << "position";
+ case BuiltinValue::kVertexIndex:
+ return out << "vertex_index";
+ case BuiltinValue::kInstanceIndex:
+ return out << "instance_index";
+ case BuiltinValue::kFrontFacing:
+ return out << "front_facing";
+ case BuiltinValue::kFragDepth:
+ return out << "frag_depth";
+ case BuiltinValue::kLocalInvocationId:
+ return out << "local_invocation_id";
+ case BuiltinValue::kLocalInvocationIndex:
+ return out << "local_invocation_index";
+ case BuiltinValue::kGlobalInvocationId:
+ return out << "global_invocation_id";
+ case BuiltinValue::kWorkgroupId:
+ return out << "workgroup_id";
+ case BuiltinValue::kNumWorkgroups:
+ return out << "num_workgroups";
+ case BuiltinValue::kSampleIndex:
+ return out << "sample_index";
+ case BuiltinValue::kSampleMask:
+ return out << "sample_mask";
+ case BuiltinValue::kPointSize:
+ return out << "point_size";
+ }
+ return out << "<unknown>";
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_value.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/builtin_value.cc.tmpl
new file mode 100644
index 00000000000..7340c8806f4
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value.cc.tmpl
@@ -0,0 +1,22 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#include "src/tint/ast/builtin_value.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin.h b/chromium/third_party/dawn/src/tint/ast/builtin_value.h
index 699632a0e99..0a2c7f02ff3 100644
--- a/chromium/third_party/dawn/src/tint/ast/builtin.h
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value.h
@@ -12,16 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_TINT_AST_BUILTIN_H_
-#define SRC_TINT_AST_BUILTIN_H_
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/builtin_value.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_AST_BUILTIN_VALUE_H_
+#define SRC_TINT_AST_BUILTIN_VALUE_H_
#include <ostream>
namespace tint::ast {
-/// The builtin identifiers
-enum class Builtin {
- kNone = -1,
+/// Storage class of a given pointer.
+enum class BuiltinValue {
+ kInvalid,
kPosition,
kVertexIndex,
kInstanceIndex,
@@ -34,17 +42,19 @@ enum class Builtin {
kNumWorkgroups,
kSampleIndex,
kSampleMask,
-
- // Below are not currently WGSL builtins, but are included in this enum as
- // they are used by certain backends.
- kPointSize,
+ kPointSize, // Tint-internal enum entry - not parsed
};
/// @param out the std::ostream to write to
-/// @param builtin the Builtin
-/// @return the std::ostream so calls can be chained
-std::ostream& operator<<(std::ostream& out, Builtin builtin);
+/// @param value the BuiltinValue
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, BuiltinValue value);
+
+/// ParseBuiltinValue parses a BuiltinValue from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or BuiltinValue::kInvalid if the string could not be parsed.
+BuiltinValue ParseBuiltinValue(std::string_view str);
} // namespace tint::ast
-#endif // SRC_TINT_AST_BUILTIN_H_
+#endif // SRC_TINT_AST_BUILTIN_VALUE_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_value.h.tmpl b/chromium/third_party/dawn/src/tint/ast/builtin_value.h.tmpl
new file mode 100644
index 00000000000..1985305c230
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#ifndef SRC_TINT_AST_BUILTIN_VALUE_H_
+#define SRC_TINT_AST_BUILTIN_VALUE_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Storage class of a given pointer.
+{{ Eval "DeclareEnum" $enum}}
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_BUILTIN_VALUE_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc b/chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc
new file mode 100644
index 00000000000..0a4048c5e12
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc
@@ -0,0 +1,130 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/builtin_value_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void BuiltinValueParser(::benchmark::State& state) {
+ std::array kStrings{
+ "pccsitin",
+ "oiti3",
+ "positVon",
+ "position",
+ "1osition",
+ "osJtqqon",
+ "llos77tion",
+ "vrtHHppx_index",
+ "vertx_icx",
+ "veGtex_bnde",
+ "vertex_index",
+ "vertex_inveii",
+ "veWWtex_ind8x",
+ "vxxrtMx_indx",
+ "isXance_indegg",
+ "insanc_iXVex",
+ "instance_in3ex",
+ "instance_index",
+ "instancE_index",
+ "nsTTance_PPndex",
+ "nstancxx_indddx",
+ "44ront_facing",
+ "fSSont_facinVV",
+ "fronR_Racing",
+ "front_facing",
+ "ron9_faciFg",
+ "front_facin",
+ "fVonRR_HaOing",
+ "fyag_epth",
+ "f77ag_nnellrrh",
+ "fra400depth",
+ "frag_depth",
+ "fa_epooh",
+ "frg_ezzth",
+ "f11a_eppiih",
+ "local_invXXcation_id",
+ "lIIcal_i5599ocation_inn",
+ "HHrrcal_inSSocation_Yaa",
+ "local_invocation_id",
+ "lokkal_invocatini",
+ "jocal_invocRRongid",
+ "local_inocatbon_i",
+ "local_injocation_index",
+ "local_invocatio_index",
+ "locl_invocqtion_ndex",
+ "local_invocation_index",
+ "localNNinvocaton_index",
+ "local_invocatin_ivvdx",
+ "locl_invocatioQQ_index",
+ "globalrnvocaton_iff",
+ "global_invocation_jd",
+ "NNlbal_wwnvocation82d",
+ "global_invocation_id",
+ "global_invocationid",
+ "globalrrinvocation_id",
+ "globaG_invocation_id",
+ "workgroupFFid",
+ "worgrupid",
+ "workgroup_rr",
+ "workgroup_id",
+ "workgrouid",
+ "DokgXoJJp_id",
+ "8orgrup_i",
+ "num_wkkr11up",
+ "numworkgroups",
+ "Ju_workgroups",
+ "num_workgroups",
+ "num_corkgroups",
+ "num_woOkgroups",
+ "num_workKK__vvttps",
+ "smple5inxxe8",
+ "s__mle_qFdex",
+ "saqqple_idex",
+ "sample_index",
+ "saOpe_33nde66",
+ "s6oople_indttQx",
+ "sam66le_inex",
+ "samxe66masOz",
+ "yyample_mask",
+ "amplZZHask",
+ "sample_mask",
+ "WWaple_maq4k",
+ "samplOO_ask",
+ "sYohpe_msk",
+ };
+ for (auto _ : state) {
+ for (auto& str : kStrings) {
+ auto result = ParseBuiltinValue(str);
+ benchmark::DoNotOptimize(result);
+ }
+ }
+}
+
+BENCHMARK(BuiltinValueParser);
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc.tmpl
new file mode 100644
index 00000000000..f50bd20d7ea
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value_bench.cc.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value_bench.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc b/chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc
new file mode 100644
index 00000000000..a29810aa7d4
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc
@@ -0,0 +1,122 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/builtin_value_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+namespace parse_print_tests {
+
+struct Case {
+ const char* string;
+ BuiltinValue value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+ return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+ {"position", BuiltinValue::kPosition},
+ {"vertex_index", BuiltinValue::kVertexIndex},
+ {"instance_index", BuiltinValue::kInstanceIndex},
+ {"front_facing", BuiltinValue::kFrontFacing},
+ {"frag_depth", BuiltinValue::kFragDepth},
+ {"local_invocation_id", BuiltinValue::kLocalInvocationId},
+ {"local_invocation_index", BuiltinValue::kLocalInvocationIndex},
+ {"global_invocation_id", BuiltinValue::kGlobalInvocationId},
+ {"workgroup_id", BuiltinValue::kWorkgroupId},
+ {"num_workgroups", BuiltinValue::kNumWorkgroups},
+ {"sample_index", BuiltinValue::kSampleIndex},
+ {"sample_mask", BuiltinValue::kSampleMask},
+};
+
+static constexpr Case kInvalidCases[] = {
+ {"pccsitin", BuiltinValue::kInvalid},
+ {"oiti3", BuiltinValue::kInvalid},
+ {"positVon", BuiltinValue::kInvalid},
+ {"1ertex_index", BuiltinValue::kInvalid},
+ {"vertex_Jnqex", BuiltinValue::kInvalid},
+ {"velltex_inde77", BuiltinValue::kInvalid},
+ {"inpptanceqHHindx", BuiltinValue::kInvalid},
+ {"cnsanvendex", BuiltinValue::kInvalid},
+ {"istancG_index", BuiltinValue::kInvalid},
+ {"front_facvnii", BuiltinValue::kInvalid},
+ {"frWWnt_faci8g", BuiltinValue::kInvalid},
+ {"fxxonM_facig", BuiltinValue::kInvalid},
+ {"fXag_detgg", BuiltinValue::kInvalid},
+ {"fag_XuVh", BuiltinValue::kInvalid},
+ {"frag_dept3", BuiltinValue::kInvalid},
+ {"local_Envocation_id", BuiltinValue::kInvalid},
+ {"localiPPvocatioTT_id", BuiltinValue::kInvalid},
+ {"localxxnvocationddid", BuiltinValue::kInvalid},
+ {"loca44_invocation_index", BuiltinValue::kInvalid},
+ {"local_invocSStionVVindex", BuiltinValue::kInvalid},
+ {"locRR_invocat22n_index", BuiltinValue::kInvalid},
+ {"globalFinvoction_id", BuiltinValue::kInvalid},
+ {"gloal_invocation_id", BuiltinValue::kInvalid},
+ {"RRlHOOaV_invoction_id", BuiltinValue::kInvalid},
+ {"workgyoup_i", BuiltinValue::kInvalid},
+ {"wnrrrkg77loup_Gd", BuiltinValue::kInvalid},
+ {"00orkgr4up_id", BuiltinValue::kInvalid},
+ {"numwroogrops", BuiltinValue::kInvalid},
+ {"nzm_wokgroups", BuiltinValue::kInvalid},
+ {"uippworkgro11ps", BuiltinValue::kInvalid},
+ {"sample_iXXdex", BuiltinValue::kInvalid},
+ {"5nnample_99IIdex", BuiltinValue::kInvalid},
+ {"samYlaaHHrrndeSS", BuiltinValue::kInvalid},
+ {"aHkk_mask", BuiltinValue::kInvalid},
+ {"jRRmpl_gsk", BuiltinValue::kInvalid},
+ {"smple_mbk", BuiltinValue::kInvalid},
+};
+
+using BuiltinValueParseTest = testing::TestWithParam<Case>;
+
+TEST_P(BuiltinValueParseTest, Parse) {
+ const char* string = GetParam().string;
+ BuiltinValue expect = GetParam().value;
+ EXPECT_EQ(expect, ParseBuiltinValue(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, BuiltinValueParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, BuiltinValueParseTest, testing::ValuesIn(kInvalidCases));
+
+using BuiltinValuePrintTest = testing::TestWithParam<Case>;
+
+TEST_P(BuiltinValuePrintTest, Print) {
+ BuiltinValue value = GetParam().value;
+ const char* expect = GetParam().string;
+ EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, BuiltinValuePrintTest, testing::ValuesIn(kValidCases));
+
+} // namespace parse_print_tests
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc.tmpl
new file mode 100644
index 00000000000..213a81b3ccc
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/builtin_value_test.cc.tmpl
@@ -0,0 +1,27 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/call_expression.cc b/chromium/third_party/dawn/src/tint/ast/call_expression.cc
index 68b6dc344a3..5a8aa96d687 100644
--- a/chromium/third_party/dawn/src/tint/ast/call_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/call_expression.cc
@@ -14,6 +14,8 @@
#include "src/tint/ast/call_expression.h"
+#include <utility>
+
#include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::CallExpression);
@@ -34,10 +36,11 @@ CallExpression::Target ToTarget(const Type* type) {
} // namespace
CallExpression::CallExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
const IdentifierExpression* name,
- ExpressionList a)
- : Base(pid, src), target(ToTarget(name)), args(a) {
+ utils::VectorRef<const Expression*> a)
+ : Base(pid, nid, src), target(ToTarget(name)), args(std::move(a)) {
TINT_ASSERT(AST, name);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
for (auto* arg : args) {
@@ -46,8 +49,12 @@ CallExpression::CallExpression(ProgramID pid,
}
}
-CallExpression::CallExpression(ProgramID pid, const Source& src, const Type* type, ExpressionList a)
- : Base(pid, src), target(ToTarget(type)), args(a) {
+CallExpression::CallExpression(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Type* type,
+ utils::VectorRef<const Expression*> a)
+ : Base(pid, nid, src), target(ToTarget(type)), args(std::move(a)) {
TINT_ASSERT(AST, type);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
for (auto* arg : args) {
@@ -64,8 +71,9 @@ const CallExpression* CallExpression::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source);
auto p = ctx->Clone(args);
- return target.name ? ctx->dst->create<CallExpression>(src, ctx->Clone(target.name), p)
- : ctx->dst->create<CallExpression>(src, ctx->Clone(target.type), p);
+ return target.name
+ ? ctx->dst->create<CallExpression>(src, ctx->Clone(target.name), std::move(p))
+ : ctx->dst->create<CallExpression>(src, ctx->Clone(target.type), std::move(p));
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/call_expression.h b/chromium/third_party/dawn/src/tint/ast/call_expression.h
index 9f197114a56..587a88f0583 100644
--- a/chromium/third_party/dawn/src/tint/ast/call_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/call_expression.h
@@ -33,24 +33,28 @@ namespace tint::ast {
class CallExpression final : public Castable<CallExpression, Expression> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the call expression source
/// @param name the function or type name
/// @param args the arguments
- CallExpression(ProgramID program_id,
+ CallExpression(ProgramID pid,
+ NodeID nid,
const Source& source,
const IdentifierExpression* name,
- ExpressionList args);
+ utils::VectorRef<const Expression*> args);
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the call expression source
/// @param type the type
/// @param args the arguments
- CallExpression(ProgramID program_id,
+ CallExpression(ProgramID pid,
+ NodeID nid,
const Source& source,
const Type* type,
- ExpressionList args);
+ utils::VectorRef<const Expression*> args);
/// Move constructor
CallExpression(CallExpression&&);
@@ -76,7 +80,7 @@ class CallExpression final : public Castable<CallExpression, Expression> {
const Target target;
/// The arguments
- const ExpressionList args;
+ const utils::Vector<const Expression*, 8> args;
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/call_expression_test.cc b/chromium/third_party/dawn/src/tint/ast/call_expression_test.cc
index 5cb31cb95cd..8b5b6a9e87f 100644
--- a/chromium/third_party/dawn/src/tint/ast/call_expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/call_expression_test.cc
@@ -22,23 +22,24 @@ using CallExpressionTest = TestHelper;
TEST_F(CallExpressionTest, CreationIdentifier) {
auto* func = Expr("func");
- ExpressionList params;
- params.push_back(Expr("param1"));
- params.push_back(Expr("param2"));
+ utils::Vector params{
+ Expr("param1"),
+ Expr("param2"),
+ };
auto* stmt = create<CallExpression>(func, params);
EXPECT_EQ(stmt->target.name, func);
EXPECT_EQ(stmt->target.type, nullptr);
const auto& vec = stmt->args;
- ASSERT_EQ(vec.size(), 2u);
+ ASSERT_EQ(vec.Length(), 2u);
EXPECT_EQ(vec[0], params[0]);
EXPECT_EQ(vec[1], params[1]);
}
TEST_F(CallExpressionTest, CreationIdentifier_WithSource) {
auto* func = Expr("func");
- auto* stmt = create<CallExpression>(Source{{20, 2}}, func, ExpressionList{});
+ auto* stmt = create<CallExpression>(Source{{20, 2}}, func, utils::Empty);
EXPECT_EQ(stmt->target.name, func);
EXPECT_EQ(stmt->target.type, nullptr);
@@ -49,23 +50,24 @@ TEST_F(CallExpressionTest, CreationIdentifier_WithSource) {
TEST_F(CallExpressionTest, CreationType) {
auto* type = ty.f32();
- ExpressionList params;
- params.push_back(Expr("param1"));
- params.push_back(Expr("param2"));
+ utils::Vector params{
+ Expr("param1"),
+ Expr("param2"),
+ };
auto* stmt = create<CallExpression>(type, params);
EXPECT_EQ(stmt->target.name, nullptr);
EXPECT_EQ(stmt->target.type, type);
const auto& vec = stmt->args;
- ASSERT_EQ(vec.size(), 2u);
+ ASSERT_EQ(vec.Length(), 2u);
EXPECT_EQ(vec[0], params[0]);
EXPECT_EQ(vec[1], params[1]);
}
TEST_F(CallExpressionTest, CreationType_WithSource) {
auto* type = ty.f32();
- auto* stmt = create<CallExpression>(Source{{20, 2}}, type, ExpressionList{});
+ auto* stmt = create<CallExpression>(Source{{20, 2}}, type, utils::Empty);
EXPECT_EQ(stmt->target.name, nullptr);
EXPECT_EQ(stmt->target.type, type);
@@ -76,7 +78,7 @@ TEST_F(CallExpressionTest, CreationType_WithSource) {
TEST_F(CallExpressionTest, IsCall) {
auto* func = Expr("func");
- auto* stmt = create<CallExpression>(func, ExpressionList{});
+ auto* stmt = create<CallExpression>(func, utils::Empty);
EXPECT_TRUE(stmt->Is<CallExpression>());
}
@@ -84,7 +86,7 @@ TEST_F(CallExpressionTest, Assert_Null_Identifier) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<CallExpression>(static_cast<IdentifierExpression*>(nullptr), ExpressionList{});
+ b.create<CallExpression>(static_cast<IdentifierExpression*>(nullptr), utils::Empty);
},
"internal compiler error");
}
@@ -93,7 +95,7 @@ TEST_F(CallExpressionTest, Assert_Null_Type) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<CallExpression>(static_cast<Type*>(nullptr), ExpressionList{});
+ b.create<CallExpression>(static_cast<Type*>(nullptr), utils::Empty);
},
"internal compiler error");
}
@@ -102,11 +104,11 @@ TEST_F(CallExpressionTest, Assert_Null_Param) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- ExpressionList params;
- params.push_back(b.Expr("param1"));
- params.push_back(nullptr);
- params.push_back(b.Expr("param2"));
- b.create<CallExpression>(b.Expr("func"), params);
+ b.create<CallExpression>(b.Expr("func"), utils::Vector{
+ b.Expr("param1"),
+ nullptr,
+ b.Expr("param2"),
+ });
},
"internal compiler error");
}
@@ -116,7 +118,7 @@ TEST_F(CallExpressionTest, Assert_DifferentProgramID_Identifier) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<CallExpression>(b2.Expr("func"), ExpressionList{});
+ b1.create<CallExpression>(b2.Expr("func"), utils::Empty);
},
"internal compiler error");
}
@@ -126,7 +128,7 @@ TEST_F(CallExpressionTest, Assert_DifferentProgramID_Type) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<CallExpression>(b2.ty.f32(), ExpressionList{});
+ b1.create<CallExpression>(b2.ty.f32(), utils::Empty);
},
"internal compiler error");
}
@@ -136,7 +138,7 @@ TEST_F(CallExpressionTest, Assert_DifferentProgramID_Param) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<CallExpression>(b1.Expr("func"), ExpressionList{b2.Expr("param1")});
+ b1.create<CallExpression>(b1.Expr("func"), utils::Vector{b2.Expr("param1")});
},
"internal compiler error");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/call_statement.cc b/chromium/third_party/dawn/src/tint/ast/call_statement.cc
index 5e98fc9f333..597e30fe3ae 100644
--- a/chromium/third_party/dawn/src/tint/ast/call_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/call_statement.cc
@@ -20,8 +20,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::CallStatement);
namespace tint::ast {
-CallStatement::CallStatement(ProgramID pid, const Source& src, const CallExpression* call)
- : Base(pid, src), expr(call) {
+CallStatement::CallStatement(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const CallExpression* call)
+ : Base(pid, nid, src), expr(call) {
TINT_ASSERT(AST, expr);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/call_statement.h b/chromium/third_party/dawn/src/tint/ast/call_statement.h
index d0d9f5301b8..daf0b3f1afd 100644
--- a/chromium/third_party/dawn/src/tint/ast/call_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/call_statement.h
@@ -25,9 +25,10 @@ class CallStatement final : public Castable<CallStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node for the statement
/// @param call the function
- CallStatement(ProgramID pid, const Source& src, const CallExpression* call);
+ CallStatement(ProgramID pid, NodeID nid, const Source& src, const CallExpression* call);
/// Move constructor
CallStatement(CallStatement&&);
~CallStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/call_statement_test.cc b/chromium/third_party/dawn/src/tint/ast/call_statement_test.cc
index 342659731f9..84d2b41fabc 100644
--- a/chromium/third_party/dawn/src/tint/ast/call_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/call_statement_test.cc
@@ -23,7 +23,7 @@ namespace {
using CallStatementTest = TestHelper;
TEST_F(CallStatementTest, Creation) {
- auto* expr = create<CallExpression>(Expr("func"), ExpressionList{});
+ auto* expr = create<CallExpression>(Expr("func"), utils::Empty);
auto* c = create<CallStatement>(expr);
EXPECT_EQ(c->expr, expr);
@@ -48,7 +48,7 @@ TEST_F(CallStatementTest, Assert_DifferentProgramID_Call) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<CallStatement>(b2.create<CallExpression>(b2.Expr("func"), ExpressionList{}));
+ b1.create<CallStatement>(b2.create<CallExpression>(b2.Expr("func"), utils::Empty));
},
"internal compiler error");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/case_statement.cc b/chromium/third_party/dawn/src/tint/ast/case_statement.cc
index bf1f0bf797b..9f1c20e8b7c 100644
--- a/chromium/third_party/dawn/src/tint/ast/case_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/case_statement.cc
@@ -14,6 +14,8 @@
#include "src/tint/ast/case_statement.h"
+#include <utility>
+
#include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::CaseStatement);
@@ -21,10 +23,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::CaseStatement);
namespace tint::ast {
CaseStatement::CaseStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
- CaseSelectorList s,
+ utils::VectorRef<const IntLiteralExpression*> s,
const BlockStatement* b)
- : Base(pid, src), selectors(s), body(b) {
+ : Base(pid, nid, src), selectors(std::move(s)), body(b) {
TINT_ASSERT(AST, body);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
for (auto* selector : selectors) {
@@ -42,7 +45,7 @@ const CaseStatement* CaseStatement::Clone(CloneContext* ctx) const {
auto src = ctx->Clone(source);
auto sel = ctx->Clone(selectors);
auto* b = ctx->Clone(body);
- return ctx->dst->create<CaseStatement>(src, sel, b);
+ return ctx->dst->create<CaseStatement>(src, std::move(sel), b);
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/case_statement.h b/chromium/third_party/dawn/src/tint/ast/case_statement.h
index 19ca69308f6..47d2097e528 100644
--- a/chromium/third_party/dawn/src/tint/ast/case_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/case_statement.h
@@ -22,27 +22,26 @@
namespace tint::ast {
-/// A list of case literals
-using CaseSelectorList = std::vector<const IntLiteralExpression*>;
-
/// A case statement
class CaseStatement final : public Castable<CaseStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param selectors the case selectors
/// @param body the case body
CaseStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
- CaseSelectorList selectors,
+ utils::VectorRef<const IntLiteralExpression*> selectors,
const BlockStatement* body);
/// Move constructor
CaseStatement(CaseStatement&&);
~CaseStatement() override;
/// @returns true if this is a default statement
- bool IsDefault() const { return selectors.empty(); }
+ bool IsDefault() const { return selectors.IsEmpty(); }
/// Clones this node and all transitive child nodes using the `CloneContext`
/// `ctx`.
@@ -51,15 +50,12 @@ class CaseStatement final : public Castable<CaseStatement, Statement> {
const CaseStatement* Clone(CloneContext* ctx) const override;
/// The case selectors, empty if none set
- const CaseSelectorList selectors;
+ const utils::Vector<const IntLiteralExpression*, 4> selectors;
/// The case body
const BlockStatement* const body;
};
-/// A list of case statements
-using CaseStatementList = std::vector<const CaseStatement*>;
-
} // namespace tint::ast
#endif // SRC_TINT_AST_CASE_STATEMENT_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/case_statement_test.cc b/chromium/third_party/dawn/src/tint/ast/case_statement_test.cc
index 12fcbda9261..dc3c88ad038 100644
--- a/chromium/third_party/dawn/src/tint/ast/case_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/case_statement_test.cc
@@ -27,40 +27,37 @@ namespace {
using CaseStatementTest = TestHelper;
TEST_F(CaseStatementTest, Creation_i32) {
- CaseSelectorList b;
auto* selector = Expr(2_i);
- b.push_back(selector);
+ utils::Vector b{selector};
auto* discard = create<DiscardStatement>();
- auto* body = create<BlockStatement>(StatementList{discard});
+ auto* body = create<BlockStatement>(utils::Vector{discard});
auto* c = create<CaseStatement>(b, body);
- ASSERT_EQ(c->selectors.size(), 1u);
+ ASSERT_EQ(c->selectors.Length(), 1u);
EXPECT_EQ(c->selectors[0], selector);
- ASSERT_EQ(c->body->statements.size(), 1u);
+ ASSERT_EQ(c->body->statements.Length(), 1u);
EXPECT_EQ(c->body->statements[0], discard);
}
TEST_F(CaseStatementTest, Creation_u32) {
- CaseSelectorList b;
auto* selector = Expr(2_u);
- b.push_back(selector);
+ utils::Vector b{selector};
auto* discard = create<DiscardStatement>();
- auto* body = create<BlockStatement>(StatementList{discard});
+ auto* body = create<BlockStatement>(utils::Vector{discard});
auto* c = create<CaseStatement>(b, body);
- ASSERT_EQ(c->selectors.size(), 1u);
+ ASSERT_EQ(c->selectors.Length(), 1u);
EXPECT_EQ(c->selectors[0], selector);
- ASSERT_EQ(c->body->statements.size(), 1u);
+ ASSERT_EQ(c->body->statements.Length(), 1u);
EXPECT_EQ(c->body->statements[0], discard);
}
TEST_F(CaseStatementTest, Creation_WithSource) {
- CaseSelectorList b;
- b.push_back(Expr(2_i));
+ utils::Vector b{Expr(2_i)};
- auto* body = create<BlockStatement>(StatementList{
+ auto* body = create<BlockStatement>(utils::Vector{
create<DiscardStatement>(),
});
auto* c = create<CaseStatement>(Source{Source::Location{20, 2}}, b, body);
@@ -70,23 +67,21 @@ TEST_F(CaseStatementTest, Creation_WithSource) {
}
TEST_F(CaseStatementTest, IsDefault_WithoutSelectors) {
- auto* body = create<BlockStatement>(StatementList{
+ auto* body = create<BlockStatement>(utils::Vector{
create<DiscardStatement>(),
});
- auto* c = create<CaseStatement>(CaseSelectorList{}, body);
+ auto* c = create<CaseStatement>(utils::Empty, body);
EXPECT_TRUE(c->IsDefault());
}
TEST_F(CaseStatementTest, IsDefault_WithSelectors) {
- CaseSelectorList b;
- b.push_back(Expr(2_i));
-
- auto* c = create<CaseStatement>(b, create<BlockStatement>(StatementList{}));
+ utils::Vector b{Expr(2_i)};
+ auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty));
EXPECT_FALSE(c->IsDefault());
}
TEST_F(CaseStatementTest, IsCase) {
- auto* c = create<CaseStatement>(CaseSelectorList{}, create<BlockStatement>(StatementList{}));
+ auto* c = create<CaseStatement>(utils::Empty, create<BlockStatement>(utils::Empty));
EXPECT_TRUE(c->Is<CaseStatement>());
}
@@ -94,7 +89,7 @@ TEST_F(CaseStatementTest, Assert_Null_Body) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<CaseStatement>(CaseSelectorList{}, nullptr);
+ b.create<CaseStatement>(utils::Empty, nullptr);
},
"internal compiler error");
}
@@ -103,8 +98,8 @@ TEST_F(CaseStatementTest, Assert_Null_Selector) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<CaseStatement>(CaseSelectorList{nullptr},
- b.create<BlockStatement>(StatementList{}));
+ b.create<CaseStatement>(utils::Vector<const ast::IntLiteralExpression*, 1>{nullptr},
+ b.create<BlockStatement>(utils::Empty));
},
"internal compiler error");
}
@@ -114,8 +109,7 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Call) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<CaseStatement>(CaseSelectorList{},
- b2.create<BlockStatement>(StatementList{}));
+ b1.create<CaseStatement>(utils::Empty, b2.create<BlockStatement>(utils::Empty));
},
"internal compiler error");
}
@@ -125,8 +119,8 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Selector) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<CaseStatement>(CaseSelectorList{b2.Expr(2_i)},
- b1.create<BlockStatement>(StatementList{}));
+ b1.create<CaseStatement>(utils::Vector{b2.Expr(2_i)},
+ b1.create<BlockStatement>(utils::Empty));
},
"internal compiler error");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.cc b/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.cc
index 848d5003917..f7528625f2c 100644
--- a/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.cc
@@ -21,11 +21,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::CompoundAssignmentStatement);
namespace tint::ast {
CompoundAssignmentStatement::CompoundAssignmentStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* l,
const Expression* r,
BinaryOp o)
- : Base(pid, src), lhs(l), rhs(r), op(o) {
+ : Base(pid, nid, src), lhs(l), rhs(r), op(o) {
TINT_ASSERT(AST, lhs);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
TINT_ASSERT(AST, rhs);
diff --git a/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.h b/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.h
index ba9a558a6b2..9fbd22c2b32 100644
--- a/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/compound_assignment_statement.h
@@ -25,12 +25,14 @@ namespace tint::ast {
class CompoundAssignmentStatement final : public Castable<CompoundAssignmentStatement, Statement> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the compound assignment statement source
/// @param lhs the left side of the expression
/// @param rhs the right side of the expression
/// @param op the binary operator
- CompoundAssignmentStatement(ProgramID program_id,
+ CompoundAssignmentStatement(ProgramID pid,
+ NodeID nid,
const Source& source,
const Expression* lhs,
const Expression* rhs,
diff --git a/chromium/third_party/dawn/src/tint/ast/const.cc b/chromium/third_party/dawn/src/tint/ast/const.cc
new file mode 100644
index 00000000000..fbc8469feef
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/const.cc
@@ -0,0 +1,53 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/const.h"
+
+#include <utility>
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::Const);
+
+namespace tint::ast {
+
+Const::Const(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Symbol& sym,
+ const ast::Type* ty,
+ const Expression* ctor,
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)) {
+ TINT_ASSERT(AST, ctor != nullptr);
+}
+
+Const::Const(Const&&) = default;
+
+Const::~Const() = default;
+
+const char* Const::Kind() const {
+ return "const";
+}
+
+const Const* Const::Clone(CloneContext* ctx) const {
+ auto src = ctx->Clone(source);
+ auto sym = ctx->Clone(symbol);
+ auto* ty = ctx->Clone(type);
+ auto* ctor = ctx->Clone(constructor);
+ auto attrs = ctx->Clone(attributes);
+ return ctx->dst->create<Const>(src, sym, ty, ctor, std::move(attrs));
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/const.h b/chromium/third_party/dawn/src/tint/ast/const.h
new file mode 100644
index 00000000000..c37458f352d
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/const.h
@@ -0,0 +1,69 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_CONST_H_
+#define SRC_TINT_AST_CONST_H_
+
+#include "src/tint/ast/variable.h"
+
+namespace tint::ast {
+
+/// A "const" declaration is a name for a module-scoped or function-scoped creation-time value.
+/// const must have a constructor expression.
+///
+/// Examples:
+///
+/// ```
+/// const n = 123; // Abstract-integer typed constant
+/// const pi = 3.14159265359; // Abstract-float typed constant
+/// const max_f32 : f32 = 0x1.fffffep+127; // f32 typed constant
+/// ```
+/// @see https://www.w3.org/TR/WGSL/#creation-time-consts
+class Const final : public Castable<Const, Variable> {
+ public:
+ /// Create a 'const' creation-time value variable.
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param source the variable source
+ /// @param sym the variable symbol
+ /// @param type the declared variable type
+ /// @param constructor the constructor expression. Must not be nullptr.
+ /// @param attributes the variable attributes
+ Const(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ const Symbol& sym,
+ const ast::Type* type,
+ const Expression* constructor,
+ utils::VectorRef<const Attribute*> attributes);
+
+ /// Move constructor
+ Const(Const&&);
+
+ /// Destructor
+ ~Const() override;
+
+ /// @returns "const"
+ const char* Kind() const override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext`
+ /// `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const Const* Clone(CloneContext* ctx) const override;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_CONST_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/continue_statement.cc b/chromium/third_party/dawn/src/tint/ast/continue_statement.cc
index 8ae4b9c1eee..53bd6a9a2f0 100644
--- a/chromium/third_party/dawn/src/tint/ast/continue_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/continue_statement.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::ContinueStatement);
namespace tint::ast {
-ContinueStatement::ContinueStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
+ContinueStatement::ContinueStatement(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src) {}
ContinueStatement::ContinueStatement(ContinueStatement&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/continue_statement.h b/chromium/third_party/dawn/src/tint/ast/continue_statement.h
index 17d8586d900..09b82543735 100644
--- a/chromium/third_party/dawn/src/tint/ast/continue_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/continue_statement.h
@@ -24,8 +24,9 @@ class ContinueStatement final : public Castable<ContinueStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- ContinueStatement(ProgramID pid, const Source& src);
+ ContinueStatement(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
ContinueStatement(ContinueStatement&&);
~ContinueStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.cc b/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.cc
index 66c5a86c525..64998b5170c 100644
--- a/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.cc
+++ b/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.cc
@@ -28,9 +28,10 @@ bool IsValidDepthDimension(TextureDimension dim) {
} // namespace
DepthMultisampledTexture::DepthMultisampledTexture(ProgramID pid,
+ NodeID nid,
const Source& src,
TextureDimension d)
- : Base(pid, src, d) {
+ : Base(pid, nid, src, d) {
TINT_ASSERT(AST, IsValidDepthDimension(dim));
}
diff --git a/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.h b/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.h
index d15ac7a7def..2cc8d78bd67 100644
--- a/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.h
+++ b/chromium/third_party/dawn/src/tint/ast/depth_multisampled_texture.h
@@ -26,9 +26,10 @@ class DepthMultisampledTexture final : public Castable<DepthMultisampledTexture,
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param dim the dimensionality of the texture
- DepthMultisampledTexture(ProgramID pid, const Source& src, TextureDimension dim);
+ DepthMultisampledTexture(ProgramID pid, NodeID nid, const Source& src, TextureDimension dim);
/// Move constructor
DepthMultisampledTexture(DepthMultisampledTexture&&);
~DepthMultisampledTexture() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/depth_texture.cc b/chromium/third_party/dawn/src/tint/ast/depth_texture.cc
index 6c0858ffbb8..4aae6f32a61 100644
--- a/chromium/third_party/dawn/src/tint/ast/depth_texture.cc
+++ b/chromium/third_party/dawn/src/tint/ast/depth_texture.cc
@@ -28,8 +28,8 @@ bool IsValidDepthDimension(TextureDimension dim) {
} // namespace
-DepthTexture::DepthTexture(ProgramID pid, const Source& src, TextureDimension d)
- : Base(pid, src, d) {
+DepthTexture::DepthTexture(ProgramID pid, NodeID nid, const Source& src, TextureDimension d)
+ : Base(pid, nid, src, d) {
TINT_ASSERT(AST, IsValidDepthDimension(dim));
}
diff --git a/chromium/third_party/dawn/src/tint/ast/depth_texture.h b/chromium/third_party/dawn/src/tint/ast/depth_texture.h
index 42349e32e12..7df34a2736c 100644
--- a/chromium/third_party/dawn/src/tint/ast/depth_texture.h
+++ b/chromium/third_party/dawn/src/tint/ast/depth_texture.h
@@ -26,9 +26,10 @@ class DepthTexture final : public Castable<DepthTexture, Texture> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param dim the dimensionality of the texture
- DepthTexture(ProgramID pid, const Source& src, TextureDimension dim);
+ DepthTexture(ProgramID pid, NodeID nid, const Source& src, TextureDimension dim);
/// Move constructor
DepthTexture(DepthTexture&&);
~DepthTexture() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.cc b/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.cc
index 4bc9f74c650..1f58799dd9d 100644
--- a/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.cc
@@ -20,8 +20,10 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::DisableValidationAttribute);
namespace tint::ast {
-DisableValidationAttribute::DisableValidationAttribute(ProgramID pid, DisabledValidation val)
- : Base(pid), validation(val) {}
+DisableValidationAttribute::DisableValidationAttribute(ProgramID pid,
+ NodeID nid,
+ DisabledValidation val)
+ : Base(pid, nid), validation(val) {}
DisableValidationAttribute::~DisableValidationAttribute() = default;
@@ -35,8 +37,8 @@ std::string DisableValidationAttribute::InternalName() const {
return "disable_validation__ignore_storage_class";
case DisabledValidation::kEntryPointParameter:
return "disable_validation__entry_point_parameter";
- case DisabledValidation::kIgnoreConstructibleFunctionParameter:
- return "disable_validation__ignore_constructible_function_parameter";
+ case DisabledValidation::kFunctionParameter:
+ return "disable_validation__function_parameter";
case DisabledValidation::kIgnoreStrideAttribute:
return "disable_validation__ignore_stride";
case DisabledValidation::kIgnoreInvalidPointerArgument:
@@ -46,7 +48,8 @@ std::string DisableValidationAttribute::InternalName() const {
}
const DisableValidationAttribute* DisableValidationAttribute::Clone(CloneContext* ctx) const {
- return ctx->dst->ASTNodes().Create<DisableValidationAttribute>(ctx->dst->ID(), validation);
+ return ctx->dst->ASTNodes().Create<DisableValidationAttribute>(
+ ctx->dst->ID(), ctx->dst->AllocateNodeID(), validation);
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.h b/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.h
index db70ad4c9ad..a109d18d4a5 100644
--- a/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/disable_validation_attribute.h
@@ -24,27 +24,23 @@ namespace tint::ast {
/// Enumerator of validation features that can be disabled with a
/// DisableValidationAttribute attribute.
enum class DisabledValidation {
- /// When applied to a function, the validator will not complain there is no
- /// body to a function.
+ /// When applied to a function, the validator will not complain there is no body to a function.
kFunctionHasNoBody,
- /// When applied to a module-scoped variable, the validator will not complain
- /// if two resource variables have the same binding points.
+ /// When applied to a module-scoped variable, the validator will not complain if two resource
+ /// variables have the same binding points.
kBindingPointCollision,
- /// When applied to a variable, the validator will not complain about the
- /// declared storage class.
+ /// When applied to a variable, the validator will not complain about the declared storage
+ /// class.
kIgnoreStorageClass,
- /// When applied to an entry-point function parameter, the validator will not
- /// check for entry IO attributes.
+ /// When applied to an entry-point function parameter, the validator will not check for entry IO
+ /// attributes.
kEntryPointParameter,
- /// When applied to a function parameter, the validator will not
- /// check if parameter type is constructible
- kIgnoreConstructibleFunctionParameter,
- /// When applied to a member attribute, a stride attribute may be applied to
- /// non-array types.
+ /// When applied to a function parameter, the parameter will not be validated.
+ kFunctionParameter,
+ /// When applied to a member attribute, a stride attribute may be applied to non-array types.
kIgnoreStrideAttribute,
- /// When applied to a pointer function parameter, the validator will not
- /// require a function call argument passed for that parameter to have a
- /// certain form.
+ /// When applied to a pointer function parameter, the validator will not require a function call
+ /// argument passed for that parameter to have a certain form.
kIgnoreInvalidPointerArgument,
};
@@ -55,9 +51,10 @@ class DisableValidationAttribute final
: public Castable<DisableValidationAttribute, InternalAttribute> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param validation the validation to disable
- explicit DisableValidationAttribute(ProgramID program_id, DisabledValidation validation);
+ explicit DisableValidationAttribute(ProgramID pid, NodeID nid, DisabledValidation validation);
/// Destructor
~DisableValidationAttribute() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/discard_statement.cc b/chromium/third_party/dawn/src/tint/ast/discard_statement.cc
index 7ca673f6298..fc9e75bbffc 100644
--- a/chromium/third_party/dawn/src/tint/ast/discard_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/discard_statement.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::DiscardStatement);
namespace tint::ast {
-DiscardStatement::DiscardStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
+DiscardStatement::DiscardStatement(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src) {}
DiscardStatement::DiscardStatement(DiscardStatement&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/discard_statement.h b/chromium/third_party/dawn/src/tint/ast/discard_statement.h
index 9d18c744545..272cc2dbf25 100644
--- a/chromium/third_party/dawn/src/tint/ast/discard_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/discard_statement.h
@@ -24,8 +24,9 @@ class DiscardStatement final : public Castable<DiscardStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- DiscardStatement(ProgramID pid, const Source& src);
+ DiscardStatement(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
DiscardStatement(DiscardStatement&&);
~DiscardStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/enable.cc b/chromium/third_party/dawn/src/tint/ast/enable.cc
index ef43200c052..9da44c7520b 100644
--- a/chromium/third_party/dawn/src/tint/ast/enable.cc
+++ b/chromium/third_party/dawn/src/tint/ast/enable.cc
@@ -21,7 +21,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Enable);
namespace tint::ast {
-Enable::Enable(ProgramID pid, const Source& src, Extension ext) : Base(pid, src), extension(ext) {}
+Enable::Enable(ProgramID pid, NodeID nid, const Source& src, Extension ext)
+ : Base(pid, nid, src), extension(ext) {}
Enable::Enable(Enable&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/enable.h b/chromium/third_party/dawn/src/tint/ast/enable.h
index 674d9cb42f7..4c27113c0dd 100644
--- a/chromium/third_party/dawn/src/tint/ast/enable.h
+++ b/chromium/third_party/dawn/src/tint/ast/enable.h
@@ -33,9 +33,10 @@ class Enable final : public Castable<Enable, Node> {
public:
/// Create a extension
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param ext the extension
- Enable(ProgramID pid, const Source& src, Extension ext);
+ Enable(ProgramID pid, NodeID nid, const Source& src, Extension ext);
/// Move constructor
Enable(Enable&&);
@@ -51,9 +52,6 @@ class Enable final : public Castable<Enable, Node> {
const Extension extension;
};
-/// A list of enables
-using EnableList = std::vector<const Enable*>;
-
} // namespace tint::ast
#endif // SRC_TINT_AST_ENABLE_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/expression.cc b/chromium/third_party/dawn/src/tint/ast/expression.cc
index a7f23aace4c..17b3dc2b114 100644
--- a/chromium/third_party/dawn/src/tint/ast/expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/expression.cc
@@ -21,7 +21,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Expression);
namespace tint::ast {
-Expression::Expression(ProgramID pid, const Source& src) : Base(pid, src) {}
+Expression::Expression(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
Expression::Expression(Expression&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/expression.h b/chromium/third_party/dawn/src/tint/ast/expression.h
index dc69ff8e4e6..8e0718b0f19 100644
--- a/chromium/third_party/dawn/src/tint/ast/expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/expression.h
@@ -31,15 +31,13 @@ class Expression : public Castable<Expression, Node> {
protected:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- Expression(ProgramID pid, const Source& src);
+ Expression(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
Expression(Expression&&);
};
-/// A list of expressions
-using ExpressionList = std::vector<const Expression*>;
-
} // namespace tint::ast
#endif // SRC_TINT_AST_EXPRESSION_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/extension.cc b/chromium/third_party/dawn/src/tint/ast/extension.cc
index f03e3a02985..e57b2487730 100644
--- a/chromium/third_party/dawn/src/tint/ast/extension.cc
+++ b/chromium/third_party/dawn/src/tint/ast/extension.cc
@@ -12,40 +12,51 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/extension.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
#include "src/tint/ast/extension.h"
namespace tint::ast {
-Extension ParseExtension(const std::string& name) {
- if (name == "chromium_experimental_dp4a") {
- return Extension::kChromiumExperimentalDP4a;
+/// ParseExtension parses a Extension from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or Extension::kInvalid if the string could not be parsed.
+Extension ParseExtension(std::string_view str) {
+ if (str == "f16") {
+ return Extension::kF16;
}
- if (name == "chromium_disable_uniformity_analysis") {
+ if (str == "chromium_experimental_dp4a") {
+ return Extension::kChromiumExperimentalDp4A;
+ }
+ if (str == "chromium_disable_uniformity_analysis") {
return Extension::kChromiumDisableUniformityAnalysis;
}
- if (name == "f16") {
- return Extension::kF16;
+ if (str == "chromium_experimental_push_constant") {
+ return Extension::kChromiumExperimentalPushConstant;
}
- return Extension::kNone;
+ return Extension::kInvalid;
}
-const char* str(Extension ext) {
- switch (ext) {
- case Extension::kChromiumExperimentalDP4a:
- return "chromium_experimental_dp4a";
- case Extension::kChromiumDisableUniformityAnalysis:
- return "chromium_disable_uniformity_analysis";
+std::ostream& operator<<(std::ostream& out, Extension value) {
+ switch (value) {
+ case Extension::kInvalid:
+ return out << "invalid";
case Extension::kF16:
- return "f16";
- case Extension::kNone:
- return "<none>";
+ return out << "f16";
+ case Extension::kChromiumExperimentalDp4A:
+ return out << "chromium_experimental_dp4a";
+ case Extension::kChromiumDisableUniformityAnalysis:
+ return out << "chromium_disable_uniformity_analysis";
+ case Extension::kChromiumExperimentalPushConstant:
+ return out << "chromium_experimental_push_constant";
}
- return "<unknown>";
-}
-
-std::ostream& operator<<(std::ostream& out, Extension i) {
- out << str(i);
- return out;
+ return out << "<unknown>";
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/extension.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/extension.cc.tmpl
new file mode 100644
index 00000000000..e0f319ec7a2
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/extension.cc.tmpl
@@ -0,0 +1,22 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#include "src/tint/ast/extension.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/extension.h b/chromium/third_party/dawn/src/tint/ast/extension.h
index 21e9ac15b38..eea9becb724 100644
--- a/chromium/third_party/dawn/src/tint/ast/extension.h
+++ b/chromium/third_party/dawn/src/tint/ast/extension.h
@@ -12,56 +12,45 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/extension.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
#ifndef SRC_TINT_AST_EXTENSION_H_
#define SRC_TINT_AST_EXTENSION_H_
-#include <sstream>
-#include <string>
+#include <ostream>
#include "src/tint/utils/unique_vector.h"
namespace tint::ast {
/// An enumerator of WGSL extensions
+/// @see src/tint/intrinsics.def for extension descriptions
enum class Extension {
- /// WGSL Extension "f16"
+ kInvalid,
kF16,
-
- /// An extension for the experimental feature
- /// "chromium_experimental_dp4a".
- /// See crbug.com/tint/1497 for more details
- kChromiumExperimentalDP4a,
- /// A Chromium-specific extension for disabling uniformity analysis.
+ kChromiumExperimentalDp4A,
kChromiumDisableUniformityAnalysis,
-
- /// Reserved for representing "No extension required" or "Not a valid extension".
- kNone,
+ kChromiumExperimentalPushConstant,
};
-/// Convert a string of extension name into one of Extension enum value, the result will be
-/// Extension::kNone if the name is not a known extension name. A extension node of kind
-/// kNone must not exist in the AST tree, and using a unknown extension name in WGSL code
-/// should result in a shader-creation error.
-/// @param name string of the extension name
-/// @return the Extension enum value for the extension of given name, or kNone if no known extension
-/// has the given name
-Extension ParseExtension(const std::string& name);
-
-/// Convert the Extension enum value to corresponding extension name string.
-/// @param ext the Extension enum value
-/// @return string of the extension name corresponding to the given kind, or
-/// an empty string if the given enum value is kNone or don't have a
-/// known corresponding name
-const char* ExtensionName(Extension ext);
-
-/// @returns the name of the extension.
-const char* str(Extension i);
+/// @param out the std::ostream to write to
+/// @param value the Extension
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, Extension value);
-/// Emits the name of the extension type.
-std::ostream& operator<<(std::ostream& out, Extension i);
+/// ParseExtension parses a Extension from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or Extension::kInvalid if the string could not be parsed.
+Extension ParseExtension(std::string_view str);
// A unique vector of extensions
-using Extensions = utils::UniqueVector<Extension>;
+using Extensions = utils::UniqueVector<Extension, 4>;
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/extension.h.tmpl b/chromium/third_party/dawn/src/tint/ast/extension.h.tmpl
new file mode 100644
index 00000000000..29feff962ad
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/extension.h.tmpl
@@ -0,0 +1,32 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#ifndef SRC_TINT_AST_EXTENSION_H_
+#define SRC_TINT_AST_EXTENSION_H_
+
+#include <ostream>
+
+#include "src/tint/utils/unique_vector.h"
+
+namespace tint::ast {
+
+/// An enumerator of WGSL extensions
+/// @see src/tint/intrinsics.def for extension descriptions
+{{ Eval "DeclareEnum" $enum}}
+
+// A unique vector of extensions
+using Extensions = utils::UniqueVector<Extension, 4>;
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_EXTENSION_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/extension_bench.cc b/chromium/third_party/dawn/src/tint/ast/extension_bench.cc
new file mode 100644
index 00000000000..8fc9d1cbbdf
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/extension_bench.cc
@@ -0,0 +1,74 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/extension_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/extension.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void ExtensionParser(::benchmark::State& state) {
+ std::array kStrings{
+ "cc6",
+ "s",
+ "HH6",
+ "f16",
+ "116",
+ "qJ6",
+ "f17ll",
+ "chromippHm_experqqmetal_dp4a",
+ "chrmium_expecimntal_dp4",
+ "chrmiumGexpebimental_dp4a",
+ "chromium_experimental_dp4a",
+ "chromium_exverimentiil_dp4a",
+ "chro8ium_experimenWWal_dp4a",
+ "chromiMm_eperimxxntal_dp4a",
+ "chXggmium_disable_uniformity_aalysis",
+ "Xhomiuu_disale_uniformity_analysis",
+ "chromium_3isable_uniformity_analysis",
+ "chromium_disable_uniformity_analysis",
+ "chromiuE_disable_uniformity_analysis",
+ "chromium_disable_uniTTormity_aPPalsis",
+ "ddhromium_disabexxuniformity_analysis",
+ "c44romium_experimental_push_constant",
+ "chromium_experimental_pSSsVV_constant",
+ "chrom22Rm_experimental_pushRonstant",
+ "chromium_experimental_push_constant",
+ "chromium_exp9rimFntal_ush_constant",
+ "chrmium_experimental_push_constant",
+ "cOOromium_experiVeHtal_puh_conRRtant",
+ };
+ for (auto _ : state) {
+ for (auto& str : kStrings) {
+ auto result = ParseExtension(str);
+ benchmark::DoNotOptimize(result);
+ }
+ }
+}
+
+BENCHMARK(ExtensionParser);
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/extension_bench.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/extension_bench.cc.tmpl
new file mode 100644
index 00000000000..af3dc9595a6
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/extension_bench.cc.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension_bench.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#include "src/tint/ast/extension.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/extension_test.cc b/chromium/third_party/dawn/src/tint/ast/extension_test.cc
index ed27674b9e0..283088db466 100644
--- a/chromium/third_party/dawn/src/tint/ast/extension_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/extension_test.cc
@@ -1,4 +1,3 @@
-
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,24 +12,79 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/extension_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
#include "src/tint/ast/extension.h"
-#include "gtest/gtest.h"
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
namespace tint::ast {
namespace {
-TEST(ExtensionTest, NameToKind_InvalidName) {
- EXPECT_EQ(ParseExtension("f16"), Extension::kF16);
- EXPECT_EQ(ParseExtension(""), Extension::kNone);
- EXPECT_EQ(ParseExtension("__ImpossibleExtensionName"), Extension::kNone);
- EXPECT_EQ(ParseExtension("123"), Extension::kNone);
+namespace parse_print_tests {
+
+struct Case {
+ const char* string;
+ Extension value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+ return out << "'" << std::string(c.string) << "'";
}
-TEST(ExtensionTest, KindToName) {
- EXPECT_EQ(std::string(str(Extension::kF16)), "f16");
- EXPECT_EQ(std::string(str(Extension::kNone)), "<none>");
+static constexpr Case kValidCases[] = {
+ {"f16", Extension::kF16},
+ {"chromium_experimental_dp4a", Extension::kChromiumExperimentalDp4A},
+ {"chromium_disable_uniformity_analysis", Extension::kChromiumDisableUniformityAnalysis},
+ {"chromium_experimental_push_constant", Extension::kChromiumExperimentalPushConstant},
+};
+
+static constexpr Case kInvalidCases[] = {
+ {"cc6", Extension::kInvalid},
+ {"s", Extension::kInvalid},
+ {"HH6", Extension::kInvalid},
+ {"chro1ium_experimental_dp4a", Extension::kInvalid},
+ {"chrJmium_experiqqetal_dp4a", Extension::kInvalid},
+ {"chromium_experimenll77l_dp4a", Extension::kInvalid},
+ {"chromiumppdisableqquniformity_aalysHHs", Extension::kInvalid},
+ {"chromiu_disable_unifovmitc_analyi", Extension::kInvalid},
+ {"chromium_diable_uGbformity_analysis", Extension::kInvalid},
+ {"chvomium_experimental_push_constiint", Extension::kInvalid},
+ {"chromiu8WWexperimental_push_constant", Extension::kInvalid},
+ {"chromium_experiMental_push_costanxx", Extension::kInvalid},
+};
+
+using ExtensionParseTest = testing::TestWithParam<Case>;
+
+TEST_P(ExtensionParseTest, Parse) {
+ const char* string = GetParam().string;
+ Extension expect = GetParam().value;
+ EXPECT_EQ(expect, ParseExtension(string));
}
+INSTANTIATE_TEST_SUITE_P(ValidCases, ExtensionParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, ExtensionParseTest, testing::ValuesIn(kInvalidCases));
+
+using ExtensionPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(ExtensionPrintTest, Print) {
+ Extension value = GetParam().value;
+ const char* expect = GetParam().string;
+ EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, ExtensionPrintTest, testing::ValuesIn(kValidCases));
+
+} // namespace parse_print_tests
+
} // namespace
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/extension_test.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/extension_test.cc.tmpl
new file mode 100644
index 00000000000..8c7a6af3394
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/extension_test.cc.tmpl
@@ -0,0 +1,27 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#include "src/tint/ast/extension.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/external_texture.cc b/chromium/third_party/dawn/src/tint/ast/external_texture.cc
index b88de9055ae..488191389d8 100644
--- a/chromium/third_party/dawn/src/tint/ast/external_texture.cc
+++ b/chromium/third_party/dawn/src/tint/ast/external_texture.cc
@@ -21,8 +21,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::ExternalTexture);
namespace tint::ast {
// ExternalTexture::ExternalTexture() : Base(ast::TextureDimension::k2d) {}
-ExternalTexture::ExternalTexture(ProgramID pid, const Source& src)
- : Base(pid, src, ast::TextureDimension::k2d) {}
+ExternalTexture::ExternalTexture(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src, ast::TextureDimension::k2d) {}
ExternalTexture::ExternalTexture(ExternalTexture&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/external_texture.h b/chromium/third_party/dawn/src/tint/ast/external_texture.h
index 17224cffcfc..f2d68b42b40 100644
--- a/chromium/third_party/dawn/src/tint/ast/external_texture.h
+++ b/chromium/third_party/dawn/src/tint/ast/external_texture.h
@@ -26,8 +26,9 @@ class ExternalTexture final : public Castable<ExternalTexture, Texture> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- ExternalTexture(ProgramID pid, const Source& src);
+ ExternalTexture(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
ExternalTexture(ExternalTexture&&);
diff --git a/chromium/third_party/dawn/src/tint/ast/f16.cc b/chromium/third_party/dawn/src/tint/ast/f16.cc
index 0eb1be5fdd4..dd3e48e67ab 100644
--- a/chromium/third_party/dawn/src/tint/ast/f16.cc
+++ b/chromium/third_party/dawn/src/tint/ast/f16.cc
@@ -20,7 +20,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::F16);
namespace tint::ast {
-F16::F16(ProgramID pid, const Source& src) : Base(pid, src) {}
+F16::F16(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
F16::F16(F16&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/f16.h b/chromium/third_party/dawn/src/tint/ast/f16.h
index 1b84f09529e..bae62913561 100644
--- a/chromium/third_party/dawn/src/tint/ast/f16.h
+++ b/chromium/third_party/dawn/src/tint/ast/f16.h
@@ -22,12 +22,13 @@
namespace tint::ast {
/// A float 16 type
-class F16 : public Castable<F16, Type> {
+class F16 final : public Castable<F16, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- F16(ProgramID pid, const Source& src);
+ F16(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
F16(F16&&);
~F16() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/f32.cc b/chromium/third_party/dawn/src/tint/ast/f32.cc
index b731e65c9df..0ae354ad00d 100644
--- a/chromium/third_party/dawn/src/tint/ast/f32.cc
+++ b/chromium/third_party/dawn/src/tint/ast/f32.cc
@@ -20,7 +20,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::F32);
namespace tint::ast {
-F32::F32(ProgramID pid, const Source& src) : Base(pid, src) {}
+F32::F32(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
F32::F32(F32&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/f32.h b/chromium/third_party/dawn/src/tint/ast/f32.h
index db81491d815..5176c45e3de 100644
--- a/chromium/third_party/dawn/src/tint/ast/f32.h
+++ b/chromium/third_party/dawn/src/tint/ast/f32.h
@@ -26,8 +26,9 @@ class F32 final : public Castable<F32, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- F32(ProgramID pid, const Source& src);
+ F32(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
F32(F32&&);
~F32() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.cc b/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.cc
index 446534d354f..0d30ae3ec2e 100644
--- a/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::FallthroughStatement);
namespace tint::ast {
-FallthroughStatement::FallthroughStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
+FallthroughStatement::FallthroughStatement(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src) {}
FallthroughStatement::FallthroughStatement(FallthroughStatement&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.h b/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.h
index b313efbd6dd..da2fd3d88ba 100644
--- a/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/fallthrough_statement.h
@@ -24,8 +24,9 @@ class FallthroughStatement final : public Castable<FallthroughStatement, Stateme
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- FallthroughStatement(ProgramID pid, const Source& src);
+ FallthroughStatement(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
FallthroughStatement(FallthroughStatement&&);
~FallthroughStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/float_literal_expression.cc b/chromium/third_party/dawn/src/tint/ast/float_literal_expression.cc
index 36cb42a609e..524b56efefc 100644
--- a/chromium/third_party/dawn/src/tint/ast/float_literal_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/float_literal_expression.cc
@@ -23,10 +23,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::FloatLiteralExpression);
namespace tint::ast {
FloatLiteralExpression::FloatLiteralExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
double val,
Suffix suf)
- : Base(pid, src), value(val), suffix(suf) {}
+ : Base(pid, nid, src), value(val), suffix(suf) {}
FloatLiteralExpression::~FloatLiteralExpression() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/float_literal_expression.h b/chromium/third_party/dawn/src/tint/ast/float_literal_expression.h
index 7f03caf692c..7f3cd1289f7 100644
--- a/chromium/third_party/dawn/src/tint/ast/float_literal_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/float_literal_expression.h
@@ -36,10 +36,11 @@ class FloatLiteralExpression final : public Castable<FloatLiteralExpression, Lit
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param val the literal value
/// @param suf the literal suffix
- FloatLiteralExpression(ProgramID pid, const Source& src, double val, Suffix suf);
+ FloatLiteralExpression(ProgramID pid, NodeID nid, const Source& src, double val, Suffix suf);
~FloatLiteralExpression() override;
/// Clones this node and all transitive child nodes using the `CloneContext`
diff --git a/chromium/third_party/dawn/src/tint/ast/for_loop_statement.cc b/chromium/third_party/dawn/src/tint/ast/for_loop_statement.cc
index 804389c8c50..aba956d695b 100644
--- a/chromium/third_party/dawn/src/tint/ast/for_loop_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/for_loop_statement.cc
@@ -21,12 +21,13 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::ForLoopStatement);
namespace tint::ast {
ForLoopStatement::ForLoopStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Statement* init,
const Expression* cond,
const Statement* cont,
const BlockStatement* b)
- : Base(pid, src), initializer(init), condition(cond), continuing(cont), body(b) {
+ : Base(pid, nid, src), initializer(init), condition(cond), continuing(cont), body(b) {
TINT_ASSERT(AST, body);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, initializer, program_id);
diff --git a/chromium/third_party/dawn/src/tint/ast/for_loop_statement.h b/chromium/third_party/dawn/src/tint/ast/for_loop_statement.h
index 464ea499e8f..59e05878426 100644
--- a/chromium/third_party/dawn/src/tint/ast/for_loop_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/for_loop_statement.h
@@ -25,14 +25,16 @@ class Expression;
class ForLoopStatement final : public Castable<ForLoopStatement, Statement> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the for loop statement source
/// @param initializer the optional loop initializer statement
/// @param condition the optional loop condition expression
/// @param continuing the optional continuing statement
/// @param body the loop body
- ForLoopStatement(ProgramID program_id,
- Source const& source,
+ ForLoopStatement(ProgramID pid,
+ NodeID nid,
+ const Source& source,
const Statement* initializer,
const Expression* condition,
const Statement* continuing,
diff --git a/chromium/third_party/dawn/src/tint/ast/function.cc b/chromium/third_party/dawn/src/tint/ast/function.cc
index d8485d6cc9b..1cb03396dfd 100644
--- a/chromium/third_party/dawn/src/tint/ast/function.cc
+++ b/chromium/third_party/dawn/src/tint/ast/function.cc
@@ -23,14 +23,15 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Function);
namespace tint::ast {
Function::Function(ProgramID pid,
+ NodeID nid,
const Source& src,
Symbol sym,
- VariableList parameters,
+ utils::VectorRef<const Parameter*> parameters,
const Type* return_ty,
const BlockStatement* b,
- AttributeList attrs,
- AttributeList return_type_attrs)
- : Base(pid, src),
+ utils::VectorRef<const Attribute*> attrs,
+ utils::VectorRef<const Attribute*> return_type_attrs)
+ : Base(pid, nid, src),
symbol(sym),
params(std::move(parameters)),
return_type(return_ty),
@@ -40,7 +41,7 @@ Function::Function(ProgramID pid,
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
for (auto* param : params) {
- TINT_ASSERT(AST, param && param->is_const);
+ TINT_ASSERT(AST, tint::Is<Parameter>(param));
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, param, program_id);
}
TINT_ASSERT(AST, symbol.IsValid());
diff --git a/chromium/third_party/dawn/src/tint/ast/function.h b/chromium/third_party/dawn/src/tint/ast/function.h
index 843877efde3..61771bb4fbc 100644
--- a/chromium/third_party/dawn/src/tint/ast/function.h
+++ b/chromium/third_party/dawn/src/tint/ast/function.h
@@ -26,8 +26,8 @@
#include "src/tint/ast/builtin_attribute.h"
#include "src/tint/ast/group_attribute.h"
#include "src/tint/ast/location_attribute.h"
+#include "src/tint/ast/parameter.h"
#include "src/tint/ast/pipeline_stage.h"
-#include "src/tint/ast/variable.h"
namespace tint::ast {
@@ -35,7 +35,8 @@ namespace tint::ast {
class Function final : public Castable<Function, Node> {
public:
/// Create a function
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the variable source
/// @param symbol the function symbol
/// @param params the function parameters
@@ -43,14 +44,15 @@ class Function final : public Castable<Function, Node> {
/// @param body the function body
/// @param attributes the function attributes
/// @param return_type_attributes the return type attributes
- Function(ProgramID program_id,
+ Function(ProgramID pid,
+ NodeID nid,
const Source& source,
Symbol symbol,
- VariableList params,
+ utils::VectorRef<const Parameter*> params,
const Type* return_type,
const BlockStatement* body,
- AttributeList attributes,
- AttributeList return_type_attributes);
+ utils::VectorRef<const Attribute*> attributes,
+ utils::VectorRef<const Attribute*> return_type_attributes);
/// Move constructor
Function(Function&&);
@@ -72,7 +74,7 @@ class Function final : public Castable<Function, Node> {
const Symbol symbol;
/// The function params
- const VariableList params;
+ const utils::Vector<const Parameter*, 8> params;
/// The function return type
const Type* const return_type;
@@ -81,18 +83,18 @@ class Function final : public Castable<Function, Node> {
const BlockStatement* const body;
/// The attributes attached to this function
- const AttributeList attributes;
+ const utils::Vector<const Attribute*, 2> attributes;
/// The attributes attached to the function return type.
- const AttributeList return_type_attributes;
+ const utils::Vector<const Attribute*, 2> return_type_attributes;
};
/// A list of functions
-class FunctionList : public std::vector<const Function*> {
+class FunctionList : public utils::Vector<const Function*, 8> {
public:
/// Appends f to the end of the list
/// @param f the function to append to this list
- void Add(const Function* f) { this->emplace_back(f); }
+ void Add(const Function* f) { this->Push(f); }
/// Returns the function with the given name
/// @param sym the function symbol to search for
diff --git a/chromium/third_party/dawn/src/tint/ast/function_test.cc b/chromium/third_party/dawn/src/tint/ast/function_test.cc
index bd05fd827db..b95af2674aa 100644
--- a/chromium/third_party/dawn/src/tint/ast/function_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/function_test.cc
@@ -26,23 +26,20 @@ namespace {
using FunctionTest = TestHelper;
TEST_F(FunctionTest, Creation) {
- VariableList params;
- params.push_back(Param("var", ty.i32()));
+ utils::Vector params{Param("var", ty.i32())};
auto* var = params[0];
- auto* f = Func("func", params, ty.void_(), StatementList{}, AttributeList{});
+ auto* f = Func("func", params, ty.void_(), utils::Empty);
EXPECT_EQ(f->symbol, Symbols().Get("func"));
- ASSERT_EQ(f->params.size(), 1u);
+ ASSERT_EQ(f->params.Length(), 1u);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->params[0], var);
}
TEST_F(FunctionTest, Creation_WithSource) {
- VariableList params;
- params.push_back(Param("var", ty.i32()));
+ utils::Vector params{Param("var", ty.i32())};
- auto* f = Func(Source{Source::Location{20, 2}}, "func", params, ty.void_(), StatementList{},
- AttributeList{});
+ auto* f = Func(Source{Source::Location{20, 2}}, "func", params, ty.void_(), utils::Empty);
auto src = f->source;
EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u);
@@ -52,7 +49,7 @@ TEST_F(FunctionTest, Assert_InvalidName) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.Func("", VariableList{}, b.ty.void_(), StatementList{}, AttributeList{});
+ b.Func("", utils::Empty, b.ty.void_(), utils::Empty);
},
"internal compiler error");
}
@@ -61,20 +58,20 @@ TEST_F(FunctionTest, Assert_Null_ReturnType) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.Func("f", VariableList{}, nullptr, StatementList{}, AttributeList{});
+ b.Func("f", utils::Empty, nullptr, utils::Empty);
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_Null_Param) {
+ using ParamList = utils::Vector<const ast::Parameter*, 2>;
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- VariableList params;
- params.push_back(b.Param("var", b.ty.i32()));
- params.push_back(nullptr);
-
- b.Func("f", params, b.ty.void_(), StatementList{}, AttributeList{});
+ ParamList params;
+ params.Push(b.Param("var", b.ty.i32()));
+ params.Push(nullptr);
+ b.Func("f", params, b.ty.void_(), utils::Empty);
},
"internal compiler error");
}
@@ -84,7 +81,7 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Symbol) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.Func(b2.Sym("func"), VariableList{}, b1.ty.void_(), StatementList{});
+ b1.Func(b2.Sym("func"), utils::Empty, b1.ty.void_(), utils::Empty);
},
"internal compiler error");
}
@@ -94,8 +91,11 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Param) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.Func("func", VariableList{b2.Param("var", b2.ty.i32())}, b1.ty.void_(),
- StatementList{});
+ b1.Func("func",
+ utils::Vector{
+ b2.Param("var", b2.ty.i32()),
+ },
+ b1.ty.void_(), utils::Empty);
},
"internal compiler error");
}
@@ -105,8 +105,8 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Attr) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{},
- AttributeList{
+ b1.Func("func", utils::Empty, b1.ty.void_(), utils::Empty,
+ utils::Vector{
b2.WorkgroupSize(2_i, 4_i, 6_i),
});
},
@@ -118,30 +118,18 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnAttr) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{}, AttributeList{},
- AttributeList{
+ b1.Func("func", utils::Empty, b1.ty.void_(), utils::Empty, utils::Empty,
+ utils::Vector{
b2.WorkgroupSize(2_i, 4_i, 6_i),
});
},
"internal compiler error");
}
-TEST_F(FunctionTest, Assert_NonConstParam) {
- EXPECT_FATAL_FAILURE(
- {
- ProgramBuilder b;
- VariableList params;
- params.push_back(b.Var("var", b.ty.i32(), ast::StorageClass::kNone));
-
- b.Func("f", params, b.ty.void_(), StatementList{}, AttributeList{});
- },
- "internal compiler error");
-}
-
using FunctionListTest = TestHelper;
TEST_F(FunctionListTest, FindSymbol) {
- auto* func = Func("main", VariableList{}, ty.f32(), StatementList{}, ast::AttributeList{});
+ auto* func = Func("main", utils::Empty, ty.f32(), utils::Empty);
FunctionList list;
list.Add(func);
EXPECT_EQ(func, list.Find(Symbols().Register("main")));
@@ -153,12 +141,12 @@ TEST_F(FunctionListTest, FindSymbolMissing) {
}
TEST_F(FunctionListTest, FindSymbolStage) {
- auto* fs = Func("main", VariableList{}, ty.f32(), StatementList{},
- ast::AttributeList{
+ auto* fs = Func("main", utils::Empty, ty.f32(), utils::Empty,
+ utils::Vector{
Stage(PipelineStage::kFragment),
});
- auto* vs = Func("main", VariableList{}, ty.f32(), StatementList{},
- ast::AttributeList{
+ auto* vs = Func("main", utils::Empty, ty.f32(), utils::Empty,
+ utils::Vector{
Stage(PipelineStage::kVertex),
});
FunctionList list;
@@ -170,8 +158,8 @@ TEST_F(FunctionListTest, FindSymbolStage) {
TEST_F(FunctionListTest, FindSymbolStageMissing) {
FunctionList list;
- list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
- ast::AttributeList{
+ list.Add(Func("main", utils::Empty, ty.f32(), utils::Empty,
+ utils::Vector{
Stage(PipelineStage::kFragment),
}));
EXPECT_EQ(nullptr, list.Find(Symbols().Register("main"), PipelineStage::kVertex));
@@ -179,8 +167,8 @@ TEST_F(FunctionListTest, FindSymbolStageMissing) {
TEST_F(FunctionListTest, HasStage) {
FunctionList list;
- list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
- ast::AttributeList{
+ list.Add(Func("main", utils::Empty, ty.f32(), utils::Empty,
+ utils::Vector{
Stage(PipelineStage::kFragment),
}));
EXPECT_TRUE(list.HasStage(PipelineStage::kFragment));
diff --git a/chromium/third_party/dawn/src/tint/ast/group_attribute.cc b/chromium/third_party/dawn/src/tint/ast/group_attribute.cc
index 394a6907718..9d011114ca2 100644
--- a/chromium/third_party/dawn/src/tint/ast/group_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/group_attribute.cc
@@ -22,8 +22,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::GroupAttribute);
namespace tint::ast {
-GroupAttribute::GroupAttribute(ProgramID pid, const Source& src, uint32_t val)
- : Base(pid, src), value(val) {}
+GroupAttribute::GroupAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t val)
+ : Base(pid, nid, src), value(val) {}
GroupAttribute::~GroupAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/group_attribute.h b/chromium/third_party/dawn/src/tint/ast/group_attribute.h
index a55946177b5..66d6ccb4092 100644
--- a/chromium/third_party/dawn/src/tint/ast/group_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/group_attribute.h
@@ -26,9 +26,10 @@ class GroupAttribute final : public Castable<GroupAttribute, Attribute> {
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param value the group value
- GroupAttribute(ProgramID pid, const Source& src, uint32_t value);
+ GroupAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t value);
~GroupAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/group_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/group_attribute_test.cc
index 53167bbb7a1..4a6dd1dd28b 100644
--- a/chromium/third_party/dawn/src/tint/ast/group_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/group_attribute_test.cc
@@ -20,7 +20,7 @@ namespace {
using GroupAttributeTest = TestHelper;
TEST_F(GroupAttributeTest, Creation) {
- auto* d = create<GroupAttribute>(2);
+ auto* d = create<GroupAttribute>(2u);
EXPECT_EQ(2u, d->value);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/i32.cc b/chromium/third_party/dawn/src/tint/ast/i32.cc
index 46fe75ed78a..ffdf30dedf3 100644
--- a/chromium/third_party/dawn/src/tint/ast/i32.cc
+++ b/chromium/third_party/dawn/src/tint/ast/i32.cc
@@ -20,7 +20,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::I32);
namespace tint::ast {
-I32::I32(ProgramID pid, const Source& src) : Base(pid, src) {}
+I32::I32(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
I32::I32(I32&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/i32.h b/chromium/third_party/dawn/src/tint/ast/i32.h
index acafd37cfdb..d2c951c3f0e 100644
--- a/chromium/third_party/dawn/src/tint/ast/i32.h
+++ b/chromium/third_party/dawn/src/tint/ast/i32.h
@@ -26,8 +26,9 @@ class I32 final : public Castable<I32, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- I32(ProgramID pid, const Source& src);
+ I32(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
I32(I32&&);
~I32() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/id_attribute.cc b/chromium/third_party/dawn/src/tint/ast/id_attribute.cc
index b6e19574b36..75d62c6cd09 100644
--- a/chromium/third_party/dawn/src/tint/ast/id_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/id_attribute.cc
@@ -22,8 +22,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::IdAttribute);
namespace tint::ast {
-IdAttribute::IdAttribute(ProgramID pid, const Source& src, uint32_t val)
- : Base(pid, src), value(val) {}
+IdAttribute::IdAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t val)
+ : Base(pid, nid, src), value(val) {}
IdAttribute::~IdAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/id_attribute.h b/chromium/third_party/dawn/src/tint/ast/id_attribute.h
index 5e3ec12f782..ca2a35822d8 100644
--- a/chromium/third_party/dawn/src/tint/ast/id_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/id_attribute.h
@@ -26,9 +26,10 @@ class IdAttribute final : public Castable<IdAttribute, Attribute> {
public:
/// Create an id attribute.
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param val the numeric id value
- IdAttribute(ProgramID pid, const Source& src, uint32_t val);
+ IdAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t val);
~IdAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/id_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/id_attribute_test.cc
index 6957d66b637..ad05c58ab53 100644
--- a/chromium/third_party/dawn/src/tint/ast/id_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/id_attribute_test.cc
@@ -22,7 +22,7 @@ namespace {
using IdAttributeTest = TestHelper;
TEST_F(IdAttributeTest, Creation) {
- auto* d = create<IdAttribute>(12);
+ auto* d = create<IdAttribute>(12u);
EXPECT_EQ(12u, d->value);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/identifier_expression.cc b/chromium/third_party/dawn/src/tint/ast/identifier_expression.cc
index 453ae696622..34eadeb07bc 100644
--- a/chromium/third_party/dawn/src/tint/ast/identifier_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/identifier_expression.cc
@@ -20,8 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::IdentifierExpression);
namespace tint::ast {
-IdentifierExpression::IdentifierExpression(ProgramID pid, const Source& src, Symbol sym)
- : Base(pid, src), symbol(sym) {
+IdentifierExpression::IdentifierExpression(ProgramID pid, NodeID nid, const Source& src, Symbol sym)
+ : Base(pid, nid, src), symbol(sym) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
TINT_ASSERT(AST, symbol.IsValid());
}
diff --git a/chromium/third_party/dawn/src/tint/ast/identifier_expression.h b/chromium/third_party/dawn/src/tint/ast/identifier_expression.h
index c3e1c30e544..b583807ba26 100644
--- a/chromium/third_party/dawn/src/tint/ast/identifier_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/identifier_expression.h
@@ -24,9 +24,10 @@ class IdentifierExpression final : public Castable<IdentifierExpression, Express
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param sym the symbol for the identifier
- IdentifierExpression(ProgramID pid, const Source& src, Symbol sym);
+ IdentifierExpression(ProgramID pid, NodeID nid, const Source& src, Symbol sym);
/// Move constructor
IdentifierExpression(IdentifierExpression&&);
~IdentifierExpression() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/if_statement.cc b/chromium/third_party/dawn/src/tint/ast/if_statement.cc
index c8fd374042b..5f7f1a71485 100644
--- a/chromium/third_party/dawn/src/tint/ast/if_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/if_statement.cc
@@ -21,11 +21,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::IfStatement);
namespace tint::ast {
IfStatement::IfStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* cond,
const BlockStatement* b,
const Statement* else_stmt)
- : Base(pid, src), condition(cond), body(b), else_statement(else_stmt) {
+ : Base(pid, nid, src), condition(cond), body(b), else_statement(else_stmt) {
TINT_ASSERT(AST, condition);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
TINT_ASSERT(AST, body);
diff --git a/chromium/third_party/dawn/src/tint/ast/if_statement.h b/chromium/third_party/dawn/src/tint/ast/if_statement.h
index 75e6eee1ef6..81d9756c66c 100644
--- a/chromium/third_party/dawn/src/tint/ast/if_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/if_statement.h
@@ -27,11 +27,13 @@ class IfStatement final : public Castable<IfStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param condition the if condition
/// @param body the if body
/// @param else_stmt the else statement, or nullptr
IfStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* condition,
const BlockStatement* body,
diff --git a/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.cc b/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.cc
index 99c65cb4f75..5b10e5fb8c4 100644
--- a/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::IncrementDecrementStatement);
namespace tint::ast {
IncrementDecrementStatement::IncrementDecrementStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* l,
bool inc)
- : Base(pid, src), lhs(l), increment(inc) {
+ : Base(pid, nid, src), lhs(l), increment(inc) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.h b/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.h
index 05b8478e948..ec9923ab690 100644
--- a/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/increment_decrement_statement.h
@@ -25,10 +25,15 @@ class IncrementDecrementStatement final : public Castable<IncrementDecrementStat
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param lhs the LHS expression
/// @param inc `true` for increment, `false` for decrement
- IncrementDecrementStatement(ProgramID pid, const Source& src, const Expression* lhs, bool inc);
+ IncrementDecrementStatement(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Expression* lhs,
+ bool inc);
/// Move constructor
IncrementDecrementStatement(IncrementDecrementStatement&&);
~IncrementDecrementStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.cc b/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.cc
index 232bc793c23..47f5156a8d5 100644
--- a/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::IndexAccessorExpression);
namespace tint::ast {
IndexAccessorExpression::IndexAccessorExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* obj,
const Expression* idx)
- : Base(pid, src), object(obj), index(idx) {
+ : Base(pid, nid, src), object(obj), index(idx) {
TINT_ASSERT(AST, object);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, object, program_id);
TINT_ASSERT(AST, idx);
diff --git a/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.h b/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.h
index c36f6b89115..0307f9edbeb 100644
--- a/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/index_accessor_expression.h
@@ -23,11 +23,13 @@ namespace tint::ast {
class IndexAccessorExpression final : public Castable<IndexAccessorExpression, Expression> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the index accessor source
/// @param obj the object
/// @param idx the index expression
- IndexAccessorExpression(ProgramID program_id,
+ IndexAccessorExpression(ProgramID pid,
+ NodeID nid,
const Source& source,
const Expression* obj,
const Expression* idx);
diff --git a/chromium/third_party/dawn/src/tint/ast/int_literal_expression.cc b/chromium/third_party/dawn/src/tint/ast/int_literal_expression.cc
index 7e11f7ec5a4..502ea9d0db4 100644
--- a/chromium/third_party/dawn/src/tint/ast/int_literal_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/int_literal_expression.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::IntLiteralExpression);
namespace tint::ast {
IntLiteralExpression::IntLiteralExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
int64_t val,
Suffix suf)
- : Base(pid, src), value(val), suffix(suf) {}
+ : Base(pid, nid, src), value(val), suffix(suf) {}
IntLiteralExpression::~IntLiteralExpression() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/int_literal_expression.h b/chromium/third_party/dawn/src/tint/ast/int_literal_expression.h
index 8ff58eaf229..10cbbee5a0e 100644
--- a/chromium/third_party/dawn/src/tint/ast/int_literal_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/int_literal_expression.h
@@ -20,7 +20,7 @@
namespace tint::ast {
/// An integer literal. The literal may have an 'i', 'u' or no suffix.
-class IntLiteralExpression : public Castable<IntLiteralExpression, LiteralExpression> {
+class IntLiteralExpression final : public Castable<IntLiteralExpression, LiteralExpression> {
public:
/// Literal suffix
enum class Suffix {
@@ -34,10 +34,11 @@ class IntLiteralExpression : public Castable<IntLiteralExpression, LiteralExpres
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param val the literal value
/// @param suf the literal suffix
- IntLiteralExpression(ProgramID pid, const Source& src, int64_t val, Suffix suf);
+ IntLiteralExpression(ProgramID pid, NodeID nid, const Source& src, int64_t val, Suffix suf);
~IntLiteralExpression() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/internal_attribute.cc b/chromium/third_party/dawn/src/tint/ast/internal_attribute.cc
index 180e90983a9..1b4ca9e99ba 100644
--- a/chromium/third_party/dawn/src/tint/ast/internal_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/internal_attribute.cc
@@ -18,7 +18,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::InternalAttribute);
namespace tint::ast {
-InternalAttribute::InternalAttribute(ProgramID pid) : Base(pid, Source{}) {}
+InternalAttribute::InternalAttribute(ProgramID pid, NodeID nid) : Base(pid, nid, Source{}) {}
InternalAttribute::~InternalAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/internal_attribute.h b/chromium/third_party/dawn/src/tint/ast/internal_attribute.h
index bb135591841..9904af819e7 100644
--- a/chromium/third_party/dawn/src/tint/ast/internal_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/internal_attribute.h
@@ -28,7 +28,8 @@ class InternalAttribute : public Castable<InternalAttribute, Attribute> {
public:
/// Constructor
/// @param program_id the identifier of the program that owns this node
- explicit InternalAttribute(ProgramID program_id);
+ /// @param nid the unique node identifier
+ explicit InternalAttribute(ProgramID program_id, NodeID nid);
/// Destructor
~InternalAttribute() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.cc b/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.cc
index 909e827d59a..29e3bfed427 100644
--- a/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.cc
@@ -23,10 +23,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::InterpolateAttribute);
namespace tint::ast {
InterpolateAttribute::InterpolateAttribute(ProgramID pid,
+ NodeID nid,
const Source& src,
InterpolationType ty,
InterpolationSampling smpl)
- : Base(pid, src), type(ty), sampling(smpl) {}
+ : Base(pid, nid, src), type(ty), sampling(smpl) {}
InterpolateAttribute::~InterpolateAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.h b/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.h
index 4b2a2df787c..4f9ea9de4b8 100644
--- a/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/interpolate_attribute.h
@@ -33,10 +33,12 @@ class InterpolateAttribute final : public Castable<InterpolateAttribute, Attribu
public:
/// Create an interpolate attribute.
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param type the interpolation type
/// @param sampling the interpolation sampling
InterpolateAttribute(ProgramID pid,
+ NodeID nid,
const Source& src,
InterpolationType type,
InterpolationSampling sampling);
diff --git a/chromium/third_party/dawn/src/tint/ast/invariant_attribute.cc b/chromium/third_party/dawn/src/tint/ast/invariant_attribute.cc
index 1b0f126fd2d..1fa4e5dc095 100644
--- a/chromium/third_party/dawn/src/tint/ast/invariant_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/invariant_attribute.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::InvariantAttribute);
namespace tint::ast {
-InvariantAttribute::InvariantAttribute(ProgramID pid, const Source& src) : Base(pid, src) {}
+InvariantAttribute::InvariantAttribute(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src) {}
InvariantAttribute::~InvariantAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/invariant_attribute.h b/chromium/third_party/dawn/src/tint/ast/invariant_attribute.h
index 6bb42fc6b63..9abb6a4c605 100644
--- a/chromium/third_party/dawn/src/tint/ast/invariant_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/invariant_attribute.h
@@ -26,8 +26,9 @@ class InvariantAttribute final : public Castable<InvariantAttribute, Attribute>
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- InvariantAttribute(ProgramID pid, const Source& src);
+ InvariantAttribute(ProgramID pid, NodeID nid, const Source& src);
~InvariantAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/let.cc b/chromium/third_party/dawn/src/tint/ast/let.cc
new file mode 100644
index 00000000000..0248234c897
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/let.cc
@@ -0,0 +1,53 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/let.h"
+
+#include <utility>
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::Let);
+
+namespace tint::ast {
+
+Let::Let(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Symbol& sym,
+ const ast::Type* ty,
+ const Expression* ctor,
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)) {
+ TINT_ASSERT(AST, ctor != nullptr);
+}
+
+Let::Let(Let&&) = default;
+
+Let::~Let() = default;
+
+const char* Let::Kind() const {
+ return "let";
+}
+
+const Let* Let::Clone(CloneContext* ctx) const {
+ auto src = ctx->Clone(source);
+ auto sym = ctx->Clone(symbol);
+ auto* ty = ctx->Clone(type);
+ auto* ctor = ctx->Clone(constructor);
+ auto attrs = ctx->Clone(attributes);
+ return ctx->dst->create<Let>(src, sym, ty, ctor, std::move(attrs));
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/let.h b/chromium/third_party/dawn/src/tint/ast/let.h
new file mode 100644
index 00000000000..fa0c8be6a92
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/let.h
@@ -0,0 +1,66 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_LET_H_
+#define SRC_TINT_AST_LET_H_
+
+#include "src/tint/ast/variable.h"
+
+namespace tint::ast {
+
+/// A "let" declaration is a name for a function-scoped runtime typed value.
+///
+/// Examples:
+///
+/// ```
+/// let twice_depth : i32 = width + width; // Must have initializer
+/// ```
+/// @see https://www.w3.org/TR/WGSL/#let-decls
+class Let final : public Castable<Let, Variable> {
+ public:
+ /// Create a 'let' variable
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param source the variable source
+ /// @param sym the variable symbol
+ /// @param type the declared variable type
+ /// @param constructor the constructor expression
+ /// @param attributes the variable attributes
+ Let(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ const Symbol& sym,
+ const ast::Type* type,
+ const Expression* constructor,
+ utils::VectorRef<const Attribute*> attributes);
+
+ /// Move constructor
+ Let(Let&&);
+
+ /// Destructor
+ ~Let() override;
+
+ /// @returns "let"
+ const char* Kind() const override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext`
+ /// `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const Let* Clone(CloneContext* ctx) const override;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_LET_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/literal_expression.cc b/chromium/third_party/dawn/src/tint/ast/literal_expression.cc
index d05279d0f73..bcf62adb086 100644
--- a/chromium/third_party/dawn/src/tint/ast/literal_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/literal_expression.cc
@@ -18,7 +18,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::LiteralExpression);
namespace tint::ast {
-LiteralExpression::LiteralExpression(ProgramID pid, const Source& src) : Base(pid, src) {}
+LiteralExpression::LiteralExpression(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src) {}
LiteralExpression::~LiteralExpression() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/literal_expression.h b/chromium/third_party/dawn/src/tint/ast/literal_expression.h
index 56fc1f0f802..b4b2b097a1d 100644
--- a/chromium/third_party/dawn/src/tint/ast/literal_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/literal_expression.h
@@ -29,8 +29,9 @@ class LiteralExpression : public Castable<LiteralExpression, Expression> {
protected:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the input source
- LiteralExpression(ProgramID pid, const Source& src);
+ LiteralExpression(ProgramID pid, NodeID nid, const Source& src);
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/location_attribute.cc b/chromium/third_party/dawn/src/tint/ast/location_attribute.cc
index 1eae823adeb..2ea2d5d24d7 100644
--- a/chromium/third_party/dawn/src/tint/ast/location_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/location_attribute.cc
@@ -22,8 +22,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::LocationAttribute);
namespace tint::ast {
-LocationAttribute::LocationAttribute(ProgramID pid, const Source& src, uint32_t val)
- : Base(pid, src), value(val) {}
+LocationAttribute::LocationAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t val)
+ : Base(pid, nid, src), value(val) {}
LocationAttribute::~LocationAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/location_attribute.h b/chromium/third_party/dawn/src/tint/ast/location_attribute.h
index 3646c544fc6..97c6feaf844 100644
--- a/chromium/third_party/dawn/src/tint/ast/location_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/location_attribute.h
@@ -26,9 +26,10 @@ class LocationAttribute final : public Castable<LocationAttribute, Attribute> {
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param value the location value
- LocationAttribute(ProgramID pid, const Source& src, uint32_t value);
+ LocationAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t value);
~LocationAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/location_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/location_attribute_test.cc
index a1562d561ab..e0bcb39c7f0 100644
--- a/chromium/third_party/dawn/src/tint/ast/location_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/location_attribute_test.cc
@@ -20,7 +20,7 @@ namespace {
using LocationAttributeTest = TestHelper;
TEST_F(LocationAttributeTest, Creation) {
- auto* d = create<LocationAttribute>(2);
+ auto* d = create<LocationAttribute>(2u);
EXPECT_EQ(2u, d->value);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/loop_statement.cc b/chromium/third_party/dawn/src/tint/ast/loop_statement.cc
index 9d14960c97f..b7e7a1bd711 100644
--- a/chromium/third_party/dawn/src/tint/ast/loop_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/loop_statement.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::LoopStatement);
namespace tint::ast {
LoopStatement::LoopStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const BlockStatement* b,
const BlockStatement* cont)
- : Base(pid, src), body(b), continuing(cont) {
+ : Base(pid, nid, src), body(b), continuing(cont) {
TINT_ASSERT(AST, body);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, continuing, program_id);
diff --git a/chromium/third_party/dawn/src/tint/ast/loop_statement.h b/chromium/third_party/dawn/src/tint/ast/loop_statement.h
index 5a044fead84..d4b24cf7bc3 100644
--- a/chromium/third_party/dawn/src/tint/ast/loop_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/loop_statement.h
@@ -23,11 +23,13 @@ namespace tint::ast {
class LoopStatement final : public Castable<LoopStatement, Statement> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the loop statement source
/// @param body the body statements
/// @param continuing the continuing statements
- LoopStatement(ProgramID program_id,
+ LoopStatement(ProgramID pid,
+ NodeID nid,
const Source& source,
const BlockStatement* body,
const BlockStatement* continuing);
diff --git a/chromium/third_party/dawn/src/tint/ast/loop_statement_test.cc b/chromium/third_party/dawn/src/tint/ast/loop_statement_test.cc
index c28665b0b70..caa995debfa 100644
--- a/chromium/third_party/dawn/src/tint/ast/loop_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/loop_statement_test.cc
@@ -31,9 +31,9 @@ TEST_F(LoopStatementTest, Creation) {
auto* continuing = Block(create<DiscardStatement>());
auto* l = create<LoopStatement>(body, continuing);
- ASSERT_EQ(l->body->statements.size(), 1u);
+ ASSERT_EQ(l->body->statements.Length(), 1u);
EXPECT_EQ(l->body->statements[0], b);
- ASSERT_EQ(l->continuing->statements.size(), 1u);
+ ASSERT_EQ(l->continuing->statements.Length(), 1u);
EXPECT_EQ(l->continuing->statements[0], continuing->Last());
}
diff --git a/chromium/third_party/dawn/src/tint/ast/matrix.cc b/chromium/third_party/dawn/src/tint/ast/matrix.cc
index 1f74a26ec05..69371274f99 100644
--- a/chromium/third_party/dawn/src/tint/ast/matrix.cc
+++ b/chromium/third_party/dawn/src/tint/ast/matrix.cc
@@ -20,8 +20,13 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Matrix);
namespace tint::ast {
-Matrix::Matrix(ProgramID pid, const Source& src, const Type* subtype, uint32_t r, uint32_t c)
- : Base(pid, src), type(subtype), rows(r), columns(c) {
+Matrix::Matrix(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Type* subtype,
+ uint32_t r,
+ uint32_t c)
+ : Base(pid, nid, src), type(subtype), rows(r), columns(c) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, subtype, program_id);
TINT_ASSERT(AST, rows > 1);
TINT_ASSERT(AST, rows < 5);
diff --git a/chromium/third_party/dawn/src/tint/ast/matrix.h b/chromium/third_party/dawn/src/tint/ast/matrix.h
index 620f28a38c9..e778738d8ce 100644
--- a/chromium/third_party/dawn/src/tint/ast/matrix.h
+++ b/chromium/third_party/dawn/src/tint/ast/matrix.h
@@ -26,13 +26,19 @@ class Matrix final : public Castable<Matrix, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param subtype the declared type of the matrix components. May be null for
/// matrix constructors, where the element type will be inferred from
/// the constructor arguments
/// @param rows the number of rows in the matrix
/// @param columns the number of columns in the matrix
- Matrix(ProgramID pid, const Source& src, const Type* subtype, uint32_t rows, uint32_t columns);
+ Matrix(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Type* subtype,
+ uint32_t rows,
+ uint32_t columns);
/// Move constructor
Matrix(Matrix&&);
~Matrix() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/matrix_test.cc b/chromium/third_party/dawn/src/tint/ast/matrix_test.cc
index 66ea84de9f9..dbb88e38f8a 100644
--- a/chromium/third_party/dawn/src/tint/ast/matrix_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/matrix_test.cc
@@ -34,7 +34,7 @@ using AstMatrixTest = TestHelper;
TEST_F(AstMatrixTest, Creation) {
auto* i32 = create<I32>();
- auto* m = create<Matrix>(i32, 2, 4);
+ auto* m = create<Matrix>(i32, 2u, 4u);
EXPECT_EQ(m->type, i32);
EXPECT_EQ(m->rows, 2u);
EXPECT_EQ(m->columns, 4u);
@@ -42,12 +42,12 @@ TEST_F(AstMatrixTest, Creation) {
TEST_F(AstMatrixTest, FriendlyName) {
auto* i32 = create<I32>();
- auto* m = create<Matrix>(i32, 3, 2);
+ auto* m = create<Matrix>(i32, 3u, 2u);
EXPECT_EQ(m->FriendlyName(Symbols()), "mat2x3<i32>");
}
TEST_F(AstMatrixTest, FriendlyName_WithoutType) {
- auto* m = create<Matrix>(nullptr, 3, 2);
+ auto* m = create<Matrix>(nullptr, 3u, 2u);
EXPECT_EQ(m->FriendlyName(Symbols()), "mat2x3");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.cc b/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.cc
index a087ea458cb..b895e3bec06 100644
--- a/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::MemberAccessorExpression);
namespace tint::ast {
MemberAccessorExpression::MemberAccessorExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* str,
const IdentifierExpression* mem)
- : Base(pid, src), structure(str), member(mem) {
+ : Base(pid, nid, src), structure(str), member(mem) {
TINT_ASSERT(AST, structure);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, structure, program_id);
TINT_ASSERT(AST, member);
diff --git a/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.h b/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.h
index 07054caddb7..33284fe7ace 100644
--- a/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/member_accessor_expression.h
@@ -23,11 +23,13 @@ namespace tint::ast {
class MemberAccessorExpression final : public Castable<MemberAccessorExpression, Expression> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the member accessor expression source
/// @param structure the structure
/// @param member the member
- MemberAccessorExpression(ProgramID program_id,
+ MemberAccessorExpression(ProgramID pid,
+ NodeID nid,
const Source& source,
const Expression* structure,
const IdentifierExpression* member);
diff --git a/chromium/third_party/dawn/src/tint/ast/module.cc b/chromium/third_party/dawn/src/tint/ast/module.cc
index 40dff985997..3faab6c56e0 100644
--- a/chromium/third_party/dawn/src/tint/ast/module.cc
+++ b/chromium/third_party/dawn/src/tint/ast/module.cc
@@ -23,10 +23,13 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Module);
namespace tint::ast {
-Module::Module(ProgramID pid, const Source& src) : Base(pid, src) {}
+Module::Module(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
-Module::Module(ProgramID pid, const Source& src, std::vector<const ast::Node*> global_decls)
- : Base(pid, src), global_declarations_(std::move(global_decls)) {
+Module::Module(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ utils::VectorRef<const ast::Node*> global_decls)
+ : Base(pid, nid, src), global_declarations_(std::move(global_decls)) {
for (auto* decl : global_declarations_) {
if (decl == nullptr) {
continue;
@@ -50,7 +53,7 @@ const ast::TypeDecl* Module::LookupType(Symbol name) const {
void Module::AddGlobalDeclaration(const tint::ast::Node* decl) {
diag::List diags;
BinGlobalDeclaration(decl, diags);
- global_declarations_.emplace_back(decl);
+ global_declarations_.Push(decl);
}
void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags) {
@@ -58,19 +61,23 @@ void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags
decl, //
[&](const ast::TypeDecl* type) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
- type_decls_.push_back(type);
+ type_decls_.Push(type);
},
[&](const Function* func) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
- functions_.push_back(func);
+ functions_.Push(func);
},
[&](const Variable* var) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
- global_variables_.push_back(var);
+ global_variables_.Push(var);
},
[&](const Enable* enable) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id);
- enables_.push_back(enable);
+ enables_.Push(enable);
+ },
+ [&](const StaticAssert* assertion) {
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, assertion, program_id);
+ static_asserts_.Push(assertion);
},
[&](Default) { TINT_ICE(AST, diags) << "Unknown global declaration type"; });
}
@@ -78,29 +85,36 @@ void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags
void Module::AddEnable(const ast::Enable* enable) {
TINT_ASSERT(AST, enable);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id);
- global_declarations_.push_back(enable);
- enables_.push_back(enable);
+ global_declarations_.Push(enable);
+ enables_.Push(enable);
}
void Module::AddGlobalVariable(const ast::Variable* var) {
TINT_ASSERT(AST, var);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
- global_variables_.push_back(var);
- global_declarations_.push_back(var);
+ global_variables_.Push(var);
+ global_declarations_.Push(var);
+}
+
+void Module::AddStaticAssert(const StaticAssert* assertion) {
+ TINT_ASSERT(AST, assertion);
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, assertion, program_id);
+ static_asserts_.Push(assertion);
+ global_declarations_.Push(assertion);
}
void Module::AddTypeDecl(const ast::TypeDecl* type) {
TINT_ASSERT(AST, type);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
- type_decls_.push_back(type);
- global_declarations_.push_back(type);
+ type_decls_.Push(type);
+ global_declarations_.Push(type);
}
void Module::AddFunction(const ast::Function* func) {
TINT_ASSERT(AST, func);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
- functions_.push_back(func);
- global_declarations_.push_back(func);
+ functions_.Push(func);
+ global_declarations_.Push(func);
}
const Module* Module::Clone(CloneContext* ctx) const {
@@ -114,10 +128,10 @@ void Module::Copy(CloneContext* ctx, const Module* src) {
// During the clone, declarations may have been placed into the module.
// Clear everything out, as we're about to re-bin the declarations.
- type_decls_.clear();
- functions_.clear();
- global_variables_.clear();
- enables_.clear();
+ type_decls_.Clear();
+ functions_.Clear();
+ global_variables_.Clear();
+ enables_.Clear();
for (auto* decl : global_declarations_) {
if (!decl) {
diff --git a/chromium/third_party/dawn/src/tint/ast/module.h b/chromium/third_party/dawn/src/tint/ast/module.h
index 45b1ec6ebe4..2818cb827e9 100644
--- a/chromium/third_party/dawn/src/tint/ast/module.h
+++ b/chromium/third_party/dawn/src/tint/ast/module.h
@@ -16,11 +16,12 @@
#define SRC_TINT_AST_MODULE_H_
#include <string>
-#include <vector>
#include "src/tint/ast/enable.h"
#include "src/tint/ast/function.h"
+#include "src/tint/ast/static_assert.h"
#include "src/tint/ast/type.h"
+#include "src/tint/utils/vector.h"
namespace tint::ast {
@@ -32,27 +33,28 @@ class Module final : public Castable<Module, Node> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- Module(ProgramID pid, const Source& src);
+ Module(ProgramID pid, NodeID nid, const Source& src);
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param global_decls the list of global types, functions, and variables, in
/// the order they were declared in the source program
- Module(ProgramID pid, const Source& src, std::vector<const Node*> global_decls);
+ Module(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ utils::VectorRef<const ast::Node*> global_decls);
/// Destructor
~Module() override;
/// @returns the declaration-ordered global declarations for the module
- const std::vector<const Node*>& GlobalDeclarations() const { return global_declarations_; }
+ const auto& GlobalDeclarations() const { return global_declarations_; }
- /// Add a enable directive to the Builder
- /// @param ext the enable directive to add
- void AddEnable(const Enable* ext);
-
- /// Add a global variable to the Builder
+ /// Add a global variable to the module
/// @param var the variable to add
void AddGlobalVariable(const Variable* var);
@@ -67,20 +69,44 @@ class Module final : public Castable<Module, Node> {
return false;
}
- /// Adds a global declaration to the Builder.
+ /// Adds a global declaration to the module.
/// @param decl the declaration to add
void AddGlobalDeclaration(const tint::ast::Node* decl);
/// @returns the global variables for the module
- const VariableList& GlobalVariables() const { return global_variables_; }
+ const auto& GlobalVariables() const { return global_variables_; }
/// @returns the global variables for the module
- VariableList& GlobalVariables() { return global_variables_; }
+ auto& GlobalVariables() { return global_variables_; }
+
+ /// @returns the global variable declarations of kind 'T' for the module
+ template <typename T, typename = traits::EnableIfIsType<T, ast::Variable>>
+ auto Globals() const {
+ utils::Vector<const T*, 32> out;
+ out.Reserve(global_variables_.Length());
+ for (auto* global : global_variables_) {
+ if (auto* var = global->As<T>()) {
+ out.Push(var);
+ }
+ }
+ return out;
+ }
+
+ /// Add a enable directive to the module
+ /// @param ext the enable directive to add
+ void AddEnable(const Enable* ext);
/// @returns the extension set for the module
- const EnableList& Enables() const { return enables_; }
+ const auto& Enables() const { return enables_; }
+
+ /// Add a global static assertion to the module
+ /// @param assertion the static assert to add
+ void AddStaticAssert(const StaticAssert* assertion);
+
+ /// @returns the list of global static assertions
+ const auto& StaticAsserts() const { return static_asserts_; }
- /// Adds a type declaration to the Builder.
+ /// Adds a type declaration to the module
/// @param decl the type declaration to add
void AddTypeDecl(const TypeDecl* decl);
@@ -89,9 +115,9 @@ class Module final : public Castable<Module, Node> {
const TypeDecl* LookupType(Symbol name) const;
/// @returns the declared types in the module
- const std::vector<const TypeDecl*>& TypeDecls() const { return type_decls_; }
+ const auto& TypeDecls() const { return type_decls_; }
- /// Add a function to the Builder
+ /// Add a function to the module
/// @param func the function to add
void AddFunction(const Function* func);
@@ -116,11 +142,12 @@ class Module final : public Castable<Module, Node> {
/// * #functions_
void BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags);
- std::vector<const Node*> global_declarations_;
- std::vector<const TypeDecl*> type_decls_;
+ utils::Vector<const Node*, 64> global_declarations_;
+ utils::Vector<const TypeDecl*, 16> type_decls_;
FunctionList functions_;
- VariableList global_variables_;
- EnableList enables_;
+ utils::Vector<const Variable*, 32> global_variables_;
+ utils::Vector<const Enable*, 8> enables_;
+ utils::Vector<const StaticAssert*, 8> static_asserts_;
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/module_clone_test.cc b/chromium/third_party/dawn/src/tint/ast/module_clone_test.cc
index bd96b2609f5..a79ef0e566b 100644
--- a/chromium/third_party/dawn/src/tint/ast/module_clone_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/module_clone_test.cc
@@ -37,8 +37,8 @@ struct S1 {
m1 : array<u32, 6>,
};
-let c0 : i32 = 10;
-let c1 : bool = true;
+const c0 : i32 = 10;
+const c1 : bool = true;
type t0 = array<vec4<f32>>;
type t1 = array<vec4<f32>>;
@@ -52,7 +52,7 @@ var<private> g1 : f32 = 123.0;
@group(4) @binding(0) var g6 : texture_external;
var<private> g7 : vec3<f32>;
-@group(0) @binding(1) var<storage, write> g8 : S0;
+@group(0) @binding(1) var<storage, read_write> g8 : S0;
@group(1) @binding(1) var<storage, read> g9 : S0;
@group(2) @binding(1) var<storage, read_write> g10 : S0;
@@ -71,6 +71,8 @@ fn f1(p0 : f32, p1 : i32) -> f32 {
var l4 : S1;
var l5 : u32 = l4.m1[5];
let l6 : ptr<private, u32> = &g0;
+ const l7 = 123;
+ const l8 : i32 = 123;
loop {
l0 = (p1 + 2);
if (((l0 % 4) == 0)) {
@@ -104,7 +106,7 @@ fn main() {
f1(1.0, 2);
}
-let declaration_order_check_0 : i32 = 1;
+const declaration_order_check_0 : i32 = 1;
type declaration_order_check_1 = f32;
@@ -112,7 +114,7 @@ fn declaration_order_check_2() {}
type declaration_order_check_3 = f32;
-let declaration_order_check_4 : i32 = 1;
+const declaration_order_check_4 : i32 = 1;
)");
diff --git a/chromium/third_party/dawn/src/tint/ast/module_test.cc b/chromium/third_party/dawn/src/tint/ast/module_test.cc
index 6ac610ef2e6..3093a16efeb 100644
--- a/chromium/third_party/dawn/src/tint/ast/module_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/module_test.cc
@@ -22,11 +22,11 @@ namespace {
using ModuleTest = TestHelper;
TEST_F(ModuleTest, Creation) {
- EXPECT_EQ(Program(std::move(*this)).AST().Functions().size(), 0u);
+ EXPECT_EQ(Program(std::move(*this)).AST().Functions().Length(), 0u);
}
TEST_F(ModuleTest, LookupFunction) {
- auto* func = Func("main", VariableList{}, ty.f32(), StatementList{}, ast::AttributeList{});
+ auto* func = Func("main", {}, ty.f32(), {});
Program program(std::move(*this));
EXPECT_EQ(func, program.AST().Functions().Find(program.Symbols().Get("main")));
@@ -61,8 +61,8 @@ TEST_F(ModuleTest, Assert_DifferentProgramID_Function) {
ProgramBuilder b1;
ProgramBuilder b2;
b1.AST().AddFunction(b2.create<ast::Function>(b2.Symbols().Register("func"),
- VariableList{}, b2.ty.f32(), b2.Block(),
- AttributeList{}, AttributeList{}));
+ utils::Empty, b2.ty.f32(), b2.Block(),
+ utils::Empty, utils::Empty));
},
"internal compiler error");
}
@@ -92,7 +92,7 @@ TEST_F(ModuleTest, CloneOrder) {
ProgramBuilder b;
b.Func("F", {}, b.ty.void_(), {});
b.Alias("A", b.ty.u32());
- b.Global("V", b.ty.i32(), ast::StorageClass::kPrivate);
+ b.GlobalVar("V", b.ty.i32(), ast::StorageClass::kPrivate);
return Program(std::move(b));
}();
@@ -116,7 +116,7 @@ TEST_F(ModuleTest, CloneOrder) {
ctx.Clone();
auto& decls = cloned.AST().GlobalDeclarations();
- ASSERT_EQ(decls.size(), 6u);
+ ASSERT_EQ(decls.Length(), 6u);
EXPECT_TRUE(decls[1]->Is<ast::Function>());
EXPECT_TRUE(decls[3]->Is<ast::Alias>());
EXPECT_TRUE(decls[5]->Is<ast::Variable>());
diff --git a/chromium/third_party/dawn/src/tint/ast/multisampled_texture.cc b/chromium/third_party/dawn/src/tint/ast/multisampled_texture.cc
index 91f8edf5dd9..0c4485754dc 100644
--- a/chromium/third_party/dawn/src/tint/ast/multisampled_texture.cc
+++ b/chromium/third_party/dawn/src/tint/ast/multisampled_texture.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::MultisampledTexture);
namespace tint::ast {
MultisampledTexture::MultisampledTexture(ProgramID pid,
+ NodeID nid,
const Source& src,
TextureDimension d,
const Type* ty)
- : Base(pid, src, d), type(ty) {
+ : Base(pid, nid, src, d), type(ty) {
TINT_ASSERT(AST, type);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/multisampled_texture.h b/chromium/third_party/dawn/src/tint/ast/multisampled_texture.h
index 1d955056149..6887045fc5f 100644
--- a/chromium/third_party/dawn/src/tint/ast/multisampled_texture.h
+++ b/chromium/third_party/dawn/src/tint/ast/multisampled_texture.h
@@ -26,10 +26,15 @@ class MultisampledTexture final : public Castable<MultisampledTexture, Texture>
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param dim the dimensionality of the texture
/// @param type the data type of the multisampled texture
- MultisampledTexture(ProgramID pid, const Source& src, TextureDimension dim, const Type* type);
+ MultisampledTexture(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ TextureDimension dim,
+ const Type* type);
/// Move constructor
MultisampledTexture(MultisampledTexture&&);
~MultisampledTexture() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/node.cc b/chromium/third_party/dawn/src/tint/ast/node.cc
index 2368791d3d8..ce3a71d1b9d 100644
--- a/chromium/third_party/dawn/src/tint/ast/node.cc
+++ b/chromium/third_party/dawn/src/tint/ast/node.cc
@@ -18,7 +18,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Node);
namespace tint::ast {
-Node::Node(ProgramID pid, const Source& src) : program_id(pid), source(src) {}
+Node::Node(ProgramID pid, NodeID nid, const Source& src)
+ : program_id(pid), node_id(nid), source(src) {}
Node::Node(Node&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/node.h b/chromium/third_party/dawn/src/tint/ast/node.h
index 19d768228ae..6eaa1e94f0b 100644
--- a/chromium/third_party/dawn/src/tint/ast/node.h
+++ b/chromium/third_party/dawn/src/tint/ast/node.h
@@ -17,6 +17,7 @@
#include <string>
+#include "src/tint/ast/node_id.h"
#include "src/tint/clone_context.h"
namespace tint::ast {
@@ -29,14 +30,18 @@ class Node : public Castable<Node, Cloneable> {
/// The identifier of the program that owns this node
const ProgramID program_id;
+ /// The node identifier, unique for the program.
+ const NodeID node_id;
+
/// The node source data
const Source source;
protected:
/// Create a new node
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the input source for the node
- Node(ProgramID pid, const Source& src);
+ Node(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
Node(Node&&);
diff --git a/chromium/third_party/dawn/src/tint/ast/node_id.h b/chromium/third_party/dawn/src/tint/ast/node_id.h
new file mode 100644
index 00000000000..79683b0348f
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/node_id.h
@@ -0,0 +1,36 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_NODE_ID_H_
+#define SRC_TINT_AST_NODE_ID_H_
+
+#include <stddef.h>
+
+namespace tint::ast {
+
+/// NodeID is a unique node identifier for a given Program.
+/// NodeIDs are sequentially allocated, starting at 0.
+struct NodeID {
+ /// Equality operator
+ /// @param other the other NodeID
+ /// @returns true if the NodeIDs are the same
+ bool operator==(const NodeID& other) const { return value == other.value; }
+
+ /// The numerical value for the node identifier
+ size_t value = 0;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_NODE_ID_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/override.cc b/chromium/third_party/dawn/src/tint/ast/override.cc
new file mode 100644
index 00000000000..3a0a3a94677
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/override.cc
@@ -0,0 +1,58 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/override.h"
+
+#include <utility>
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::Override);
+
+namespace tint::ast {
+
+Override::Override(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Symbol& sym,
+ const ast::Type* ty,
+ const Expression* ctor,
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)) {}
+
+Override::Override(Override&&) = default;
+
+Override::~Override() = default;
+
+const char* Override::Kind() const {
+ return "override";
+}
+
+const Override* Override::Clone(CloneContext* ctx) const {
+ auto src = ctx->Clone(source);
+ auto sym = ctx->Clone(symbol);
+ auto* ty = ctx->Clone(type);
+ auto* ctor = ctx->Clone(constructor);
+ auto attrs = ctx->Clone(attributes);
+ return ctx->dst->create<Override>(src, sym, ty, ctor, std::move(attrs));
+}
+
+std::string Override::Identifier(const SymbolTable& symbols) const {
+ if (auto* id = ast::GetAttribute<ast::IdAttribute>(attributes)) {
+ return std::to_string(id->value);
+ }
+ return symbols.NameFor(symbol);
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/override.h b/chromium/third_party/dawn/src/tint/ast/override.h
new file mode 100644
index 00000000000..7d01d135e34
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/override.h
@@ -0,0 +1,75 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_OVERRIDE_H_
+#define SRC_TINT_AST_OVERRIDE_H_
+
+#include <string>
+
+#include "src/tint/ast/variable.h"
+
+namespace tint::ast {
+
+/// An "override" declaration - a name for a pipeline-overridable constant.
+/// Examples:
+///
+/// ```
+/// override radius : i32 = 2; // Can be overridden by name.
+/// @id(5) override width : i32 = 2; // Can be overridden by ID.
+/// override scale : f32; // No default - must be overridden.
+/// ```
+/// @see https://www.w3.org/TR/WGSL/#override-decls
+class Override final : public Castable<Override, Variable> {
+ public:
+ /// Create an 'override' pipeline-overridable constant.
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param source the variable source
+ /// @param sym the variable symbol
+ /// @param type the declared variable type
+ /// @param constructor the constructor expression
+ /// @param attributes the variable attributes
+ Override(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ const Symbol& sym,
+ const ast::Type* type,
+ const Expression* constructor,
+ utils::VectorRef<const Attribute*> attributes);
+
+ /// Move constructor
+ Override(Override&&);
+
+ /// Destructor
+ ~Override() override;
+
+ /// @returns "override"
+ const char* Kind() const override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext`
+ /// `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const Override* Clone(CloneContext* ctx) const override;
+
+ /// @param symbols the symbol table to retrieve the name from
+ /// @returns the identifier string for the override. If the override has
+ /// an ID attribute, the string is the id-stringified. Otherwise, the ID
+ /// is the symbol.
+ std::string Identifier(const SymbolTable& symbols) const;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_OVERRIDE_H_
diff --git a/chromium/third_party/dawn/src/tint/utils/to_const_ptr_vec.h b/chromium/third_party/dawn/src/tint/ast/override_test.cc
index 02cc984aae8..9e7af836219 100644
--- a/chromium/third_party/dawn/src/tint/utils/to_const_ptr_vec.h
+++ b/chromium/third_party/dawn/src/tint/ast/override_test.cc
@@ -1,5 +1,4 @@
-
-// Copyright 2021 The Tint Authors.
+// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,25 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_TINT_UTILS_TO_CONST_PTR_VEC_H_
-#define SRC_TINT_UTILS_TO_CONST_PTR_VEC_H_
+#include "src/tint/ast/override.h"
+
+#include "src/tint/ast/test_helper.h"
-#include <vector>
+namespace tint::ast {
+namespace {
-namespace tint::utils {
+using OverrideTest = TestHelper;
-/// @param in a vector of `T*`
-/// @returns a vector of `const T*` with the content of `in`.
-template <typename T>
-std::vector<const T*> ToConstPtrVec(const std::vector<T*>& in) {
- std::vector<const T*> out;
- out.reserve(in.size());
- for (auto* ptr : in) {
- out.emplace_back(ptr);
- }
- return out;
+TEST_F(OverrideTest, Identifier_NoId) {
+ auto* o = Override("o", nullptr, Expr(f32(1.0)));
+ EXPECT_EQ(std::string("o"), o->Identifier(Symbols()));
}
-} // namespace tint::utils
+TEST_F(OverrideTest, Identifier_WithId) {
+ auto* o = Override("o", nullptr, Expr(f32(1.0)), utils::Vector{Id(4u)});
+ EXPECT_EQ(std::string("4"), o->Identifier(Symbols()));
+}
-#endif // SRC_TINT_UTILS_TO_CONST_PTR_VEC_H_
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/parameter.cc b/chromium/third_party/dawn/src/tint/ast/parameter.cc
new file mode 100644
index 00000000000..01ee3aa6f99
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/parameter.cc
@@ -0,0 +1,49 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/parameter.h"
+
+#include <utility>
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::Parameter);
+
+namespace tint::ast {
+
+Parameter::Parameter(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Symbol& sym,
+ const ast::Type* ty,
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src, sym, ty, nullptr, std::move(attrs)) {}
+
+Parameter::Parameter(Parameter&&) = default;
+
+Parameter::~Parameter() = default;
+
+const char* Parameter::Kind() const {
+ return "parameter";
+}
+
+const Parameter* Parameter::Clone(CloneContext* ctx) const {
+ auto src = ctx->Clone(source);
+ auto sym = ctx->Clone(symbol);
+ auto* ty = ctx->Clone(type);
+ auto attrs = ctx->Clone(attributes);
+ return ctx->dst->create<Parameter>(src, sym, ty, std::move(attrs));
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/parameter.h b/chromium/third_party/dawn/src/tint/ast/parameter.h
new file mode 100644
index 00000000000..e9d9f62f236
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/parameter.h
@@ -0,0 +1,68 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_PARAMETER_H_
+#define SRC_TINT_AST_PARAMETER_H_
+
+#include <vector>
+
+#include "src/tint/ast/variable.h"
+
+namespace tint::ast {
+
+/// A formal parameter to a function - a name for a typed value to be passed into a function.
+/// Example:
+///
+/// ```
+/// fn twice(a: i32) -> i32 { // "a:i32" is the formal parameter
+/// return a + a;
+/// }
+/// ```
+///
+/// @see https://www.w3.org/TR/WGSL/#creation-time-consts
+class Parameter final : public Castable<Parameter, Variable> {
+ public:
+ /// Create a 'parameter' creation-time value variable.
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param source the variable source
+ /// @param sym the variable symbol
+ /// @param type the declared variable type
+ /// @param attributes the variable attributes
+ Parameter(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ const Symbol& sym,
+ const ast::Type* type,
+ utils::VectorRef<const Attribute*> attributes);
+
+ /// Move constructor
+ Parameter(Parameter&&);
+
+ /// Destructor
+ ~Parameter() override;
+
+ /// @returns "parameter"
+ const char* Kind() const override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext`
+ /// `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const Parameter* Clone(CloneContext* ctx) const override;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_PARAMETER_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/phony_expression.cc b/chromium/third_party/dawn/src/tint/ast/phony_expression.cc
index a3fd4fd9465..6bce1bf3a56 100644
--- a/chromium/third_party/dawn/src/tint/ast/phony_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/phony_expression.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::PhonyExpression);
namespace tint::ast {
-PhonyExpression::PhonyExpression(ProgramID pid, const Source& src) : Base(pid, src) {}
+PhonyExpression::PhonyExpression(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src) {}
PhonyExpression::PhonyExpression(PhonyExpression&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/phony_expression.h b/chromium/third_party/dawn/src/tint/ast/phony_expression.h
index 4fc32dd53d2..d429a51db28 100644
--- a/chromium/third_party/dawn/src/tint/ast/phony_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/phony_expression.h
@@ -25,8 +25,9 @@ class PhonyExpression final : public Castable<PhonyExpression, Expression> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- PhonyExpression(ProgramID pid, const Source& src);
+ PhonyExpression(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
PhonyExpression(PhonyExpression&&);
~PhonyExpression() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/pointer.cc b/chromium/third_party/dawn/src/tint/ast/pointer.cc
index 42c3fa9e864..796fe8587ec 100644
--- a/chromium/third_party/dawn/src/tint/ast/pointer.cc
+++ b/chromium/third_party/dawn/src/tint/ast/pointer.cc
@@ -21,11 +21,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Pointer);
namespace tint::ast {
Pointer::Pointer(ProgramID pid,
+ NodeID nid,
const Source& src,
const Type* const subtype,
ast::StorageClass sc,
ast::Access ac)
- : Base(pid, src), type(subtype), storage_class(sc), access(ac) {}
+ : Base(pid, nid, src), type(subtype), storage_class(sc), access(ac) {}
std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
std::ostringstream out;
diff --git a/chromium/third_party/dawn/src/tint/ast/pointer.h b/chromium/third_party/dawn/src/tint/ast/pointer.h
index 030e844eb35..61eff88efa9 100644
--- a/chromium/third_party/dawn/src/tint/ast/pointer.h
+++ b/chromium/third_party/dawn/src/tint/ast/pointer.h
@@ -28,11 +28,13 @@ class Pointer final : public Castable<Pointer, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param subtype the pointee type
/// @param storage_class the storage class of the pointer
/// @param access the access control of the pointer
Pointer(ProgramID pid,
+ NodeID nid,
const Source& src,
const Type* const subtype,
ast::StorageClass storage_class,
diff --git a/chromium/third_party/dawn/src/tint/ast/return_statement.cc b/chromium/third_party/dawn/src/tint/ast/return_statement.cc
index 976c063ca4a..459bb721fc6 100644
--- a/chromium/third_party/dawn/src/tint/ast/return_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/return_statement.cc
@@ -20,11 +20,14 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::ReturnStatement);
namespace tint::ast {
-ReturnStatement::ReturnStatement(ProgramID pid, const Source& src)
- : Base(pid, src), value(nullptr) {}
-
-ReturnStatement::ReturnStatement(ProgramID pid, const Source& src, const Expression* val)
- : Base(pid, src), value(val) {
+ReturnStatement::ReturnStatement(ProgramID pid, NodeID nid, const Source& src)
+ : Base(pid, nid, src), value(nullptr) {}
+
+ReturnStatement::ReturnStatement(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Expression* val)
+ : Base(pid, nid, src), value(val) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, value, program_id);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/return_statement.h b/chromium/third_party/dawn/src/tint/ast/return_statement.h
index 34d86782367..571a738c677 100644
--- a/chromium/third_party/dawn/src/tint/ast/return_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/return_statement.h
@@ -25,14 +25,16 @@ class ReturnStatement final : public Castable<ReturnStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- ReturnStatement(ProgramID pid, const Source& src);
+ ReturnStatement(ProgramID pid, NodeID nid, const Source& src);
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param value the return value
- ReturnStatement(ProgramID pid, const Source& src, const Expression* value);
+ ReturnStatement(ProgramID pid, NodeID nid, const Source& src, const Expression* value);
/// Move constructor
ReturnStatement(ReturnStatement&&);
~ReturnStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/sampled_texture.cc b/chromium/third_party/dawn/src/tint/ast/sampled_texture.cc
index 9c4cea631fd..b8dfd61aee6 100644
--- a/chromium/third_party/dawn/src/tint/ast/sampled_texture.cc
+++ b/chromium/third_party/dawn/src/tint/ast/sampled_texture.cc
@@ -20,8 +20,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::SampledTexture);
namespace tint::ast {
-SampledTexture::SampledTexture(ProgramID pid, const Source& src, TextureDimension d, const Type* ty)
- : Base(pid, src, d), type(ty) {
+SampledTexture::SampledTexture(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ TextureDimension d,
+ const Type* ty)
+ : Base(pid, nid, src, d), type(ty) {
TINT_ASSERT(AST, type);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/sampled_texture.h b/chromium/third_party/dawn/src/tint/ast/sampled_texture.h
index f68fccf57ab..1f33af3b6b1 100644
--- a/chromium/third_party/dawn/src/tint/ast/sampled_texture.h
+++ b/chromium/third_party/dawn/src/tint/ast/sampled_texture.h
@@ -26,10 +26,15 @@ class SampledTexture final : public Castable<SampledTexture, Texture> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param dim the dimensionality of the texture
/// @param type the data type of the sampled texture
- SampledTexture(ProgramID pid, const Source& src, TextureDimension dim, const Type* type);
+ SampledTexture(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ TextureDimension dim,
+ const Type* type);
/// Move constructor
SampledTexture(SampledTexture&&);
~SampledTexture() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/sampler.cc b/chromium/third_party/dawn/src/tint/ast/sampler.cc
index 5d88bf86067..5237380a19d 100644
--- a/chromium/third_party/dawn/src/tint/ast/sampler.cc
+++ b/chromium/third_party/dawn/src/tint/ast/sampler.cc
@@ -32,7 +32,8 @@ std::ostream& operator<<(std::ostream& out, SamplerKind kind) {
return out;
}
-Sampler::Sampler(ProgramID pid, const Source& src, SamplerKind k) : Base(pid, src), kind(k) {}
+Sampler::Sampler(ProgramID pid, NodeID nid, const Source& src, SamplerKind k)
+ : Base(pid, nid, src), kind(k) {}
Sampler::Sampler(Sampler&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/sampler.h b/chromium/third_party/dawn/src/tint/ast/sampler.h
index 067fc386181..bcdf7511f53 100644
--- a/chromium/third_party/dawn/src/tint/ast/sampler.h
+++ b/chromium/third_party/dawn/src/tint/ast/sampler.h
@@ -39,9 +39,10 @@ class Sampler final : public Castable<Sampler, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param kind the kind of sampler
- Sampler(ProgramID pid, const Source& src, SamplerKind kind);
+ Sampler(ProgramID pid, NodeID nid, const Source& src, SamplerKind kind);
/// Move constructor
Sampler(Sampler&&);
~Sampler() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/stage_attribute.cc b/chromium/third_party/dawn/src/tint/ast/stage_attribute.cc
index 51cfe8c2629..c7009509fd0 100644
--- a/chromium/third_party/dawn/src/tint/ast/stage_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/stage_attribute.cc
@@ -22,8 +22,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::StageAttribute);
namespace tint::ast {
-StageAttribute::StageAttribute(ProgramID pid, const Source& src, PipelineStage s)
- : Base(pid, src), stage(s) {}
+StageAttribute::StageAttribute(ProgramID pid, NodeID nid, const Source& src, PipelineStage s)
+ : Base(pid, nid, src), stage(s) {}
StageAttribute::~StageAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/stage_attribute.h b/chromium/third_party/dawn/src/tint/ast/stage_attribute.h
index a447d1f78c8..0bf9d9e9329 100644
--- a/chromium/third_party/dawn/src/tint/ast/stage_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/stage_attribute.h
@@ -26,10 +26,11 @@ namespace tint::ast {
class StageAttribute final : public Castable<StageAttribute, Attribute> {
public:
/// constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param stage the pipeline stage
/// @param source the source of this attribute
- StageAttribute(ProgramID program_id, const Source& source, PipelineStage stage);
+ StageAttribute(ProgramID pid, NodeID nid, const Source& source, PipelineStage stage);
~StageAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/statement.cc b/chromium/third_party/dawn/src/tint/ast/statement.cc
index 12a1cc9406e..6acfff31a4e 100644
--- a/chromium/third_party/dawn/src/tint/ast/statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/statement.cc
@@ -30,7 +30,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Statement);
namespace tint::ast {
-Statement::Statement(ProgramID pid, const Source& src) : Base(pid, src) {}
+Statement::Statement(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
Statement::Statement(Statement&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/statement.h b/chromium/third_party/dawn/src/tint/ast/statement.h
index 94de2472416..616e348120a 100644
--- a/chromium/third_party/dawn/src/tint/ast/statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/statement.h
@@ -32,15 +32,13 @@ class Statement : public Castable<Statement, Node> {
protected:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of the expression
- Statement(ProgramID pid, const Source& src);
+ Statement(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
Statement(Statement&&);
};
-/// A list of statements
-using StatementList = std::vector<const Statement*>;
-
} // namespace tint::ast
#endif // SRC_TINT_AST_STATEMENT_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/static_assert.cc b/chromium/third_party/dawn/src/tint/ast/static_assert.cc
new file mode 100644
index 00000000000..0609194b882
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/static_assert.cc
@@ -0,0 +1,40 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/static_assert.h"
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::StaticAssert);
+
+namespace tint::ast {
+
+StaticAssert::StaticAssert(ProgramID pid, NodeID nid, const Source& src, const Expression* cond)
+ : Base(pid, nid, src), condition(cond) {
+ TINT_ASSERT(AST, cond);
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, cond, program_id);
+}
+
+StaticAssert::StaticAssert(StaticAssert&&) = default;
+
+StaticAssert::~StaticAssert() = default;
+
+const StaticAssert* StaticAssert::Clone(CloneContext* ctx) const {
+ // Clone arguments outside of create() call to have deterministic ordering
+ auto src = ctx->Clone(source);
+ auto* cond = ctx->Clone(condition);
+ return ctx->dst->create<StaticAssert>(src, cond);
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/static_assert.h b/chromium/third_party/dawn/src/tint/ast/static_assert.h
new file mode 100644
index 00000000000..f42ad0707bd
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/static_assert.h
@@ -0,0 +1,50 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_STATIC_ASSERT_H_
+#define SRC_TINT_AST_STATIC_ASSERT_H_
+
+#include "src/tint/ast/statement.h"
+#include "src/tint/ast/variable.h"
+
+namespace tint::ast {
+
+/// A `static_assert` statement
+class StaticAssert final : public Castable<StaticAssert, Statement> {
+ public:
+ /// Constructor
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param source the variable statement source
+ /// @param condition the assertion condition
+ StaticAssert(ProgramID pid, NodeID nid, const Source& source, const Expression* condition);
+
+ /// Move constructor
+ StaticAssert(StaticAssert&&);
+
+ /// Destructor
+ ~StaticAssert() override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext` `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const StaticAssert* Clone(CloneContext* ctx) const override;
+
+ /// The assertion condition
+ const Expression* const condition;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_STATIC_ASSERT_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/static_assert_test.cc b/chromium/third_party/dawn/src/tint/ast/static_assert_test.cc
new file mode 100644
index 00000000000..48bee481411
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/static_assert_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/static_assert.h"
+
+#include "gtest/gtest-spi.h"
+#include "src/tint/ast/test_helper.h"
+
+namespace tint::ast {
+namespace {
+
+using StaticAssertTest = TestHelper;
+
+TEST_F(StaticAssertTest, Creation) {
+ auto* cond = Expr(true);
+ auto* stmt = StaticAssert(cond);
+ EXPECT_EQ(stmt->condition, cond);
+}
+
+TEST_F(StaticAssertTest, Creation_WithSource) {
+ auto* cond = Expr(true);
+ auto* stmt = StaticAssert(Source{{20, 2}}, cond);
+ auto src = stmt->source;
+ EXPECT_EQ(src.range.begin.line, 20u);
+ EXPECT_EQ(src.range.begin.column, 2u);
+}
+
+TEST_F(StaticAssertTest, IsStaticAssert) {
+ auto* cond = Expr(true);
+
+ auto* stmt = StaticAssert(cond);
+ EXPECT_TRUE(stmt->Is<ast::StaticAssert>());
+}
+
+TEST_F(StaticAssertTest, Assert_Null_Condition) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b;
+ b.StaticAssert(nullptr);
+ },
+ "internal compiler error");
+}
+
+TEST_F(StaticAssertTest, Assert_DifferentProgramID_Condition) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b1;
+ ProgramBuilder b2;
+ b1.StaticAssert(b2.Expr(i32(123)));
+ },
+ "internal compiler error");
+}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class.cc b/chromium/third_party/dawn/src/tint/ast/storage_class.cc
index 31612717d61..450067b950a 100644
--- a/chromium/third_party/dawn/src/tint/ast/storage_class.cc
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class.cc
@@ -12,38 +12,69 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/storage_class.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
#include "src/tint/ast/storage_class.h"
namespace tint::ast {
-const char* ToString(StorageClass sc) {
- switch (sc) {
+/// ParseStorageClass parses a StorageClass from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or StorageClass::kInvalid if the string could not be parsed.
+StorageClass ParseStorageClass(std::string_view str) {
+ if (str == "function") {
+ return StorageClass::kFunction;
+ }
+ if (str == "private") {
+ return StorageClass::kPrivate;
+ }
+ if (str == "workgroup") {
+ return StorageClass::kWorkgroup;
+ }
+ if (str == "uniform") {
+ return StorageClass::kUniform;
+ }
+ if (str == "storage") {
+ return StorageClass::kStorage;
+ }
+ if (str == "push_constant") {
+ return StorageClass::kPushConstant;
+ }
+ return StorageClass::kInvalid;
+}
+
+std::ostream& operator<<(std::ostream& out, StorageClass value) {
+ switch (value) {
case StorageClass::kInvalid:
- return "invalid";
+ return out << "invalid";
case StorageClass::kNone:
- return "none";
- case StorageClass::kInput:
- return "in";
- case StorageClass::kOutput:
- return "out";
- case StorageClass::kUniform:
- return "uniform";
+ return out << "none";
+ case StorageClass::kFunction:
+ return out << "function";
+ case StorageClass::kPrivate:
+ return out << "private";
case StorageClass::kWorkgroup:
- return "workgroup";
- case StorageClass::kHandle:
- return "handle";
+ return out << "workgroup";
+ case StorageClass::kUniform:
+ return out << "uniform";
case StorageClass::kStorage:
- return "storage";
- case StorageClass::kPrivate:
- return "private";
- case StorageClass::kFunction:
- return "function";
+ return out << "storage";
+ case StorageClass::kPushConstant:
+ return out << "push_constant";
+ case StorageClass::kHandle:
+ return out << "handle";
+ case StorageClass::kIn:
+ return out << "in";
+ case StorageClass::kOut:
+ return out << "out";
}
- return "<unknown>";
-}
-std::ostream& operator<<(std::ostream& out, StorageClass sc) {
- out << ToString(sc);
- return out;
+ return out << "<unknown>";
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/storage_class.cc.tmpl
new file mode 100644
index 00000000000..e2903b7ea26
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class.cc.tmpl
@@ -0,0 +1,25 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class.cc
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#include "src/tint/ast/storage_class.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class.h b/chromium/third_party/dawn/src/tint/ast/storage_class.h
index d4e64792d03..43e41e165ba 100644
--- a/chromium/third_party/dawn/src/tint/ast/storage_class.h
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Tint Authors.
+// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,6 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/storage_class.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
#ifndef SRC_TINT_AST_STORAGE_CLASS_H_
#define SRC_TINT_AST_STORAGE_CLASS_H_
@@ -21,34 +29,37 @@ namespace tint::ast {
/// Storage class of a given pointer.
enum class StorageClass {
- kInvalid = -1,
- kNone,
- kInput,
- kOutput,
- kUniform,
+ kInvalid,
+ kNone, // Tint-internal enum entry - not parsed
+ kFunction,
+ kPrivate,
kWorkgroup,
- kHandle,
+ kUniform,
kStorage,
- kPrivate,
- kFunction
+ kPushConstant,
+ kHandle, // Tint-internal enum entry - not parsed
+ kIn, // Tint-internal enum entry - not parsed
+ kOut, // Tint-internal enum entry - not parsed
};
+/// @param out the std::ostream to write to
+/// @param value the StorageClass
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, StorageClass value);
+
+/// ParseStorageClass parses a StorageClass from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or StorageClass::kInvalid if the string could not be parsed.
+StorageClass ParseStorageClass(std::string_view str);
+
/// @returns true if the StorageClass is host-shareable
/// @param sc the StorageClass
/// @see https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable
inline bool IsHostShareable(StorageClass sc) {
- return sc == ast::StorageClass::kUniform || sc == ast::StorageClass::kStorage;
+ return sc == ast::StorageClass::kUniform || sc == ast::StorageClass::kStorage ||
+ sc == ast::StorageClass::kPushConstant;
}
-/// @param sc the StorageClass
-/// @return the name of the given storage class
-const char* ToString(StorageClass sc);
-
-/// @param out the std::ostream to write to
-/// @param sc the StorageClass
-/// @return the std::ostream so calls can be chained
-std::ostream& operator<<(std::ostream& out, StorageClass sc);
-
} // namespace tint::ast
#endif // SRC_TINT_AST_STORAGE_CLASS_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class.h.tmpl b/chromium/third_party/dawn/src/tint/ast/storage_class.h.tmpl
new file mode 100644
index 00000000000..c21d6f6034a
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class.h.tmpl
@@ -0,0 +1,37 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class.h
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#ifndef SRC_TINT_AST_STORAGE_CLASS_H_
+#define SRC_TINT_AST_STORAGE_CLASS_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Storage class of a given pointer.
+{{ Eval "DeclareEnum" $enum}}
+
+/// @returns true if the StorageClass is host-shareable
+/// @param sc the StorageClass
+/// @see https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable
+inline bool IsHostShareable(StorageClass sc) {
+ return sc == ast::StorageClass::kUniform || sc == ast::StorageClass::kStorage ||
+ sc == ast::StorageClass::kPushConstant;
+}
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_STORAGE_CLASS_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc b/chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc
new file mode 100644
index 00000000000..00095c2a62a
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc
@@ -0,0 +1,88 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/storage_class_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/storage_class.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void StorageClassParser(::benchmark::State& state) {
+ std::array kStrings{
+ "fccnctin",
+ "ucti3",
+ "functVon",
+ "function",
+ "1unction",
+ "unJtqqon",
+ "llun77tion",
+ "ppqqivtHH",
+ "prcv",
+ "bivaGe",
+ "private",
+ "priviive",
+ "8WWivate",
+ "pxxvate",
+ "wXkgrggup",
+ "worXVup",
+ "3orkgroup",
+ "workgroup",
+ "workgroEp",
+ "woTTPkroup",
+ "ddorkroxxp",
+ "u44iform",
+ "unSSfoVVm",
+ "RniR22m",
+ "uniform",
+ "uFfo9m",
+ "uniorm",
+ "VOORRHrm",
+ "straye",
+ "llntrrr77ge",
+ "stor4g00",
+ "storage",
+ "trooe",
+ "zzrage",
+ "siioppa1",
+ "puXXh_constant",
+ "pusII9_nn55nstant",
+ "YusHH_coaastSSrnt",
+ "push_constant",
+ "pushonkkHan",
+ "jush_consgRt",
+ "puh_cobsant",
+ };
+ for (auto _ : state) {
+ for (auto& str : kStrings) {
+ auto result = ParseStorageClass(str);
+ benchmark::DoNotOptimize(result);
+ }
+ }
+}
+
+BENCHMARK(StorageClassParser);
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc.tmpl
new file mode 100644
index 00000000000..d9ea8cb0b27
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class_bench.cc.tmpl
@@ -0,0 +1,29 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class_bench.cc
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#include "src/tint/ast/storage_class.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class_test.cc b/chromium/third_party/dawn/src/tint/ast/storage_class_test.cc
new file mode 100644
index 00000000000..1d12d459976
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class_test.cc
@@ -0,0 +1,86 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/storage_class_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/storage_class.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+namespace parse_print_tests {
+
+struct Case {
+ const char* string;
+ StorageClass value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+ return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+ {"function", StorageClass::kFunction}, {"private", StorageClass::kPrivate},
+ {"workgroup", StorageClass::kWorkgroup}, {"uniform", StorageClass::kUniform},
+ {"storage", StorageClass::kStorage}, {"push_constant", StorageClass::kPushConstant},
+};
+
+static constexpr Case kInvalidCases[] = {
+ {"fccnctin", StorageClass::kInvalid}, {"ucti3", StorageClass::kInvalid},
+ {"functVon", StorageClass::kInvalid}, {"priv1te", StorageClass::kInvalid},
+ {"pqiJate", StorageClass::kInvalid}, {"privat7ll", StorageClass::kInvalid},
+ {"workroppqHH", StorageClass::kInvalid}, {"workru", StorageClass::kInvalid},
+ {"wbkgGoup", StorageClass::kInvalid}, {"unifiivm", StorageClass::kInvalid},
+ {"8WWiform", StorageClass::kInvalid}, {"uxxform", StorageClass::kInvalid},
+ {"sXraggg", StorageClass::kInvalid}, {"traXe", StorageClass::kInvalid},
+ {"stor3ge", StorageClass::kInvalid}, {"push_constanE", StorageClass::kInvalid},
+ {"push_TTPnstant", StorageClass::kInvalid}, {"puxxdh_constan", StorageClass::kInvalid},
+};
+
+using StorageClassParseTest = testing::TestWithParam<Case>;
+
+TEST_P(StorageClassParseTest, Parse) {
+ const char* string = GetParam().string;
+ StorageClass expect = GetParam().value;
+ EXPECT_EQ(expect, ParseStorageClass(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, StorageClassParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, StorageClassParseTest, testing::ValuesIn(kInvalidCases));
+
+using StorageClassPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(StorageClassPrintTest, Print) {
+ StorageClass value = GetParam().value;
+ const char* expect = GetParam().string;
+ EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, StorageClassPrintTest, testing::ValuesIn(kValidCases));
+
+} // namespace parse_print_tests
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_class_test.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/storage_class_test.cc.tmpl
new file mode 100644
index 00000000000..3696aab3cb1
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/storage_class_test.cc.tmpl
@@ -0,0 +1,30 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class_test.cc
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#include "src/tint/ast/storage_class.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_texture.cc b/chromium/third_party/dawn/src/tint/ast/storage_texture.cc
index ccc250d9fbc..9c223c3336f 100644
--- a/chromium/third_party/dawn/src/tint/ast/storage_texture.cc
+++ b/chromium/third_party/dawn/src/tint/ast/storage_texture.cc
@@ -23,72 +23,14 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::StorageTexture);
namespace tint::ast {
-// Note, these names match the names in the WGSL spec. This behaviour is used
-// in the WGSL writer to emit the texture format names.
-std::ostream& operator<<(std::ostream& out, TexelFormat format) {
- switch (format) {
- case TexelFormat::kNone:
- out << "none";
- break;
- case TexelFormat::kR32Uint:
- out << "r32uint";
- break;
- case TexelFormat::kR32Sint:
- out << "r32sint";
- break;
- case TexelFormat::kR32Float:
- out << "r32float";
- break;
- case TexelFormat::kRgba8Unorm:
- out << "rgba8unorm";
- break;
- case TexelFormat::kRgba8Snorm:
- out << "rgba8snorm";
- break;
- case TexelFormat::kRgba8Uint:
- out << "rgba8uint";
- break;
- case TexelFormat::kRgba8Sint:
- out << "rgba8sint";
- break;
- case TexelFormat::kRg32Uint:
- out << "rg32uint";
- break;
- case TexelFormat::kRg32Sint:
- out << "rg32sint";
- break;
- case TexelFormat::kRg32Float:
- out << "rg32float";
- break;
- case TexelFormat::kRgba16Uint:
- out << "rgba16uint";
- break;
- case TexelFormat::kRgba16Sint:
- out << "rgba16sint";
- break;
- case TexelFormat::kRgba16Float:
- out << "rgba16float";
- break;
- case TexelFormat::kRgba32Uint:
- out << "rgba32uint";
- break;
- case TexelFormat::kRgba32Sint:
- out << "rgba32sint";
- break;
- case TexelFormat::kRgba32Float:
- out << "rgba32float";
- break;
- }
- return out;
-}
-
StorageTexture::StorageTexture(ProgramID pid,
+ NodeID nid,
const Source& src,
TextureDimension d,
TexelFormat fmt,
const Type* subtype,
Access ac)
- : Base(pid, src, d), format(fmt), type(subtype), access(ac) {}
+ : Base(pid, nid, src, d), format(fmt), type(subtype), access(ac) {}
StorageTexture::StorageTexture(StorageTexture&&) = default;
@@ -134,7 +76,7 @@ Type* StorageTexture::SubtypeFor(TexelFormat format, ProgramBuilder& builder) {
return builder.create<F32>();
}
- case TexelFormat::kNone:
+ case TexelFormat::kInvalid:
break;
}
diff --git a/chromium/third_party/dawn/src/tint/ast/storage_texture.h b/chromium/third_party/dawn/src/tint/ast/storage_texture.h
index 3cf779e244d..9ae7b95416c 100644
--- a/chromium/third_party/dawn/src/tint/ast/storage_texture.h
+++ b/chromium/third_party/dawn/src/tint/ast/storage_texture.h
@@ -18,47 +18,24 @@
#include <string>
#include "src/tint/ast/access.h"
+#include "src/tint/ast/texel_format.h"
#include "src/tint/ast/texture.h"
namespace tint::ast {
-/// The texel format in the storage texture
-enum class TexelFormat {
- kNone = -1,
- kRgba8Unorm,
- kRgba8Snorm,
- kRgba8Uint,
- kRgba8Sint,
- kRgba16Uint,
- kRgba16Sint,
- kRgba16Float,
- kR32Uint,
- kR32Sint,
- kR32Float,
- kRg32Uint,
- kRg32Sint,
- kRg32Float,
- kRgba32Uint,
- kRgba32Sint,
- kRgba32Float,
-};
-
-/// @param out the std::ostream to write to
-/// @param format the TexelFormat
-/// @return the std::ostream so calls can be chained
-std::ostream& operator<<(std::ostream& out, TexelFormat format);
-
/// A storage texture type.
class StorageTexture final : public Castable<StorageTexture, Texture> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param dim the dimensionality of the texture
/// @param format the image format of the texture
/// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
/// @param access_control the access control for the texture.
StorageTexture(ProgramID pid,
+ NodeID nid,
const Source& src,
TextureDimension dim,
TexelFormat format,
diff --git a/chromium/third_party/dawn/src/tint/ast/stride_attribute.cc b/chromium/third_party/dawn/src/tint/ast/stride_attribute.cc
index 14a07333193..408ee44176a 100644
--- a/chromium/third_party/dawn/src/tint/ast/stride_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/stride_attribute.cc
@@ -22,8 +22,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::StrideAttribute);
namespace tint::ast {
-StrideAttribute::StrideAttribute(ProgramID pid, const Source& src, uint32_t s)
- : Base(pid, src), stride(s) {}
+StrideAttribute::StrideAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t s)
+ : Base(pid, nid, src), stride(s) {}
StrideAttribute::~StrideAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/stride_attribute.h b/chromium/third_party/dawn/src/tint/ast/stride_attribute.h
index 4315f217487..90146774d1d 100644
--- a/chromium/third_party/dawn/src/tint/ast/stride_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/stride_attribute.h
@@ -28,9 +28,10 @@ class StrideAttribute final : public Castable<StrideAttribute, Attribute> {
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param stride the stride value
- StrideAttribute(ProgramID pid, const Source& src, uint32_t stride);
+ StrideAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t stride);
~StrideAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/stride_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/stride_attribute_test.cc
index 61c4fb5dadb..eb190341c67 100644
--- a/chromium/third_party/dawn/src/tint/ast/stride_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/stride_attribute_test.cc
@@ -20,13 +20,13 @@ namespace {
using StrideAttributeTest = TestHelper;
TEST_F(StrideAttributeTest, Creation) {
- auto* d = create<StrideAttribute>(2);
+ auto* d = create<StrideAttribute>(2u);
EXPECT_EQ(2u, d->stride);
}
TEST_F(StrideAttributeTest, Source) {
auto* d = create<StrideAttribute>(
- Source{Source::Range{Source::Location{1, 2}, Source::Location{3, 4}}}, 2);
+ Source{Source::Range{Source::Location{1, 2}, Source::Location{3, 4}}}, 2u);
EXPECT_EQ(d->source.range.begin.line, 1u);
EXPECT_EQ(d->source.range.begin.column, 2u);
EXPECT_EQ(d->source.range.end.line, 3u);
diff --git a/chromium/third_party/dawn/src/tint/ast/struct.cc b/chromium/third_party/dawn/src/tint/ast/struct.cc
index 19a30de9264..c2d9002e720 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct.cc
@@ -22,8 +22,13 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Struct);
namespace tint::ast {
-Struct::Struct(ProgramID pid, const Source& src, Symbol n, StructMemberList m, AttributeList attrs)
- : Base(pid, src, n), members(std::move(m)), attributes(std::move(attrs)) {
+Struct::Struct(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ Symbol n,
+ utils::VectorRef<const ast::StructMember*> m,
+ utils::VectorRef<const ast::Attribute*> attrs)
+ : Base(pid, nid, src, n), members(std::move(m)), attributes(std::move(attrs)) {
for (auto* mem : members) {
TINT_ASSERT(AST, mem);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, mem, program_id);
@@ -44,7 +49,7 @@ const Struct* Struct::Clone(CloneContext* ctx) const {
auto n = ctx->Clone(name);
auto mem = ctx->Clone(members);
auto attrs = ctx->Clone(attributes);
- return ctx->dst->create<Struct>(src, n, mem, attrs);
+ return ctx->dst->create<Struct>(src, n, std::move(mem), std::move(attrs));
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/struct.h b/chromium/third_party/dawn/src/tint/ast/struct.h
index 5c28b4cd3a4..3e3e5cf17c2 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct.h
+++ b/chromium/third_party/dawn/src/tint/ast/struct.h
@@ -21,6 +21,7 @@
#include "src/tint/ast/attribute.h"
#include "src/tint/ast/struct_member.h"
#include "src/tint/ast/type_decl.h"
+#include "src/tint/utils/vector.h"
namespace tint::ast {
@@ -29,15 +30,17 @@ class Struct final : public Castable<Struct, TypeDecl> {
public:
/// Create a new struct statement
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node for the import statement
/// @param name The name of the structure
/// @param members The struct members
/// @param attributes The struct attributes
Struct(ProgramID pid,
+ NodeID nid,
const Source& src,
Symbol name,
- StructMemberList members,
- AttributeList attributes);
+ utils::VectorRef<const ast::StructMember*> members,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Move constructor
Struct(Struct&&);
@@ -50,10 +53,10 @@ class Struct final : public Castable<Struct, TypeDecl> {
const Struct* Clone(CloneContext* ctx) const override;
/// The members
- const StructMemberList members;
+ const utils::Vector<const ast::StructMember*, 8> members;
/// The struct attributes
- const AttributeList attributes;
+ const utils::Vector<const ast::Attribute*, 4> attributes;
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member.cc b/chromium/third_party/dawn/src/tint/ast/struct_member.cc
index 611348420d4..22de0444568 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member.cc
@@ -21,11 +21,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::StructMember);
namespace tint::ast {
StructMember::StructMember(ProgramID pid,
+ NodeID nid,
const Source& src,
const Symbol& sym,
const ast::Type* ty,
- AttributeList attrs)
- : Base(pid, src), symbol(sym), type(ty), attributes(std::move(attrs)) {
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src), symbol(sym), type(ty), attributes(std::move(attrs)) {
TINT_ASSERT(AST, type);
TINT_ASSERT(AST, symbol.IsValid());
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
@@ -45,7 +46,7 @@ const StructMember* StructMember::Clone(CloneContext* ctx) const {
auto sym = ctx->Clone(symbol);
auto* ty = ctx->Clone(type);
auto attrs = ctx->Clone(attributes);
- return ctx->dst->create<StructMember>(src, sym, ty, attrs);
+ return ctx->dst->create<StructMember>(src, sym, ty, std::move(attrs));
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member.h b/chromium/third_party/dawn/src/tint/ast/struct_member.h
index 022a34cafe4..fc616d74c4e 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member.h
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member.h
@@ -16,7 +16,6 @@
#define SRC_TINT_AST_STRUCT_MEMBER_H_
#include <utility>
-#include <vector>
#include "src/tint/ast/attribute.h"
@@ -32,15 +31,17 @@ class StructMember final : public Castable<StructMember, Node> {
public:
/// Create a new struct member statement
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node for the struct member statement
/// @param sym The struct member symbol
/// @param type The struct member type
/// @param attributes The struct member attributes
StructMember(ProgramID pid,
+ NodeID nid,
const Source& src,
const Symbol& sym,
const ast::Type* type,
- AttributeList attributes);
+ utils::VectorRef<const Attribute*> attributes);
/// Move constructor
StructMember(StructMember&&);
@@ -59,12 +60,9 @@ class StructMember final : public Castable<StructMember, Node> {
const ast::Type* const type;
/// The attributes
- const AttributeList attributes;
+ const utils::Vector<const Attribute*, 4> attributes;
};
-/// A list of struct members
-using StructMemberList = std::vector<const StructMember*>;
-
} // namespace tint::ast
#endif // SRC_TINT_AST_STRUCT_MEMBER_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.cc b/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.cc
index f586e7eea7d..d8ed4fcf3c6 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.cc
@@ -23,8 +23,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::StructMemberAlignAttribute);
namespace tint::ast {
-StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid, const Source& src, uint32_t a)
- : Base(pid, src), align(a) {}
+StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ uint32_t a)
+ : Base(pid, nid, src), align(a) {}
StructMemberAlignAttribute::~StructMemberAlignAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.h b/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.h
index 10a6507d47f..efff21b203a 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute.h
@@ -27,9 +27,10 @@ class StructMemberAlignAttribute final : public Castable<StructMemberAlignAttrib
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param align the align value
- StructMemberAlignAttribute(ProgramID pid, const Source& src, uint32_t align);
+ StructMemberAlignAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t align);
~StructMemberAlignAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute_test.cc
index 5b4ff487a30..ba4d1bbb095 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_align_attribute_test.cc
@@ -22,7 +22,7 @@ namespace {
using StructMemberAlignAttributeTest = TestHelper;
TEST_F(StructMemberAlignAttributeTest, Creation) {
- auto* d = create<StructMemberAlignAttribute>(2);
+ auto* d = create<StructMemberAlignAttribute>(2u);
EXPECT_EQ(2u, d->align);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.cc b/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.cc
index 0a33127bf99..48d73336b3e 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.cc
@@ -23,9 +23,10 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::StructMemberOffsetAttribute);
namespace tint::ast {
StructMemberOffsetAttribute::StructMemberOffsetAttribute(ProgramID pid,
+ NodeID nid,
const Source& src,
uint32_t o)
- : Base(pid, src), offset(o) {}
+ : Base(pid, nid, src), offset(o) {}
StructMemberOffsetAttribute::~StructMemberOffsetAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.h b/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.h
index 92cc68ec1da..790927eaa86 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute.h
@@ -35,9 +35,10 @@ class StructMemberOffsetAttribute final : public Castable<StructMemberOffsetAttr
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param offset the offset value
- StructMemberOffsetAttribute(ProgramID pid, const Source& src, uint32_t offset);
+ StructMemberOffsetAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t offset);
~StructMemberOffsetAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute_test.cc
index 3c0eb41c02f..9d81ffb1c45 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_offset_attribute_test.cc
@@ -20,7 +20,7 @@ namespace {
using StructMemberOffsetAttributeTest = TestHelper;
TEST_F(StructMemberOffsetAttributeTest, Creation) {
- auto* d = create<StructMemberOffsetAttribute>(2);
+ auto* d = create<StructMemberOffsetAttribute>(2u);
EXPECT_EQ(2u, d->offset);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.cc b/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.cc
index a7f291b63a9..391907877de 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.cc
@@ -23,8 +23,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::StructMemberSizeAttribute);
namespace tint::ast {
-StructMemberSizeAttribute::StructMemberSizeAttribute(ProgramID pid, const Source& src, uint32_t sz)
- : Base(pid, src), size(sz) {}
+StructMemberSizeAttribute::StructMemberSizeAttribute(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ uint32_t sz)
+ : Base(pid, nid, src), size(sz) {}
StructMemberSizeAttribute::~StructMemberSizeAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.h b/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.h
index 0c4ddd6c056..5649e2eaa39 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute.h
@@ -27,9 +27,10 @@ class StructMemberSizeAttribute final : public Castable<StructMemberSizeAttribut
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param size the size value
- StructMemberSizeAttribute(ProgramID pid, const Source& src, uint32_t size);
+ StructMemberSizeAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t size);
~StructMemberSizeAttribute() override;
/// @returns the WGSL name for the attribute
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute_test.cc b/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute_test.cc
index a9d4637510c..a82d53a0b01 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_size_attribute_test.cc
@@ -22,7 +22,7 @@ namespace {
using StructMemberSizeAttributeTest = TestHelper;
TEST_F(StructMemberSizeAttributeTest, Creation) {
- auto* d = create<StructMemberSizeAttribute>(2);
+ auto* d = create<StructMemberSizeAttribute>(2u);
EXPECT_EQ(2u, d->size);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_member_test.cc b/chromium/third_party/dawn/src/tint/ast/struct_member_test.cc
index cec82ae03b0..69772f4e14e 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_member_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_member_test.cc
@@ -21,10 +21,10 @@ namespace {
using StructMemberTest = TestHelper;
TEST_F(StructMemberTest, Creation) {
- auto* st = Member("a", ty.i32(), {MemberSize(4)});
+ auto* st = Member("a", ty.i32(), utils::Vector{MemberSize(4)});
EXPECT_EQ(st->symbol, Symbol(1, ID()));
EXPECT_TRUE(st->type->Is<ast::I32>());
- EXPECT_EQ(st->attributes.size(), 1u);
+ EXPECT_EQ(st->attributes.Length(), 1u);
EXPECT_TRUE(st->attributes[0]->Is<StructMemberSizeAttribute>());
EXPECT_EQ(st->source.range.begin.line, 0u);
EXPECT_EQ(st->source.range.begin.column, 0u);
@@ -37,7 +37,7 @@ TEST_F(StructMemberTest, CreationWithSource) {
ty.i32());
EXPECT_EQ(st->symbol, Symbol(1, ID()));
EXPECT_TRUE(st->type->Is<ast::I32>());
- EXPECT_EQ(st->attributes.size(), 0u);
+ EXPECT_EQ(st->attributes.Length(), 0u);
EXPECT_EQ(st->source.range.begin.line, 27u);
EXPECT_EQ(st->source.range.begin.column, 4u);
EXPECT_EQ(st->source.range.end.line, 27u);
@@ -66,7 +66,7 @@ TEST_F(StructMemberTest, Assert_Null_Attribute) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.Member("a", b.ty.i32(), {b.MemberSize(4), nullptr});
+ b.Member("a", b.ty.i32(), utils::Vector{b.MemberSize(4), nullptr});
},
"internal compiler error");
}
@@ -76,7 +76,7 @@ TEST_F(StructMemberTest, Assert_DifferentProgramID_Symbol) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.Member(b2.Sym("a"), b1.ty.i32(), {b1.MemberSize(4)});
+ b1.Member(b2.Sym("a"), b1.ty.i32(), utils::Vector{b1.MemberSize(4)});
},
"internal compiler error");
}
@@ -86,7 +86,7 @@ TEST_F(StructMemberTest, Assert_DifferentProgramID_Attribute) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.Member("a", b1.ty.i32(), {b2.MemberSize(4)});
+ b1.Member("a", b1.ty.i32(), utils::Vector{b2.MemberSize(4)});
},
"internal compiler error");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/struct_test.cc b/chromium/third_party/dawn/src/tint/ast/struct_test.cc
index 895d501e5db..53ec9c8c6c1 100644
--- a/chromium/third_party/dawn/src/tint/ast/struct_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/struct_test.cc
@@ -36,10 +36,10 @@ using SpirvBlockAttribute = transform::AddSpirvBlockAttribute::SpirvBlockAttribu
TEST_F(AstStructTest, Creation) {
auto name = Sym("s");
- auto* s = create<Struct>(name, StructMemberList{Member("a", ty.i32())}, AttributeList{});
+ auto* s = create<Struct>(name, utils::Vector{Member("a", ty.i32())}, utils::Empty);
EXPECT_EQ(s->name, name);
- EXPECT_EQ(s->members.size(), 1u);
- EXPECT_TRUE(s->attributes.empty());
+ EXPECT_EQ(s->members.Length(), 1u);
+ EXPECT_TRUE(s->attributes.IsEmpty());
EXPECT_EQ(s->source.range.begin.line, 0u);
EXPECT_EQ(s->source.range.begin.column, 0u);
EXPECT_EQ(s->source.range.end.line, 0u);
@@ -48,13 +48,14 @@ TEST_F(AstStructTest, Creation) {
TEST_F(AstStructTest, Creation_WithAttributes) {
auto name = Sym("s");
- AttributeList attrs;
- attrs.push_back(ASTNodes().Create<SpirvBlockAttribute>(ID()));
- auto* s = create<Struct>(name, StructMemberList{Member("a", ty.i32())}, attrs);
+ auto* s = create<Struct>(name, utils::Vector{Member("a", ty.i32())},
+ utils::Vector{
+ ASTNodes().Create<SpirvBlockAttribute>(ID(), AllocateNodeID()),
+ });
EXPECT_EQ(s->name, name);
- EXPECT_EQ(s->members.size(), 1u);
- ASSERT_EQ(s->attributes.size(), 1u);
+ EXPECT_EQ(s->members.Length(), 1u);
+ ASSERT_EQ(s->attributes.Length(), 1u);
EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
EXPECT_EQ(s->source.range.begin.line, 0u);
EXPECT_EQ(s->source.range.begin.column, 0u);
@@ -64,13 +65,13 @@ TEST_F(AstStructTest, Creation_WithAttributes) {
TEST_F(AstStructTest, CreationWithSourceAndAttributes) {
auto name = Sym("s");
- auto* s =
- create<Struct>(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
- name, StructMemberList{Member("a", ty.i32())},
- AttributeList{ASTNodes().Create<SpirvBlockAttribute>(ID())});
+ auto* s = create<Struct>(
+ Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}}, name,
+ utils::Vector{Member("a", ty.i32())},
+ utils::Vector{ASTNodes().Create<SpirvBlockAttribute>(ID(), AllocateNodeID())});
EXPECT_EQ(s->name, name);
- EXPECT_EQ(s->members.size(), 1u);
- ASSERT_EQ(s->attributes.size(), 1u);
+ EXPECT_EQ(s->members.Length(), 1u);
+ ASSERT_EQ(s->attributes.Length(), 1u);
EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
EXPECT_EQ(s->source.range.begin.line, 27u);
EXPECT_EQ(s->source.range.begin.column, 4u);
@@ -82,8 +83,8 @@ TEST_F(AstStructTest, Assert_Null_StructMember) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<Struct>(b.Sym("S"), StructMemberList{b.Member("a", b.ty.i32()), nullptr},
- AttributeList{});
+ b.create<Struct>(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32()), nullptr},
+ utils::Empty);
},
"internal compiler error");
}
@@ -92,8 +93,8 @@ TEST_F(AstStructTest, Assert_Null_Attribute) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<Struct>(b.Sym("S"), StructMemberList{b.Member("a", b.ty.i32())},
- AttributeList{nullptr});
+ b.create<Struct>(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32())},
+ utils::Vector<const ast::Attribute*, 1>{nullptr});
},
"internal compiler error");
}
@@ -103,8 +104,8 @@ TEST_F(AstStructTest, Assert_DifferentProgramID_StructMember) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<Struct>(b1.Sym("S"), StructMemberList{b2.Member("a", b2.ty.i32())},
- AttributeList{});
+ b1.create<Struct>(b1.Sym("S"), utils::Vector{b2.Member("a", b2.ty.i32())},
+ utils::Empty);
},
"internal compiler error");
}
@@ -114,8 +115,9 @@ TEST_F(AstStructTest, Assert_DifferentProgramID_Attribute) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<Struct>(b1.Sym("S"), StructMemberList{b1.Member("a", b1.ty.i32())},
- AttributeList{b2.ASTNodes().Create<SpirvBlockAttribute>(b2.ID())});
+ b1.create<Struct>(b1.Sym("S"), utils::Vector{b1.Member("a", b1.ty.i32())},
+ utils::Vector{b2.ASTNodes().Create<SpirvBlockAttribute>(
+ b2.ID(), b2.AllocateNodeID())});
},
"internal compiler error");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/switch_statement.cc b/chromium/third_party/dawn/src/tint/ast/switch_statement.cc
index 08095a109c3..1cdf8a4ea09 100644
--- a/chromium/third_party/dawn/src/tint/ast/switch_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/switch_statement.cc
@@ -14,6 +14,8 @@
#include "src/tint/ast/switch_statement.h"
+#include <utility>
+
#include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::SwitchStatement);
@@ -21,10 +23,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::SwitchStatement);
namespace tint::ast {
SwitchStatement::SwitchStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* cond,
- CaseStatementList b)
- : Base(pid, src), condition(cond), body(b) {
+ utils::VectorRef<const CaseStatement*> b)
+ : Base(pid, nid, src), condition(cond), body(std::move(b)) {
TINT_ASSERT(AST, condition);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
for (auto* stmt : body) {
@@ -42,7 +45,7 @@ const SwitchStatement* SwitchStatement::Clone(CloneContext* ctx) const {
auto src = ctx->Clone(source);
auto* cond = ctx->Clone(condition);
auto b = ctx->Clone(body);
- return ctx->dst->create<SwitchStatement>(src, cond, b);
+ return ctx->dst->create<SwitchStatement>(src, cond, std::move(b));
}
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/switch_statement.h b/chromium/third_party/dawn/src/tint/ast/switch_statement.h
index 5ac13b7b3ed..82a9aa4d54b 100644
--- a/chromium/third_party/dawn/src/tint/ast/switch_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/switch_statement.h
@@ -25,13 +25,15 @@ class SwitchStatement final : public Castable<SwitchStatement, Statement> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param condition the switch condition
/// @param body the switch body
SwitchStatement(ProgramID pid,
+ NodeID nid,
const Source& src,
const Expression* condition,
- CaseStatementList body);
+ utils::VectorRef<const CaseStatement*> body);
/// Move constructor
SwitchStatement(SwitchStatement&&);
~SwitchStatement() override;
@@ -49,7 +51,7 @@ class SwitchStatement final : public Castable<SwitchStatement, Statement> {
const Expression* const condition;
/// The Switch body
- const CaseStatementList body;
+ const utils::Vector<const CaseStatement*, 4> body;
SwitchStatement(const SwitchStatement&) = delete;
};
diff --git a/chromium/third_party/dawn/src/tint/ast/switch_statement_test.cc b/chromium/third_party/dawn/src/tint/ast/switch_statement_test.cc
index 19d1cfbaa9d..0f66c6113e2 100644
--- a/chromium/third_party/dawn/src/tint/ast/switch_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/switch_statement_test.cc
@@ -25,54 +25,47 @@ namespace {
using SwitchStatementTest = TestHelper;
TEST_F(SwitchStatementTest, Creation) {
- CaseSelectorList lit;
- lit.push_back(Expr(1_u));
-
+ auto* case_stmt = create<CaseStatement>(utils::Vector{Expr(1_u)}, Block());
auto* ident = Expr("ident");
- CaseStatementList body;
- auto* case_stmt = create<CaseStatement>(lit, Block());
- body.push_back(case_stmt);
+ utils::Vector body{case_stmt};
auto* stmt = create<SwitchStatement>(ident, body);
EXPECT_EQ(stmt->condition, ident);
- ASSERT_EQ(stmt->body.size(), 1u);
+ ASSERT_EQ(stmt->body.Length(), 1u);
EXPECT_EQ(stmt->body[0], case_stmt);
}
TEST_F(SwitchStatementTest, Creation_WithSource) {
auto* ident = Expr("ident");
-
- auto* stmt =
- create<SwitchStatement>(Source{Source::Location{20, 2}}, ident, CaseStatementList());
+ auto* stmt = create<SwitchStatement>(Source{Source::Location{20, 2}}, ident, utils::Empty);
auto src = stmt->source;
EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u);
}
TEST_F(SwitchStatementTest, IsSwitch) {
- CaseSelectorList lit;
- lit.push_back(Expr(2_i));
-
+ utils::Vector lit{Expr(2_i)};
auto* ident = Expr("ident");
- CaseStatementList body;
- body.push_back(create<CaseStatement>(lit, Block()));
+ utils::Vector body{create<CaseStatement>(lit, Block())};
auto* stmt = create<SwitchStatement>(ident, body);
EXPECT_TRUE(stmt->Is<SwitchStatement>());
}
TEST_F(SwitchStatementTest, Assert_Null_Condition) {
+ using CaseStatementList = utils::Vector<const ast::CaseStatement*, 2>;
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
CaseStatementList cases;
- cases.push_back(b.create<CaseStatement>(CaseSelectorList{b.Expr(1_i)}, b.Block()));
+ cases.Push(b.create<CaseStatement>(utils::Vector{b.Expr(1_i)}, b.Block()));
b.create<SwitchStatement>(nullptr, cases);
},
"internal compiler error");
}
TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) {
+ using CaseStatementList = utils::Vector<const ast::CaseStatement*, 2>;
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
@@ -86,9 +79,9 @@ TEST_F(SwitchStatementTest, Assert_DifferentProgramID_Condition) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<SwitchStatement>(b2.Expr(true), CaseStatementList{
+ b1.create<SwitchStatement>(b2.Expr(true), utils::Vector{
b1.create<CaseStatement>(
- CaseSelectorList{
+ utils::Vector{
b1.Expr(1_i),
},
b1.Block()),
@@ -102,9 +95,9 @@ TEST_F(SwitchStatementTest, Assert_DifferentProgramID_CaseStatement) {
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<SwitchStatement>(b1.Expr(true), CaseStatementList{
+ b1.create<SwitchStatement>(b1.Expr(true), utils::Vector{
b2.create<CaseStatement>(
- CaseSelectorList{
+ utils::Vector{
b2.Expr(1_i),
},
b2.Block()),
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format.cc b/chromium/third_party/dawn/src/tint/ast/texel_format.cc
new file mode 100644
index 00000000000..cfac9f1757a
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format.cc
@@ -0,0 +1,122 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/texel_format.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/texel_format.h"
+
+namespace tint::ast {
+
+/// ParseTexelFormat parses a TexelFormat from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or TexelFormat::kInvalid if the string could not be parsed.
+TexelFormat ParseTexelFormat(std::string_view str) {
+ if (str == "rgba8unorm") {
+ return TexelFormat::kRgba8Unorm;
+ }
+ if (str == "rgba8snorm") {
+ return TexelFormat::kRgba8Snorm;
+ }
+ if (str == "rgba8uint") {
+ return TexelFormat::kRgba8Uint;
+ }
+ if (str == "rgba8sint") {
+ return TexelFormat::kRgba8Sint;
+ }
+ if (str == "rgba16uint") {
+ return TexelFormat::kRgba16Uint;
+ }
+ if (str == "rgba16sint") {
+ return TexelFormat::kRgba16Sint;
+ }
+ if (str == "rgba16float") {
+ return TexelFormat::kRgba16Float;
+ }
+ if (str == "r32uint") {
+ return TexelFormat::kR32Uint;
+ }
+ if (str == "r32sint") {
+ return TexelFormat::kR32Sint;
+ }
+ if (str == "r32float") {
+ return TexelFormat::kR32Float;
+ }
+ if (str == "rg32uint") {
+ return TexelFormat::kRg32Uint;
+ }
+ if (str == "rg32sint") {
+ return TexelFormat::kRg32Sint;
+ }
+ if (str == "rg32float") {
+ return TexelFormat::kRg32Float;
+ }
+ if (str == "rgba32uint") {
+ return TexelFormat::kRgba32Uint;
+ }
+ if (str == "rgba32sint") {
+ return TexelFormat::kRgba32Sint;
+ }
+ if (str == "rgba32float") {
+ return TexelFormat::kRgba32Float;
+ }
+ return TexelFormat::kInvalid;
+}
+
+std::ostream& operator<<(std::ostream& out, TexelFormat value) {
+ switch (value) {
+ case TexelFormat::kInvalid:
+ return out << "invalid";
+ case TexelFormat::kRgba8Unorm:
+ return out << "rgba8unorm";
+ case TexelFormat::kRgba8Snorm:
+ return out << "rgba8snorm";
+ case TexelFormat::kRgba8Uint:
+ return out << "rgba8uint";
+ case TexelFormat::kRgba8Sint:
+ return out << "rgba8sint";
+ case TexelFormat::kRgba16Uint:
+ return out << "rgba16uint";
+ case TexelFormat::kRgba16Sint:
+ return out << "rgba16sint";
+ case TexelFormat::kRgba16Float:
+ return out << "rgba16float";
+ case TexelFormat::kR32Uint:
+ return out << "r32uint";
+ case TexelFormat::kR32Sint:
+ return out << "r32sint";
+ case TexelFormat::kR32Float:
+ return out << "r32float";
+ case TexelFormat::kRg32Uint:
+ return out << "rg32uint";
+ case TexelFormat::kRg32Sint:
+ return out << "rg32sint";
+ case TexelFormat::kRg32Float:
+ return out << "rg32float";
+ case TexelFormat::kRgba32Uint:
+ return out << "rgba32uint";
+ case TexelFormat::kRgba32Sint:
+ return out << "rgba32sint";
+ case TexelFormat::kRgba32Float:
+ return out << "rgba32float";
+ }
+ return out << "<unknown>";
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/texel_format.cc.tmpl
new file mode 100644
index 00000000000..cc9f769f022
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format.cc.tmpl
@@ -0,0 +1,22 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#include "src/tint/ast/texel_format.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format.h b/chromium/third_party/dawn/src/tint/ast/texel_format.h
new file mode 100644
index 00000000000..28119b3379c
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format.h
@@ -0,0 +1,63 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/texel_format.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_AST_TEXEL_FORMAT_H_
+#define SRC_TINT_AST_TEXEL_FORMAT_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Enumerator of texel formats
+enum class TexelFormat {
+ kInvalid,
+ kRgba8Unorm,
+ kRgba8Snorm,
+ kRgba8Uint,
+ kRgba8Sint,
+ kRgba16Uint,
+ kRgba16Sint,
+ kRgba16Float,
+ kR32Uint,
+ kR32Sint,
+ kR32Float,
+ kRg32Uint,
+ kRg32Sint,
+ kRg32Float,
+ kRgba32Uint,
+ kRgba32Sint,
+ kRgba32Float,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the TexelFormat
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, TexelFormat value);
+
+/// ParseTexelFormat parses a TexelFormat from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or TexelFormat::kInvalid if the string could not be parsed.
+TexelFormat ParseTexelFormat(std::string_view str);
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_TEXEL_FORMAT_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format.h.tmpl b/chromium/third_party/dawn/src/tint/ast/texel_format.h.tmpl
new file mode 100644
index 00000000000..e7454a0fe9a
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#ifndef SRC_TINT_AST_TEXEL_FORMAT_H_
+#define SRC_TINT_AST_TEXEL_FORMAT_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Enumerator of texel formats
+{{ Eval "DeclareEnum" $enum}}
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_TEXEL_FORMAT_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc b/chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc
new file mode 100644
index 00000000000..a17906a33ea
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc
@@ -0,0 +1,69 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/texel_format_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/texel_format.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void TexelFormatParser(::benchmark::State& state) {
+ std::array kStrings{
+ "rgbaunccrm", "rlbanr3", "rVba8unorm", "rgba8unorm", "rgba1unorm",
+ "rgbJqqnorm", "rgb7ll8unorm", "rgqqappnoHHm", "rv8scor", "rgbbGsnrm",
+ "rgba8snorm", "rgba8vniirm", "rg8a8snoWWm", "Mgbaxxnorm", "rXa8uggnt",
+ "rgbXVut", "3gba8uint", "rgba8uint", "rgba8uiEt", "rgTTPauint",
+ "ddgbauixxt", "44gba8sint", "VVgbaSSsint", "rba8si2Rt", "rgba8sint",
+ "r9bFsint", "rgba8int", "rgVROOsHnt", "ryba1uint", "r77ba1nnullrrt",
+ "rgb4006uint", "rgba16uint", "rb1uioot", "rga1uzznt", "r11b1uppiit",
+ "XXgba16sint", "IIgb9916nni55t", "rYbaSSrrsiHHat", "rgba16sint", "rbkk6Hit",
+ "jgba1sgRR", "rgbab6si", "rgba16fljat", "rgba6float", "rbq6float",
+ "rgba16float", "rgba1NNloat", "rgbvv6flot", "rgbaQQ6foat", "r3ffir",
+ "r32uijt", "rNNwuin8", "r32uint", "r32int", "rrr2uint",
+ "G32uint", "r32sinFF", "32st", "r3rrint", "r32sint",
+ "2sint", "D3siJJt", "r38n", "r211lk", "r32floa",
+ "r3flJat", "r32float", "r32fcoat", "r32floOt", "r32floKK_vtt",
+ "rxx32ui8", "Fg3qq__n", "rg32iqqt", "rg32uint", "rg333uin6",
+ "rtto62u9QQt", "rg366uin", "rOx2si6zz", "rg3yysint", "rHHsint",
+ "rg32sint", "qWW432snt", "rg3OOsnt", "g32siYt", "g32flo",
+ "rg32foaF", "rg32fwat", "rg32float", "G3fKoaff", "KKgq2float",
+ "rg32mmlo3t", "rgba32uit", "rqba3uint", "rgbabb2uin", "rgba32uint",
+ "rba32iint", "qgba32uiOt", "rgba32uiTTvv", "rgFFa32sint", "rg00Q2sPnt",
+ "rgbaP2sint", "rgba32sint", "rgb77s2sint", "rgba32sbbRRC", "rgbXX32sint",
+ "rOOOba3CCqoat", "rgbu32fsLt", "rgba3Xfloat", "rgba32float", "rba32float",
+ "qqb3float", "rgba32fl22at",
+ };
+ for (auto _ : state) {
+ for (auto& str : kStrings) {
+ auto result = ParseTexelFormat(str);
+ benchmark::DoNotOptimize(result);
+ }
+ }
+}
+
+BENCHMARK(TexelFormatParser);
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc.tmpl
new file mode 100644
index 00000000000..4df62b4e787
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format_bench.cc.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format_bench.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#include "src/tint/ast/texel_format.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format_test.cc b/chromium/third_party/dawn/src/tint/ast/texel_format_test.cc
new file mode 100644
index 00000000000..606d78f410e
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format_test.cc
@@ -0,0 +1,106 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+// src/tint/ast/texel_format_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/texel_format.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+namespace parse_print_tests {
+
+struct Case {
+ const char* string;
+ TexelFormat value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+ return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+ {"rgba8unorm", TexelFormat::kRgba8Unorm}, {"rgba8snorm", TexelFormat::kRgba8Snorm},
+ {"rgba8uint", TexelFormat::kRgba8Uint}, {"rgba8sint", TexelFormat::kRgba8Sint},
+ {"rgba16uint", TexelFormat::kRgba16Uint}, {"rgba16sint", TexelFormat::kRgba16Sint},
+ {"rgba16float", TexelFormat::kRgba16Float}, {"r32uint", TexelFormat::kR32Uint},
+ {"r32sint", TexelFormat::kR32Sint}, {"r32float", TexelFormat::kR32Float},
+ {"rg32uint", TexelFormat::kRg32Uint}, {"rg32sint", TexelFormat::kRg32Sint},
+ {"rg32float", TexelFormat::kRg32Float}, {"rgba32uint", TexelFormat::kRgba32Uint},
+ {"rgba32sint", TexelFormat::kRgba32Sint}, {"rgba32float", TexelFormat::kRgba32Float},
+};
+
+static constexpr Case kInvalidCases[] = {
+ {"rgbaunccrm", TexelFormat::kInvalid}, {"rlbanr3", TexelFormat::kInvalid},
+ {"rVba8unorm", TexelFormat::kInvalid}, {"rgba1snorm", TexelFormat::kInvalid},
+ {"rgbJqqnorm", TexelFormat::kInvalid}, {"rgb7ll8snorm", TexelFormat::kInvalid},
+ {"rgbauippqHH", TexelFormat::kInvalid}, {"rgbaun", TexelFormat::kInvalid},
+ {"rba8Gint", TexelFormat::kInvalid}, {"rgvia8sint", TexelFormat::kInvalid},
+ {"rgba8WWint", TexelFormat::kInvalid}, {"rgbasxxMt", TexelFormat::kInvalid},
+ {"rXba16ungg", TexelFormat::kInvalid}, {"rba1XuVt", TexelFormat::kInvalid},
+ {"rgba16uin3", TexelFormat::kInvalid}, {"rgba16sinE", TexelFormat::kInvalid},
+ {"TTgba16sPPn", TexelFormat::kInvalid}, {"rgbad6xxint", TexelFormat::kInvalid},
+ {"rgba446float", TexelFormat::kInvalid}, {"SSVVba16float", TexelFormat::kInvalid},
+ {"rgbRR6float", TexelFormat::kInvalid}, {"rFui9t", TexelFormat::kInvalid},
+ {"r32int", TexelFormat::kInvalid}, {"VOORRHnt", TexelFormat::kInvalid},
+ {"r3siyt", TexelFormat::kInvalid}, {"lln3rrs77nt", TexelFormat::kInvalid},
+ {"r32s4n00", TexelFormat::kInvalid}, {"32ooat", TexelFormat::kInvalid},
+ {"r32fzzt", TexelFormat::kInvalid}, {"r3iippl1a", TexelFormat::kInvalid},
+ {"XXg32uint", TexelFormat::kInvalid}, {"rII39955nnnt", TexelFormat::kInvalid},
+ {"aagHH2uinYSS", TexelFormat::kInvalid}, {"rkk3it", TexelFormat::kInvalid},
+ {"gj3sRRn", TexelFormat::kInvalid}, {"r3bsnt", TexelFormat::kInvalid},
+ {"rg32flojt", TexelFormat::kInvalid}, {"r32floa", TexelFormat::kInvalid},
+ {"rg32lot", TexelFormat::kInvalid}, {"rgb3uit", TexelFormat::kInvalid},
+ {"rgjj3uint", TexelFormat::kInvalid}, {"rgb2urnff", TexelFormat::kInvalid},
+ {"rgba32sijt", TexelFormat::kInvalid}, {"NNgba32ww2t", TexelFormat::kInvalid},
+ {"rgba32snt", TexelFormat::kInvalid}, {"rgba32rrloat", TexelFormat::kInvalid},
+ {"rgGa32float", TexelFormat::kInvalid}, {"FFgba32float", TexelFormat::kInvalid},
+};
+
+using TexelFormatParseTest = testing::TestWithParam<Case>;
+
+TEST_P(TexelFormatParseTest, Parse) {
+ const char* string = GetParam().string;
+ TexelFormat expect = GetParam().value;
+ EXPECT_EQ(expect, ParseTexelFormat(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, TexelFormatParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, TexelFormatParseTest, testing::ValuesIn(kInvalidCases));
+
+using TexelFormatPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(TexelFormatPrintTest, Print) {
+ TexelFormat value = GetParam().value;
+ const char* expect = GetParam().string;
+ EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, TexelFormatPrintTest, testing::ValuesIn(kValidCases));
+
+} // namespace parse_print_tests
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/texel_format_test.cc.tmpl b/chromium/third_party/dawn/src/tint/ast/texel_format_test.cc.tmpl
new file mode 100644
index 00000000000..304cfebd4e7
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/texel_format_test.cc.tmpl
@@ -0,0 +1,27 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#include "src/tint/ast/texel_format.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/texture.cc b/chromium/third_party/dawn/src/tint/ast/texture.cc
index 27eb094793d..f3c01dff29d 100644
--- a/chromium/third_party/dawn/src/tint/ast/texture.cc
+++ b/chromium/third_party/dawn/src/tint/ast/texture.cc
@@ -77,7 +77,8 @@ int NumCoordinateAxes(TextureDimension dim) {
return 0;
}
-Texture::Texture(ProgramID pid, const Source& src, TextureDimension d) : Base(pid, src), dim(d) {}
+Texture::Texture(ProgramID pid, NodeID nid, const Source& src, TextureDimension d)
+ : Base(pid, nid, src), dim(d) {}
Texture::Texture(Texture&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/texture.h b/chromium/third_party/dawn/src/tint/ast/texture.h
index 9a4199bcd78..fcfa3340ffc 100644
--- a/chromium/third_party/dawn/src/tint/ast/texture.h
+++ b/chromium/third_party/dawn/src/tint/ast/texture.h
@@ -65,9 +65,10 @@ class Texture : public Castable<Texture, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param dim the dimensionality of the texture
- Texture(ProgramID pid, const Source& src, TextureDimension dim);
+ Texture(ProgramID pid, NodeID nid, const Source& src, TextureDimension dim);
/// Move constructor
Texture(Texture&&);
~Texture() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/traverse_expressions.h b/chromium/third_party/dawn/src/tint/ast/traverse_expressions.h
index 59b00e98292..bcf0bfde1ce 100644
--- a/chromium/third_party/dawn/src/tint/ast/traverse_expressions.h
+++ b/chromium/third_party/dawn/src/tint/ast/traverse_expressions.h
@@ -26,6 +26,7 @@
#include "src/tint/ast/phony_expression.h"
#include "src/tint/ast/unary_op_expression.h"
#include "src/tint/utils/reverse.h"
+#include "src/tint/utils/vector.h"
namespace tint::ast {
@@ -67,35 +68,34 @@ bool TraverseExpressions(const ast::Expression* root, diag::List& diags, CALLBAC
size_t depth;
};
- std::vector<Pending> to_visit{{root, 0}};
+ utils::Vector<Pending, 32> to_visit{{root, 0}};
auto push_single = [&](const ast::Expression* expr, size_t depth) {
- to_visit.push_back({expr, depth});
+ to_visit.Push({expr, depth});
};
auto push_pair = [&](const ast::Expression* left, const ast::Expression* right, size_t depth) {
if (ORDER == TraverseOrder::LeftToRight) {
- to_visit.push_back({right, depth});
- to_visit.push_back({left, depth});
+ to_visit.Push({right, depth});
+ to_visit.Push({left, depth});
} else {
- to_visit.push_back({left, depth});
- to_visit.push_back({right, depth});
+ to_visit.Push({left, depth});
+ to_visit.Push({right, depth});
}
};
- auto push_list = [&](const std::vector<const ast::Expression*>& exprs, size_t depth) {
+ auto push_list = [&](utils::VectorRef<const ast::Expression*> exprs, size_t depth) {
if (ORDER == TraverseOrder::LeftToRight) {
for (auto* expr : utils::Reverse(exprs)) {
- to_visit.push_back({expr, depth});
+ to_visit.Push({expr, depth});
}
} else {
for (auto* expr : exprs) {
- to_visit.push_back({expr, depth});
+ to_visit.Push({expr, depth});
}
}
};
- while (!to_visit.empty()) {
- auto p = to_visit.back();
- to_visit.pop_back();
+ while (!to_visit.IsEmpty()) {
+ auto p = to_visit.Pop();
const ast::Expression* expr = p.expr;
if (auto* filtered = expr->template As<EXPR_TYPE>()) {
diff --git a/chromium/third_party/dawn/src/tint/ast/traverse_expressions_test.cc b/chromium/third_party/dawn/src/tint/ast/traverse_expressions_test.cc
index e79decb03df..a5a6dfdae70 100644
--- a/chromium/third_party/dawn/src/tint/ast/traverse_expressions_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/traverse_expressions_test.cc
@@ -97,19 +97,19 @@ TEST_F(TraverseExpressionsTest, DescendBitcastExpression) {
auto* b2 = Bitcast<i32>(b1);
auto* root = Bitcast<i32>(b2);
{
- std::vector<const ast::Expression*> l2r;
+ utils::Vector<const ast::Expression*, 8> l2r;
TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
[&](const ast::Expression* expr) {
- l2r.push_back(expr);
+ l2r.Push(expr);
return ast::TraverseAction::Descend;
});
EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e));
}
{
- std::vector<const ast::Expression*> r2l;
+ utils::Vector<const ast::Expression*, 8> r2l;
TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
[&](const ast::Expression* expr) {
- r2l.push_back(expr);
+ r2l.Push(expr);
return ast::TraverseAction::Descend;
});
EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e));
@@ -117,23 +117,23 @@ TEST_F(TraverseExpressionsTest, DescendBitcastExpression) {
}
TEST_F(TraverseExpressionsTest, DescendCallExpression) {
- std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
- std::vector<const ast::Expression*> c = {Call("a", e[0], e[1]), Call("b", e[2], e[3])};
+ utils::Vector e{Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+ utils::Vector c{Call("a", e[0], e[1]), Call("b", e[2], e[3])};
auto* root = Call("c", c[0], c[1]);
{
- std::vector<const ast::Expression*> l2r;
+ utils::Vector<const ast::Expression*, 8> l2r;
TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
[&](const ast::Expression* expr) {
- l2r.push_back(expr);
+ l2r.Push(expr);
return ast::TraverseAction::Descend;
});
EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3]));
}
{
- std::vector<const ast::Expression*> r2l;
+ utils::Vector<const ast::Expression*, 8> r2l;
TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
[&](const ast::Expression* expr) {
- r2l.push_back(expr);
+ r2l.Push(expr);
return ast::TraverseAction::Descend;
});
EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0]));
diff --git a/chromium/third_party/dawn/src/tint/ast/type.h b/chromium/third_party/dawn/src/tint/ast/type.h
index 4fee565e1a5..4f1f276974a 100644
--- a/chromium/third_party/dawn/src/tint/ast/type.h
+++ b/chromium/third_party/dawn/src/tint/ast/type.h
@@ -42,8 +42,9 @@ class Type : public Castable<Type, Node> {
protected:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- Type(ProgramID pid, const Source& src);
+ Type(ProgramID pid, NodeID nid, const Source& src);
};
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/type_decl.cc b/chromium/third_party/dawn/src/tint/ast/type_decl.cc
index a1a06058464..0b7652461e3 100644
--- a/chromium/third_party/dawn/src/tint/ast/type_decl.cc
+++ b/chromium/third_party/dawn/src/tint/ast/type_decl.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::TypeDecl);
namespace tint::ast {
-TypeDecl::TypeDecl(ProgramID pid, const Source& src, Symbol n) : Base(pid, src), name(n) {
+TypeDecl::TypeDecl(ProgramID pid, NodeID nid, const Source& src, Symbol n)
+ : Base(pid, nid, src), name(n) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/type_decl.h b/chromium/third_party/dawn/src/tint/ast/type_decl.h
index 2b8487a4cae..e3266c69e26 100644
--- a/chromium/third_party/dawn/src/tint/ast/type_decl.h
+++ b/chromium/third_party/dawn/src/tint/ast/type_decl.h
@@ -26,9 +26,10 @@ class TypeDecl : public Castable<TypeDecl, Node> {
public:
/// Create a new struct statement
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node for the import statement
/// @param name The name of the structure
- TypeDecl(ProgramID pid, const Source& src, Symbol name);
+ TypeDecl(ProgramID pid, NodeID nid, const Source& src, Symbol name);
/// Move constructor
TypeDecl(TypeDecl&&);
diff --git a/chromium/third_party/dawn/src/tint/ast/type_name.cc b/chromium/third_party/dawn/src/tint/ast/type_name.cc
index 8eb7a1ad003..852abf87c39 100644
--- a/chromium/third_party/dawn/src/tint/ast/type_name.cc
+++ b/chromium/third_party/dawn/src/tint/ast/type_name.cc
@@ -20,7 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::TypeName);
namespace tint::ast {
-TypeName::TypeName(ProgramID pid, const Source& src, Symbol n) : Base(pid, src), name(n) {}
+TypeName::TypeName(ProgramID pid, NodeID nid, const Source& src, Symbol n)
+ : Base(pid, nid, src), name(n) {}
TypeName::~TypeName() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/type_name.h b/chromium/third_party/dawn/src/tint/ast/type_name.h
index 3bb556a9b90..ed7e2f23c59 100644
--- a/chromium/third_party/dawn/src/tint/ast/type_name.h
+++ b/chromium/third_party/dawn/src/tint/ast/type_name.h
@@ -26,9 +26,10 @@ class TypeName final : public Castable<TypeName, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param name the type name
- TypeName(ProgramID pid, const Source& src, Symbol name);
+ TypeName(ProgramID pid, NodeID nid, const Source& src, Symbol name);
/// Move constructor
TypeName(TypeName&&);
/// Destructor
diff --git a/chromium/third_party/dawn/src/tint/ast/u32.cc b/chromium/third_party/dawn/src/tint/ast/u32.cc
index ac9c4908f06..c99dc4f284a 100644
--- a/chromium/third_party/dawn/src/tint/ast/u32.cc
+++ b/chromium/third_party/dawn/src/tint/ast/u32.cc
@@ -20,7 +20,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::U32);
namespace tint::ast {
-U32::U32(ProgramID pid, const Source& src) : Base(pid, src) {}
+U32::U32(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
U32::~U32() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/u32.h b/chromium/third_party/dawn/src/tint/ast/u32.h
index 8ede11cbb49..9237278de33 100644
--- a/chromium/third_party/dawn/src/tint/ast/u32.h
+++ b/chromium/third_party/dawn/src/tint/ast/u32.h
@@ -26,8 +26,9 @@ class U32 final : public Castable<U32, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- U32(ProgramID pid, const Source& src);
+ U32(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
U32(U32&&);
~U32() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/unary_op_expression.cc b/chromium/third_party/dawn/src/tint/ast/unary_op_expression.cc
index 80e4e9061a2..eec69a05ab7 100644
--- a/chromium/third_party/dawn/src/tint/ast/unary_op_expression.cc
+++ b/chromium/third_party/dawn/src/tint/ast/unary_op_expression.cc
@@ -21,10 +21,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::UnaryOpExpression);
namespace tint::ast {
UnaryOpExpression::UnaryOpExpression(ProgramID pid,
+ NodeID nid,
const Source& src,
UnaryOp o,
const Expression* e)
- : Base(pid, src), op(o), expr(e) {
+ : Base(pid, nid, src), op(o), expr(e) {
TINT_ASSERT(AST, expr);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/unary_op_expression.h b/chromium/third_party/dawn/src/tint/ast/unary_op_expression.h
index 22093fbd1e2..a5c2be937e8 100644
--- a/chromium/third_party/dawn/src/tint/ast/unary_op_expression.h
+++ b/chromium/third_party/dawn/src/tint/ast/unary_op_expression.h
@@ -24,11 +24,13 @@ namespace tint::ast {
class UnaryOpExpression final : public Castable<UnaryOpExpression, Expression> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the unary op expression source
/// @param op the op
/// @param expr the expr
- UnaryOpExpression(ProgramID program_id,
+ UnaryOpExpression(ProgramID pid,
+ NodeID nid,
const Source& source,
UnaryOp op,
const Expression* expr);
diff --git a/chromium/third_party/dawn/src/tint/ast/var.cc b/chromium/third_party/dawn/src/tint/ast/var.cc
new file mode 100644
index 00000000000..474cff2c38b
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/var.cc
@@ -0,0 +1,54 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/var.h"
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::Var);
+
+namespace tint::ast {
+
+Var::Var(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Symbol& sym,
+ const ast::Type* ty,
+ StorageClass storage_class,
+ Access access,
+ const Expression* ctor,
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)),
+ declared_storage_class(storage_class),
+ declared_access(access) {}
+
+Var::Var(Var&&) = default;
+
+Var::~Var() = default;
+
+const char* Var::Kind() const {
+ return "var";
+}
+
+const Var* Var::Clone(CloneContext* ctx) const {
+ auto src = ctx->Clone(source);
+ auto sym = ctx->Clone(symbol);
+ auto* ty = ctx->Clone(type);
+ auto* ctor = ctx->Clone(constructor);
+ auto attrs = ctx->Clone(attributes);
+ return ctx->dst->create<Var>(src, sym, ty, declared_storage_class, declared_access, ctor,
+ std::move(attrs));
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/var.h b/chromium/third_party/dawn/src/tint/ast/var.h
new file mode 100644
index 00000000000..908a9b30f49
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/var.h
@@ -0,0 +1,91 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_VAR_H_
+#define SRC_TINT_AST_VAR_H_
+
+#include <utility>
+#include <vector>
+
+#include "src/tint/ast/variable.h"
+
+namespace tint::ast {
+
+/// A "var" declaration is a name for typed storage.
+///
+/// Examples:
+///
+/// ```
+/// // Declared outside a function, i.e. at module scope, requires
+/// // a storage class.
+/// var<workgroup> width : i32; // no initializer
+/// var<private> height : i32 = 3; // with initializer
+///
+/// // A variable declared inside a function doesn't take a storage class,
+/// // and maps to SPIR-V Function storage.
+/// var computed_depth : i32;
+/// var area : i32 = compute_area(width, height);
+/// ```
+///
+/// @see https://www.w3.org/TR/WGSL/#var-decls
+class Var final : public Castable<Var, Variable> {
+ public:
+ /// Create a 'var' variable
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param source the variable source
+ /// @param sym the variable symbol
+ /// @param type the declared variable type
+ /// @param declared_storage_class the declared storage class
+ /// @param declared_access the declared access control
+ /// @param constructor the constructor expression
+ /// @param attributes the variable attributes
+ Var(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ const Symbol& sym,
+ const ast::Type* type,
+ StorageClass declared_storage_class,
+ Access declared_access,
+ const Expression* constructor,
+ utils::VectorRef<const Attribute*> attributes);
+
+ /// Move constructor
+ Var(Var&&);
+
+ /// Destructor
+ ~Var() override;
+
+ /// @returns "var"
+ const char* Kind() const override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext`
+ /// `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const Var* Clone(CloneContext* ctx) const override;
+
+ /// The declared storage class
+ const StorageClass declared_storage_class;
+
+ /// The declared access control
+ const Access declared_access;
+};
+
+/// A list of `var` declarations
+using VarList = std::vector<const Var*>;
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_VAR_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/variable.cc b/chromium/third_party/dawn/src/tint/ast/variable.cc
index 26991f252a2..ec87e54bbd2 100644
--- a/chromium/third_party/dawn/src/tint/ast/variable.cc
+++ b/chromium/third_party/dawn/src/tint/ast/variable.cc
@@ -13,35 +13,22 @@
// limitations under the License.
#include "src/tint/ast/variable.h"
-
-#include "src/tint/program_builder.h"
-#include "src/tint/sem/variable.h"
+#include "src/tint/ast/binding_attribute.h"
+#include "src/tint/ast/group_attribute.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::Variable);
namespace tint::ast {
Variable::Variable(ProgramID pid,
+ NodeID nid,
const Source& src,
const Symbol& sym,
- StorageClass dsc,
- Access da,
const ast::Type* ty,
- bool constant,
- bool overridable,
const Expression* ctor,
- AttributeList attrs)
- : Base(pid, src),
- symbol(sym),
- type(ty),
- is_const(constant),
- is_overridable(overridable),
- constructor(ctor),
- attributes(std::move(attrs)),
- declared_storage_class(dsc),
- declared_access(da) {
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src), symbol(sym), type(ty), constructor(ctor), attributes(std::move(attrs)) {
TINT_ASSERT(AST, symbol.IsValid());
- TINT_ASSERT(AST, is_overridable ? is_const : true);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, constructor, program_id);
}
@@ -54,23 +41,12 @@ VariableBindingPoint Variable::BindingPoint() const {
const GroupAttribute* group = nullptr;
const BindingAttribute* binding = nullptr;
for (auto* attr : attributes) {
- if (auto* g = attr->As<GroupAttribute>()) {
- group = g;
- } else if (auto* b = attr->As<BindingAttribute>()) {
- binding = b;
- }
+ Switch(
+ attr, //
+ [&](const GroupAttribute* a) { group = a; },
+ [&](const BindingAttribute* a) { binding = a; });
}
return VariableBindingPoint{group, binding};
}
-const Variable* Variable::Clone(CloneContext* ctx) const {
- auto src = ctx->Clone(source);
- auto sym = ctx->Clone(symbol);
- auto* ty = ctx->Clone(type);
- auto* ctor = ctx->Clone(constructor);
- auto attrs = ctx->Clone(attributes);
- return ctx->dst->create<Variable>(src, sym, declared_storage_class, declared_access, ty,
- is_const, is_overridable, ctor, attrs);
-}
-
} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/variable.h b/chromium/third_party/dawn/src/tint/ast/variable.h
index 58022558f51..1f5d77a20a9 100644
--- a/chromium/third_party/dawn/src/tint/ast/variable.h
+++ b/chromium/third_party/dawn/src/tint/ast/variable.h
@@ -45,111 +45,43 @@ struct VariableBindingPoint {
inline operator bool() const { return group && binding; }
};
-/// A Variable statement.
+/// Variable is the base class for Var, Let, Const, Override and Parameter.
///
-/// An instance of this class represents one of four constructs in WGSL: "var"
-/// declaration, "let" declaration, "override" declaration, or formal parameter
-/// to a function.
+/// An instance of this class represents one of five constructs in WGSL: "var" declaration, "let"
+/// declaration, "override" declaration, "const" declaration, or formal parameter to a function.
///
-/// 1. A "var" declaration is a name for typed storage. Examples:
-///
-/// // Declared outside a function, i.e. at module scope, requires
-/// // a storage class.
-/// var<workgroup> width : i32; // no initializer
-/// var<private> height : i32 = 3; // with initializer
-///
-/// // A variable declared inside a function doesn't take a storage class,
-/// // and maps to SPIR-V Function storage.
-/// var computed_depth : i32;
-/// var area : i32 = compute_area(width, height);
-///
-/// 2. A "let" declaration is a name for a typed value. Examples:
-///
-/// let twice_depth : i32 = width + width; // Must have initializer
-///
-/// 3. An "override" declaration is a name for a pipeline-overridable constant.
-/// Examples:
-///
-/// override radius : i32 = 2; // Can be overridden by name.
-/// @id(5) override width : i32 = 2; // Can be overridden by ID.
-/// override scale : f32; // No default - must be overridden.
-///
-/// 4. A formal parameter to a function is a name for a typed value to
-/// be passed into a function. Example:
-///
-/// fn twice(a: i32) -> i32 { // "a:i32" is the formal parameter
-/// return a + a;
-/// }
-///
-/// From the WGSL draft, about "var"::
-///
-/// A variable is a named reference to storage that can contain a value of a
-/// particular type.
-///
-/// Two types are associated with a variable: its store type (the type of
-/// value that may be placed in the referenced storage) and its reference
-/// type (the type of the variable itself). If a variable has store type T
-/// and storage class S, then its reference type is pointer-to-T-in-S.
-///
-/// This class uses the term "type" to refer to:
-/// the value type of a "let",
-/// the value type of an "override",
-/// the value type of the formal parameter,
-/// or the store type of the "var".
-//
-/// Setting is_const:
-/// - "var" gets false
-/// - "let" gets true
-/// - "override" gets true
-/// - formal parameter gets true
-///
-/// Setting is_overrideable:
-/// - "var" gets false
-/// - "let" gets false
-/// - "override" gets true
-/// - formal parameter gets false
-///
-/// Setting storage class:
-/// - "var" is StorageClass::kNone when using the
-/// defaulting syntax for a "var" declared inside a function.
-/// - "let" is always StorageClass::kNone.
-/// - formal parameter is always StorageClass::kNone.
-class Variable final : public Castable<Variable, Node> {
+/// @see https://www.w3.org/TR/WGSL/#value-decls
+class Variable : public Castable<Variable, Node> {
public:
- /// Create a variable
- /// @param program_id the identifier of the program that owns this node
+ /// Constructor
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the variable source
/// @param sym the variable symbol
- /// @param declared_storage_class the declared storage class
- /// @param declared_access the declared access control
/// @param type the declared variable type
- /// @param is_const true if the variable is const
- /// @param is_overridable true if the variable is pipeline-overridable
/// @param constructor the constructor expression
/// @param attributes the variable attributes
- Variable(ProgramID program_id,
+ Variable(ProgramID pid,
+ NodeID nid,
const Source& source,
const Symbol& sym,
- StorageClass declared_storage_class,
- Access declared_access,
const ast::Type* type,
- bool is_const,
- bool is_overridable,
const Expression* constructor,
- AttributeList attributes);
+ utils::VectorRef<const Attribute*> attributes);
+
/// Move constructor
Variable(Variable&&);
+ /// Destructor
~Variable() override;
- /// @returns the binding point information for the variable
+ /// @returns the binding point information from the variable's attributes.
+ /// @note binding points should only be applied to Var and Parameter types.
VariableBindingPoint BindingPoint() const;
- /// Clones this node and all transitive child nodes using the `CloneContext`
- /// `ctx`.
- /// @param ctx the clone context
- /// @return the newly cloned node
- const Variable* Clone(CloneContext* ctx) const override;
+ /// @returns the kind of the variable, which can be used in diagnostics
+ /// e.g. "var", "let", "const", etc
+ virtual const char* Kind() const = 0;
/// The variable symbol
const Symbol symbol;
@@ -159,28 +91,13 @@ class Variable final : public Castable<Variable, Node> {
/// var i = 1;
const ast::Type* const type;
- /// True if this is a constant, false otherwise
- const bool is_const;
-
- /// True if this is a pipeline-overridable constant, false otherwise
- const bool is_overridable;
-
/// The constructor expression or nullptr if none set
const Expression* const constructor;
/// The attributes attached to this variable
- const AttributeList attributes;
-
- /// The declared storage class
- const StorageClass declared_storage_class;
-
- /// The declared access control
- const Access declared_access;
+ const utils::Vector<const Attribute*, 2> attributes;
};
-/// A list of variables
-using VariableList = std::vector<const Variable*>;
-
} // namespace tint::ast
#endif // SRC_TINT_AST_VARIABLE_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.cc b/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.cc
index fdde149f033..79ee92606c8 100644
--- a/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.cc
+++ b/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.cc
@@ -20,8 +20,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::VariableDeclStatement);
namespace tint::ast {
-VariableDeclStatement::VariableDeclStatement(ProgramID pid, const Source& src, const Variable* var)
- : Base(pid, src), variable(var) {
+VariableDeclStatement::VariableDeclStatement(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Variable* var)
+ : Base(pid, nid, src), variable(var) {
TINT_ASSERT(AST, variable);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, variable, program_id);
}
diff --git a/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.h b/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.h
index 3f3ae273e3f..b71d0b2acc5 100644
--- a/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.h
+++ b/chromium/third_party/dawn/src/tint/ast/variable_decl_statement.h
@@ -24,10 +24,14 @@ namespace tint::ast {
class VariableDeclStatement final : public Castable<VariableDeclStatement, Statement> {
public:
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param source the variable statement source
/// @param variable the variable
- VariableDeclStatement(ProgramID program_id, const Source& source, const Variable* variable);
+ VariableDeclStatement(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ const Variable* variable);
/// Move constructor
VariableDeclStatement(VariableDeclStatement&&);
~VariableDeclStatement() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/variable_test.cc b/chromium/third_party/dawn/src/tint/ast/variable_test.cc
index e62ec1eb053..b22699420ce 100644
--- a/chromium/third_party/dawn/src/tint/ast/variable_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/variable_test.cc
@@ -38,7 +38,7 @@ TEST_F(VariableTest, Creation) {
TEST_F(VariableTest, CreationWithSource) {
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}}, "i",
- ty.f32(), StorageClass::kPrivate, nullptr, AttributeList{});
+ ty.f32(), StorageClass::kPrivate, nullptr, utils::Empty);
EXPECT_EQ(v->symbol, Symbol(1, ID()));
EXPECT_EQ(v->declared_storage_class, StorageClass::kPrivate);
@@ -51,7 +51,7 @@ TEST_F(VariableTest, CreationWithSource) {
TEST_F(VariableTest, CreationEmpty) {
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}}, "a_var",
- ty.i32(), StorageClass::kWorkgroup, nullptr, AttributeList{});
+ ty.i32(), StorageClass::kWorkgroup, nullptr, utils::Empty);
EXPECT_EQ(v->symbol, Symbol(1, ID()));
EXPECT_EQ(v->declared_storage_class, StorageClass::kWorkgroup);
@@ -93,10 +93,10 @@ TEST_F(VariableTest, Assert_DifferentProgramID_Constructor) {
TEST_F(VariableTest, WithAttributes) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
- AttributeList{
- create<LocationAttribute>(1),
- create<BuiltinAttribute>(Builtin::kPosition),
- create<IdAttribute>(1200),
+ utils::Vector{
+ create<LocationAttribute>(1u),
+ create<BuiltinAttribute>(BuiltinValue::kPosition),
+ create<IdAttribute>(1200u),
});
auto& attributes = var->attributes;
@@ -111,9 +111,9 @@ TEST_F(VariableTest, WithAttributes) {
TEST_F(VariableTest, BindingPoint) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
- AttributeList{
- create<BindingAttribute>(2),
- create<GroupAttribute>(1),
+ utils::Vector{
+ create<BindingAttribute>(2u),
+ create<GroupAttribute>(1u),
});
EXPECT_TRUE(var->BindingPoint());
ASSERT_NE(var->BindingPoint().binding, nullptr);
@@ -123,7 +123,7 @@ TEST_F(VariableTest, BindingPoint) {
}
TEST_F(VariableTest, BindingPointAttributes) {
- auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, AttributeList{});
+ auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, utils::Empty);
EXPECT_FALSE(var->BindingPoint());
EXPECT_EQ(var->BindingPoint().group, nullptr);
EXPECT_EQ(var->BindingPoint().binding, nullptr);
@@ -131,8 +131,8 @@ TEST_F(VariableTest, BindingPointAttributes) {
TEST_F(VariableTest, BindingPointMissingGroupAttribute) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
- AttributeList{
- create<BindingAttribute>(2),
+ utils::Vector{
+ create<BindingAttribute>(2u),
});
EXPECT_FALSE(var->BindingPoint());
ASSERT_NE(var->BindingPoint().binding, nullptr);
@@ -142,7 +142,7 @@ TEST_F(VariableTest, BindingPointMissingGroupAttribute) {
TEST_F(VariableTest, BindingPointMissingBindingAttribute) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
- AttributeList{create<GroupAttribute>(1)});
+ utils::Vector{create<GroupAttribute>(1u)});
EXPECT_FALSE(var->BindingPoint());
ASSERT_NE(var->BindingPoint().group, nullptr);
EXPECT_EQ(var->BindingPoint().group->value, 1u);
diff --git a/chromium/third_party/dawn/src/tint/ast/vector.cc b/chromium/third_party/dawn/src/tint/ast/vector.cc
index 43478dfda42..d49da33126a 100644
--- a/chromium/third_party/dawn/src/tint/ast/vector.cc
+++ b/chromium/third_party/dawn/src/tint/ast/vector.cc
@@ -20,8 +20,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Vector);
namespace tint::ast {
-Vector::Vector(ProgramID pid, Source const& src, const Type* subtype, uint32_t w)
- : Base(pid, src), type(subtype), width(w) {
+Vector::Vector(ProgramID pid, NodeID nid, Source const& src, const Type* subtype, uint32_t w)
+ : Base(pid, nid, src), type(subtype), width(w) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, subtype, program_id);
TINT_ASSERT(AST, width > 1);
TINT_ASSERT(AST, width < 5);
diff --git a/chromium/third_party/dawn/src/tint/ast/vector.h b/chromium/third_party/dawn/src/tint/ast/vector.h
index 6b2d9141b88..111602de521 100644
--- a/chromium/third_party/dawn/src/tint/ast/vector.h
+++ b/chromium/third_party/dawn/src/tint/ast/vector.h
@@ -26,12 +26,13 @@ class Vector final : public Castable<Vector, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param subtype the declared type of the vector components. May be null
/// for vector constructors, where the element type will be inferred
/// from the constructor arguments
/// @param width the number of elements in the vector
- Vector(ProgramID pid, Source const& src, const Type* subtype, uint32_t width);
+ Vector(ProgramID pid, NodeID nid, Source const& src, const Type* subtype, uint32_t width);
/// Move constructor
Vector(Vector&&);
~Vector() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/vector_test.cc b/chromium/third_party/dawn/src/tint/ast/vector_test.cc
index a701852df5d..da2ad1f3de0 100644
--- a/chromium/third_party/dawn/src/tint/ast/vector_test.cc
+++ b/chromium/third_party/dawn/src/tint/ast/vector_test.cc
@@ -24,14 +24,14 @@ using AstVectorTest = TestHelper;
TEST_F(AstVectorTest, Creation) {
auto* i32 = create<I32>();
- auto* v = create<Vector>(i32, 2);
+ auto* v = create<Vector>(i32, 2u);
EXPECT_EQ(v->type, i32);
EXPECT_EQ(v->width, 2u);
}
TEST_F(AstVectorTest, FriendlyName) {
auto* f32 = create<F32>();
- auto* v = create<Vector>(f32, 3);
+ auto* v = create<Vector>(f32, 3u);
EXPECT_EQ(v->FriendlyName(Symbols()), "vec3<f32>");
}
diff --git a/chromium/third_party/dawn/src/tint/ast/void.cc b/chromium/third_party/dawn/src/tint/ast/void.cc
index 5cc89635a7b..ead89efe42c 100644
--- a/chromium/third_party/dawn/src/tint/ast/void.cc
+++ b/chromium/third_party/dawn/src/tint/ast/void.cc
@@ -20,7 +20,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Void);
namespace tint::ast {
-Void::Void(ProgramID pid, const Source& src) : Base(pid, src) {}
+Void::Void(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
Void::Void(Void&&) = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/void.h b/chromium/third_party/dawn/src/tint/ast/void.h
index 33f5b5bd1dd..dba20f11e4a 100644
--- a/chromium/third_party/dawn/src/tint/ast/void.h
+++ b/chromium/third_party/dawn/src/tint/ast/void.h
@@ -26,8 +26,9 @@ class Void final : public Castable<Void, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
- Void(ProgramID pid, const Source& src);
+ Void(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
Void(Void&&);
~Void() override;
diff --git a/chromium/third_party/dawn/src/tint/ast/while_statement.cc b/chromium/third_party/dawn/src/tint/ast/while_statement.cc
new file mode 100644
index 00000000000..160af4b5826
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/while_statement.cc
@@ -0,0 +1,49 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/while_statement.h"
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::WhileStatement);
+
+namespace tint::ast {
+
+WhileStatement::WhileStatement(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Expression* cond,
+ const BlockStatement* b)
+ : Base(pid, nid, src), condition(cond), body(b) {
+ TINT_ASSERT(AST, cond);
+ TINT_ASSERT(AST, body);
+
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
+}
+
+WhileStatement::WhileStatement(WhileStatement&&) = default;
+
+WhileStatement::~WhileStatement() = default;
+
+const WhileStatement* WhileStatement::Clone(CloneContext* ctx) const {
+ // Clone arguments outside of create() call to have deterministic ordering
+ auto src = ctx->Clone(source);
+
+ auto* cond = ctx->Clone(condition);
+ auto* b = ctx->Clone(body);
+ return ctx->dst->create<WhileStatement>(src, cond, b);
+}
+
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/while_statement.h b/chromium/third_party/dawn/src/tint/ast/while_statement.h
new file mode 100644
index 00000000000..4e8dd7e2a16
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/while_statement.h
@@ -0,0 +1,57 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_WHILE_STATEMENT_H_
+#define SRC_TINT_AST_WHILE_STATEMENT_H_
+
+#include "src/tint/ast/block_statement.h"
+
+namespace tint::ast {
+
+class Expression;
+
+/// A while loop statement
+class WhileStatement final : public Castable<WhileStatement, Statement> {
+ public:
+ /// Constructor
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param source the for loop statement source
+ /// @param condition the optional loop condition expression
+ /// @param body the loop body
+ WhileStatement(ProgramID pid,
+ NodeID nid,
+ const Source& source,
+ const Expression* condition,
+ const BlockStatement* body);
+ /// Move constructor
+ WhileStatement(WhileStatement&&);
+ ~WhileStatement() override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext`
+ /// `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const WhileStatement* Clone(CloneContext* ctx) const override;
+
+ /// The condition expression
+ const Expression* const condition;
+
+ /// The loop body block
+ const BlockStatement* const body;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_WHILE_STATEMENT_H_
diff --git a/chromium/third_party/dawn/src/tint/ast/while_statement_test.cc b/chromium/third_party/dawn/src/tint/ast/while_statement_test.cc
new file mode 100644
index 00000000000..73c9e5614f8
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/ast/while_statement_test.cc
@@ -0,0 +1,85 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest-spi.h"
+#include "src/tint/ast/binary_expression.h"
+#include "src/tint/ast/test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::ast {
+namespace {
+
+using WhileStatementTest = TestHelper;
+
+TEST_F(WhileStatementTest, Creation) {
+ auto* cond = create<BinaryExpression>(BinaryOp::kLessThan, Expr("i"), Expr(5_u));
+ auto* body = Block(Return());
+ auto* l = While(cond, body);
+
+ EXPECT_EQ(l->condition, cond);
+ EXPECT_EQ(l->body, body);
+}
+
+TEST_F(WhileStatementTest, Creation_WithSource) {
+ auto* cond = create<BinaryExpression>(BinaryOp::kLessThan, Expr("i"), Expr(5_u));
+ auto* body = Block(Return());
+ auto* l = While(Source{{20u, 2u}}, cond, body);
+ auto src = l->source;
+ EXPECT_EQ(src.range.begin.line, 20u);
+ EXPECT_EQ(src.range.begin.column, 2u);
+}
+
+TEST_F(WhileStatementTest, Assert_Null_Cond) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b;
+ auto* body = b.Block();
+ b.While(nullptr, body);
+ },
+ "internal compiler error");
+}
+
+TEST_F(WhileStatementTest, Assert_Null_Body) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b;
+ auto* cond = b.create<BinaryExpression>(BinaryOp::kLessThan, b.Expr("i"), b.Expr(5_u));
+ b.While(cond, nullptr);
+ },
+ "internal compiler error");
+}
+
+TEST_F(WhileStatementTest, Assert_DifferentProgramID_Condition) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b1;
+ ProgramBuilder b2;
+ b1.While(b2.Expr(true), b1.Block());
+ },
+ "internal compiler error");
+}
+
+TEST_F(WhileStatementTest, Assert_DifferentProgramID_Body) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b1;
+ ProgramBuilder b2;
+ b1.While(b1.Expr(true), b2.Block());
+ },
+ "internal compiler error");
+}
+
+} // namespace
+} // namespace tint::ast
diff --git a/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.cc b/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.cc
index 74ecdbe019e..7cb67dc5868 100644
--- a/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.cc
@@ -23,11 +23,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::WorkgroupAttribute);
namespace tint::ast {
WorkgroupAttribute::WorkgroupAttribute(ProgramID pid,
+ NodeID nid,
const Source& src,
const ast::Expression* x_,
const ast::Expression* y_,
const ast::Expression* z_)
- : Base(pid, src), x(x_), y(y_), z(z_) {}
+ : Base(pid, nid, src), x(x_), y(y_), z(z_) {}
WorkgroupAttribute::~WorkgroupAttribute() = default;
diff --git a/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.h b/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.h
index 536ce155fdc..e27e77e9003 100644
--- a/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.h
+++ b/chromium/third_party/dawn/src/tint/ast/workgroup_attribute.h
@@ -32,11 +32,13 @@ class WorkgroupAttribute final : public Castable<WorkgroupAttribute, Attribute>
public:
/// constructor
/// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param src the source of this node
/// @param x the workgroup x dimension expression
/// @param y the optional workgroup y dimension expression
/// @param z the optional workgroup z dimension expression
WorkgroupAttribute(ProgramID pid,
+ NodeID nid,
const Source& src,
const ast::Expression* x,
const ast::Expression* y = nullptr,
diff --git a/chromium/third_party/dawn/src/tint/bench/benchmark.h b/chromium/third_party/dawn/src/tint/bench/benchmark.h
index 733b1a7bb20..680158544d1 100644
--- a/chromium/third_party/dawn/src/tint/bench/benchmark.h
+++ b/chromium/third_party/dawn/src/tint/bench/benchmark.h
@@ -17,8 +17,7 @@
#include <memory>
#include <string>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <variant> // NOLINT: Found C system header after C++ system header.
+#include <variant>
#include "benchmark/benchmark.h"
#include "src/tint/utils/concat.h"
@@ -59,6 +58,7 @@ std::variant<ProgramAndFile, Error> LoadProgram(std::string name);
/// files in `<tint>/test/benchmark`.
#define TINT_BENCHMARK_WGSL_PROGRAMS(FUNC) \
TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "animometer.wgsl"); \
+ TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "atan2-const-eval.wgsl"); \
TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "bloom-vertical-blur.wgsl"); \
TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "cluster-lights.wgsl"); \
TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "empty.wgsl"); \
diff --git a/chromium/third_party/dawn/src/tint/castable.cc b/chromium/third_party/dawn/src/tint/castable.cc
index cff430ecb28..40c32da64aa 100644
--- a/chromium/third_party/dawn/src/tint/castable.cc
+++ b/chromium/third_party/dawn/src/tint/castable.cc
@@ -26,4 +26,8 @@ const TypeInfo detail::TypeInfoOf<CastableBase>::info{
tint::TypeInfo::FullHashCodeOf<CastableBase>(),
};
+CastableBase::CastableBase(const CastableBase&) = default;
+
+CastableBase::~CastableBase() = default;
+
} // namespace tint
diff --git a/chromium/third_party/dawn/src/tint/castable.h b/chromium/third_party/dawn/src/tint/castable.h
index 048d1e52589..d654fca7dbe 100644
--- a/chromium/third_party/dawn/src/tint/castable.h
+++ b/chromium/third_party/dawn/src/tint/castable.h
@@ -101,6 +101,36 @@ struct TypeInfo {
/// The type hash code bitwise-or'd with all ancestor's hashcodes.
const HashCode full_hashcode;
+ /// @returns true if `type` derives from the class `TO`
+ /// @param object the object type to test from, which must be, or derive from
+ /// type `FROM`.
+ /// @see CastFlags
+ template <typename TO, typename FROM, int FLAGS = 0>
+ static inline bool Is(const tint::TypeInfo* object) {
+ constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
+ constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
+ constexpr const bool nocast = std::is_same<FROM, TO>::value;
+ constexpr const bool assert_is_castable = (FLAGS & kDontErrorOnImpossibleCast) == 0;
+
+ static_assert(upcast || downcast || nocast || !assert_is_castable, "impossible cast");
+
+ return upcast || nocast || object->Is<TO>();
+ }
+
+ /// @returns true if this type derives from the class `T`
+ template <typename T>
+ inline bool Is() const {
+ auto* type = &Of<std::remove_cv_t<T>>();
+
+ if constexpr (std::is_final_v<T>) {
+ // T is final, so nothing can derive from T.
+ // We do not need to check ancestors, only whether this type is equal to the type T.
+ return type == this;
+ } else {
+ return Is(type);
+ }
+ }
+
/// @param type the test type info
/// @returns true if the class with this TypeInfo is of, or derives from the
/// class with the given TypeInfo.
@@ -112,8 +142,8 @@ struct TypeInfo {
return false;
}
- // Walk the base types, starting with this TypeInfo, to see if any of the
- // pointers match `type`.
+ // Walk the base types, starting with this TypeInfo, to see if any of the pointers match
+ // `type`.
for (auto* ti = this; ti != nullptr; ti = ti->base) {
if (ti == type) {
return true;
@@ -122,26 +152,6 @@ struct TypeInfo {
return false;
}
- /// @returns true if `type` derives from the class `TO`
- /// @param type the object type to test from, which must be, or derive from
- /// type `FROM`.
- /// @see CastFlags
- template <typename TO, typename FROM, int FLAGS = 0>
- static inline bool Is(const tint::TypeInfo* type) {
- constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
- constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
- constexpr const bool nocast = std::is_same<FROM, TO>::value;
- constexpr const bool assert_is_castable = (FLAGS & kDontErrorOnImpossibleCast) == 0;
-
- static_assert(upcast || downcast || nocast || !assert_is_castable, "impossible cast");
-
- if (upcast || nocast) {
- return true;
- }
-
- return type->Is(&Of<std::remove_cv_t<TO>>());
- }
-
/// @returns the static TypeInfo for the type T
template <typename T>
static const TypeInfo& Of() {
@@ -211,14 +221,12 @@ struct TypeInfo {
if constexpr (kCount == 0) {
return false;
} else if constexpr (kCount == 1) {
- return Is(&Of<std::tuple_element_t<0, TUPLE>>());
+ return Is<std::tuple_element_t<0, TUPLE>>();
} else if constexpr (kCount == 2) {
- return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
- Is(&Of<std::tuple_element_t<1, TUPLE>>());
+ return Is<std::tuple_element_t<0, TUPLE>>() || Is<std::tuple_element_t<1, TUPLE>>();
} else if constexpr (kCount == 3) {
- return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
- Is(&Of<std::tuple_element_t<1, TUPLE>>()) ||
- Is(&Of<std::tuple_element_t<2, TUPLE>>());
+ return Is<std::tuple_element_t<0, TUPLE>>() || Is<std::tuple_element_t<1, TUPLE>>() ||
+ Is<std::tuple_element_t<2, TUPLE>>();
} else {
// Optimization: Compare the object's hashcode to the bitwise-or of all
// the tested type's hashcodes. If there's no intersection of bits in
@@ -320,10 +328,10 @@ inline const TO* As(const FROM* obj) {
class CastableBase {
public:
/// Copy constructor
- CastableBase(const CastableBase&) = default;
+ CastableBase(const CastableBase&);
/// Destructor
- virtual ~CastableBase() = default;
+ virtual ~CastableBase();
/// Copy assignment
/// @param other the CastableBase to copy
@@ -460,7 +468,7 @@ struct CastableCommonBaseImpl {};
/// Alias to typename CastableCommonBaseImpl<TYPES>::type
template <typename... TYPES>
-using CastableCommonBase = typename detail::CastableCommonBaseImpl<TYPES...>::type;
+using CastableCommonBase = typename CastableCommonBaseImpl<TYPES...>::type;
/// CastableCommonBaseImpl template specialization for a single type
template <typename T>
@@ -587,7 +595,7 @@ inline bool NonDefaultCases(T* object,
// Attempt to dynamically cast the object to the handler type. If that
// succeeds, call the case handler with the cast object.
using CaseType = SwitchCaseType<CaseFunc>;
- if (type->Is(&TypeInfo::Of<CaseType>())) {
+ if (type->Is<CaseType>()) {
auto* ptr = static_cast<CaseType*>(object);
if constexpr (kHasReturnType) {
new (result) RETURN_TYPE(static_cast<RETURN_TYPE>(std::get<0>(cases)(ptr)));
@@ -626,7 +634,7 @@ inline void SwitchCases(T* object, RETURN_TYPE* result, std::tuple<CASES...>&& c
// Static assertions
static constexpr bool kDefaultIsOK =
- kDefaultIndex == -1 || kDefaultIndex == std::tuple_size_v<Cases> - 1;
+ kDefaultIndex == -1 || kDefaultIndex == static_cast<int>(std::tuple_size_v<Cases> - 1);
static constexpr bool kReturnIsOK =
kHasDefaultCase || !kHasReturnType || std::is_constructible_v<RETURN_TYPE>;
static_assert(kDefaultIsOK, "Default case must be last in Switch()");
diff --git a/chromium/third_party/dawn/src/tint/castable_bench.cc b/chromium/third_party/dawn/src/tint/castable_bench.cc
index 7c7e0ef34bf..c9d0c437714 100644
--- a/chromium/third_party/dawn/src/tint/castable_bench.cc
+++ b/chromium/third_party/dawn/src/tint/castable_bench.cc
@@ -12,7 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "bench/benchmark.h"
+#include <memory>
+
+#include "benchmark/benchmark.h"
+
+#include "src/tint/castable.h"
namespace tint {
namespace {
diff --git a/chromium/third_party/dawn/src/tint/clone_context.cc b/chromium/third_party/dawn/src/tint/clone_context.cc
index 0a9e606742e..12252942ad4 100644
--- a/chromium/third_party/dawn/src/tint/clone_context.cc
+++ b/chromium/third_party/dawn/src/tint/clone_context.cc
@@ -23,6 +23,10 @@ TINT_INSTANTIATE_TYPEINFO(tint::Cloneable);
namespace tint {
+Cloneable::Cloneable() = default;
+Cloneable::Cloneable(Cloneable&&) = default;
+Cloneable::~Cloneable() = default;
+
CloneContext::ListTransforms::ListTransforms() = default;
CloneContext::ListTransforms::~ListTransforms() = default;
@@ -58,7 +62,7 @@ void CloneContext::Clone() {
ast::FunctionList CloneContext::Clone(const ast::FunctionList& v) {
ast::FunctionList out;
- out.reserve(v.size());
+ out.Reserve(v.Length());
for (const ast::Function* el : v) {
out.Add(Clone(el));
}
diff --git a/chromium/third_party/dawn/src/tint/clone_context.h b/chromium/third_party/dawn/src/tint/clone_context.h
index e027565aa15..e7e2d52c6ba 100644
--- a/chromium/third_party/dawn/src/tint/clone_context.h
+++ b/chromium/third_party/dawn/src/tint/clone_context.h
@@ -28,6 +28,7 @@
#include "src/tint/program_id.h"
#include "src/tint/symbol.h"
#include "src/tint/traits.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint {
@@ -48,6 +49,13 @@ ProgramID ProgramIDOf(const ProgramBuilder*);
/// Cloneable is the base class for all objects that can be cloned
class Cloneable : public Castable<Cloneable> {
public:
+ /// Constructor
+ Cloneable();
+ /// Move constructor
+ Cloneable(Cloneable&&);
+ /// Destructor
+ ~Cloneable() override;
+
/// Performs a deep clone of this object using the CloneContext `ctx`.
/// @param ctx the clone context
/// @return the newly cloned object
@@ -156,12 +164,12 @@ class CloneContext {
///
/// @param v the vector to clone
/// @return the cloned vector
- template <typename T>
- std::vector<T> Clone(const std::vector<T>& v) {
- std::vector<T> out;
+ template <typename T, size_t N>
+ utils::Vector<T, N> Clone(const utils::Vector<T, N>& v) {
+ utils::Vector<T, N> out;
out.reserve(v.size());
for (auto& el : v) {
- out.emplace_back(Clone(el));
+ out.Push(Clone(el));
}
return out;
}
@@ -174,9 +182,9 @@ class CloneContext {
///
/// @param v the vector to clone
/// @return the cloned vector
- template <typename T>
- std::vector<T*> Clone(const std::vector<T*>& v) {
- std::vector<T*> out;
+ template <typename T, size_t N>
+ utils::Vector<T*, N> Clone(const utils::Vector<T*, N>& v) {
+ utils::Vector<T*, N> out;
Clone(out, v);
return out;
}
@@ -189,39 +197,39 @@ class CloneContext {
///
/// @param from the vector to clone
/// @param to the cloned result
- template <typename T>
- void Clone(std::vector<T*>& to, const std::vector<T*>& from) {
- to.reserve(from.size());
+ template <typename T, size_t N>
+ void Clone(utils::Vector<T*, N>& to, const utils::Vector<T*, N>& from) {
+ to.Reserve(from.Length());
auto list_transform_it = list_transforms_.find(&from);
if (list_transform_it != list_transforms_.end()) {
const auto& transforms = list_transform_it->second;
for (auto* o : transforms.insert_front_) {
- to.emplace_back(CheckedCast<T>(o));
+ to.Push(CheckedCast<T>(o));
}
for (auto& el : from) {
auto insert_before_it = transforms.insert_before_.find(el);
if (insert_before_it != transforms.insert_before_.end()) {
for (auto insert : insert_before_it->second) {
- to.emplace_back(CheckedCast<T>(insert));
+ to.Push(CheckedCast<T>(insert));
}
}
if (transforms.remove_.count(el) == 0) {
- to.emplace_back(Clone(el));
+ to.Push(Clone(el));
}
auto insert_after_it = transforms.insert_after_.find(el);
if (insert_after_it != transforms.insert_after_.end()) {
for (auto insert : insert_after_it->second) {
- to.emplace_back(CheckedCast<T>(insert));
+ to.Push(CheckedCast<T>(insert));
}
}
}
for (auto* o : transforms.insert_back_) {
- to.emplace_back(CheckedCast<T>(o));
+ to.Push(CheckedCast<T>(o));
}
} else {
for (auto& el : from) {
- to.emplace_back(Clone(el));
+ to.Push(Clone(el));
// Clone(el) may have inserted after
list_transform_it = list_transforms_.find(&from);
@@ -231,7 +239,7 @@ class CloneContext {
auto insert_after_it = transforms.insert_after_.find(el);
if (insert_after_it != transforms.insert_after_.end()) {
for (auto insert : insert_after_it->second) {
- to.emplace_back(CheckedCast<T>(insert));
+ to.Push(CheckedCast<T>(insert));
}
}
}
@@ -243,7 +251,7 @@ class CloneContext {
const auto& transforms = list_transform_it->second;
for (auto* o : transforms.insert_back_) {
- to.emplace_back(CheckedCast<T>(o));
+ to.Push(CheckedCast<T>(o));
}
}
}
@@ -311,7 +319,7 @@ class CloneContext {
CloneableTransform transform;
transform.typeinfo = &TypeInfo::Of<T>();
transform.function = [=](const Cloneable* in) { return replacer(in->As<T>()); };
- transforms_.emplace_back(std::move(transform));
+ transforms_.Push(std::move(transform));
return *this;
}
@@ -379,8 +387,8 @@ class CloneContext {
/// @param object a pointer to the object in #src that will be omitted from
/// the cloned vector.
/// @returns this CloneContext so calls can be chained
- template <typename T, typename OBJECT>
- CloneContext& Remove(const std::vector<T>& vector, OBJECT* object) {
+ template <typename T, size_t N, typename OBJECT>
+ CloneContext& Remove(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object);
if (std::find(vector.begin(), vector.end(), object) == vector.end()) {
TINT_ICE(Clone, Diagnostics())
@@ -397,12 +405,12 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted at the
/// front of the vector
/// @returns this CloneContext so calls can be chained
- template <typename T, typename OBJECT>
- CloneContext& InsertFront(const std::vector<T>& vector, OBJECT* object) {
+ template <typename T, size_t N, typename OBJECT>
+ CloneContext& InsertFront(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_front_;
- list.emplace_back(object);
+ list.Push(object);
return *this;
}
@@ -411,12 +419,12 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted at the
/// end of the vector
/// @returns this CloneContext so calls can be chained
- template <typename T, typename OBJECT>
- CloneContext& InsertBack(const std::vector<T>& vector, OBJECT* object) {
+ template <typename T, size_t N, typename OBJECT>
+ CloneContext& InsertBack(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_back_;
- list.emplace_back(object);
+ list.Push(object);
return *this;
}
@@ -426,8 +434,8 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted before
/// any occurrence of the clone of `before`
/// @returns this CloneContext so calls can be chained
- template <typename T, typename BEFORE, typename OBJECT>
- CloneContext& InsertBefore(const std::vector<T>& vector,
+ template <typename T, size_t N, typename BEFORE, typename OBJECT>
+ CloneContext& InsertBefore(const utils::Vector<T, N>& vector,
const BEFORE* before,
const OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, before);
@@ -440,7 +448,7 @@ class CloneContext {
auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_before_[before];
- list.emplace_back(object);
+ list.Push(object);
return *this;
}
@@ -450,8 +458,8 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted after
/// any occurrence of the clone of `after`
/// @returns this CloneContext so calls can be chained
- template <typename T, typename AFTER, typename OBJECT>
- CloneContext& InsertAfter(const std::vector<T>& vector,
+ template <typename T, size_t N, typename AFTER, typename OBJECT>
+ CloneContext& InsertAfter(const utils::Vector<T, N>& vector,
const AFTER* after,
const OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, after);
@@ -464,7 +472,7 @@ class CloneContext {
auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_after_[after];
- list.emplace_back(object);
+ list.Push(object);
return *this;
}
@@ -523,7 +531,7 @@ class CloneContext {
diag::List& Diagnostics() const;
/// A vector of const Cloneable*
- using CloneableList = std::vector<const Cloneable*>;
+ using CloneableList = utils::Vector<const Cloneable*, 4>;
/// Transformations to be applied to a list (vector)
struct ListTransforms {
@@ -544,12 +552,12 @@ class CloneContext {
CloneableList insert_back_;
/// A map of object in #src to the list of cloned objects in #dst.
- /// Clone(const std::vector<T*>& v) will use this to insert the map-value
+ /// Clone(const utils::Vector<T*>& v) will use this to insert the map-value
/// list into the target vector before cloning and inserting the map-key.
std::unordered_map<const Cloneable*, CloneableList> insert_before_;
/// A map of object in #src to the list of cloned objects in #dst.
- /// Clone(const std::vector<T*>& v) will use this to insert the map-value
+ /// Clone(const utils::Vector<T*>& v) will use this to insert the map-value
/// list into the target vector after cloning and inserting the map-key.
std::unordered_map<const Cloneable*, CloneableList> insert_after_;
};
@@ -562,9 +570,9 @@ class CloneContext {
std::unordered_map<Symbol, Symbol> cloned_symbols_;
/// Cloneable transform functions registered with ReplaceAll()
- std::vector<CloneableTransform> transforms_;
+ utils::Vector<CloneableTransform, 8> transforms_;
- /// Map of std::vector pointer to transforms for that list
+ /// Map of utils::Vector pointer to transforms for that list
std::unordered_map<const void*, ListTransforms> list_transforms_;
/// Symbol transform registered with ReplaceAll()
diff --git a/chromium/third_party/dawn/src/tint/clone_context_test.cc b/chromium/third_party/dawn/src/tint/clone_context_test.cc
index 46cc7208652..c8951515cbf 100644
--- a/chromium/third_party/dawn/src/tint/clone_context_test.cc
+++ b/chromium/third_party/dawn/src/tint/clone_context_test.cc
@@ -37,12 +37,13 @@ struct Node : public Castable<Node, Cloneable> {
const Node* node_b = nullptr,
const Node* node_c = nullptr)
: allocator(alloc), name(n), a(node_a), b(node_b), c(node_c) {}
+ Node(Node&&) = delete;
Allocator* const allocator;
Symbol name;
const Node* a = nullptr;
const Node* b = nullptr;
const Node* c = nullptr;
- std::vector<const Node*> vec;
+ utils::Vector<const Node*, 8> vec;
Node* Clone(CloneContext* ctx) const override {
auto* out = allocator->Create<Node>(ctx->Clone(name));
@@ -387,7 +388,7 @@ TEST_F(CloneContextNodeTest, CloneWithRemove) {
.Remove(original_root->vec, original_root->vec[1])
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 2u);
+ EXPECT_EQ(cloned_root->vec.Length(), 2u);
EXPECT_NE(cloned_root->vec[0], cloned_root->a);
EXPECT_NE(cloned_root->vec[1], cloned_root->c);
@@ -416,7 +417,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFront) {
.InsertFront(original_root->vec, insertion)
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 4u);
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_NE(cloned_root->vec[0], cloned_root->a);
EXPECT_NE(cloned_root->vec[1], cloned_root->b);
@@ -434,7 +435,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
ProgramBuilder builder;
auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
- original_root->vec = {};
+ original_root->vec.Clear();
Program original(std::move(builder));
ProgramBuilder cloned;
@@ -444,7 +445,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
.InsertFront(original_root->vec, insertion)
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 1u);
+ EXPECT_EQ(cloned_root->vec.Length(), 1u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
@@ -469,7 +470,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBack) {
.InsertBack(original_root->vec, insertion)
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 4u);
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@@ -483,7 +484,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
ProgramBuilder builder;
auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
- original_root->vec = {};
+ original_root->vec.Clear();
Program original(std::move(builder));
ProgramBuilder cloned;
@@ -493,7 +494,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
.InsertBack(original_root->vec, insertion)
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 1u);
+ EXPECT_EQ(cloned_root->vec.Length(), 1u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
@@ -504,7 +505,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
ProgramBuilder builder;
auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
- original_root->vec = {};
+ original_root->vec.Clear();
Program original(std::move(builder));
ProgramBuilder cloned;
@@ -516,7 +517,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
.InsertFront(original_root->vec, insertion_front)
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 2u);
+ EXPECT_EQ(cloned_root->vec.Length(), 2u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front"));
@@ -542,7 +543,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBefore) {
.InsertBefore(original_root->vec, original_root->vec[1], insertion)
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 4u);
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@@ -570,7 +571,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertAfter) {
.InsertAfter(original_root->vec, original_root->vec[1], insertion)
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 4u);
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@@ -602,7 +603,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertAfterInVectorNodeClone) {
auto* cloned_root = ctx.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 4u);
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@@ -634,7 +635,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBackInVectorNodeClone) {
auto* cloned_root = ctx.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 4u);
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@@ -666,7 +667,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBeforeAndAfterRemoved) {
.Remove(original_root->vec, original_root->vec[1])
.Clone(original_root);
- EXPECT_EQ(cloned_root->vec.size(), 4u);
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
diff --git a/chromium/third_party/dawn/src/tint/cmd/main.cc b/chromium/third_party/dawn/src/tint/cmd/main.cc
index 438e4a28d15..6f1234807f2 100644
--- a/chromium/third_party/dawn/src/tint/cmd/main.cc
+++ b/chromium/third_party/dawn/src/tint/cmd/main.cc
@@ -17,9 +17,10 @@
#include <iostream>
#include <limits>
#include <memory>
-#include <optional> // NOLINT(build/include_order)
+#include <optional>
#include <sstream>
#include <string>
+#include <unordered_map>
#include <vector>
#if TINT_BUILD_GLSL_WRITER
@@ -31,8 +32,10 @@
#include "spirv-tools/libspirv.hpp"
#endif // TINT_BUILD_SPV_READER
+#include "src/tint/ast/module.h"
#include "src/tint/utils/io/command.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/transform.h"
#include "src/tint/val/val.h"
#include "tint/tint.h"
@@ -66,6 +69,7 @@ enum class Format {
struct Options {
bool show_help = false;
+ bool verbose = false;
std::string input_filename;
std::string output_file = "-"; // Default to stdout
@@ -83,10 +87,10 @@ struct Options {
std::vector<std::string> transforms;
- bool use_fxc = false;
+ std::string fxc_path;
std::string dxc_path;
std::string xcrun_path;
- std::vector<std::string> overrides;
+ std::unordered_map<std::string, double> overrides;
std::optional<tint::sem::BindingPoint> hlsl_root_constant_binding_point;
};
@@ -119,14 +123,15 @@ ${transforms}
used for num_workgroups in HLSL. If not specified, then
default to binding 0 of the largest used group plus 1,
or group 0 if no resource bound.
- --validate -- Validates the generated shader
- --fxc -- Ask to validate HLSL output using FXC instead of DXC.
- When specified, automatically enables --validate
+ --validate -- Validates the generated shader with all available validators
+ --fxc -- Path to FXC dll, used to validate HLSL output.
+ When specified, automatically enables HLSL validation with FXC
--dxc -- Path to DXC executable, used to validate HLSL output.
- When specified, automatically enables --validate
+ When specified, automatically enables HLSL validation with DXC
--xcrun -- Path to xcrun executable, used to validate MSL output.
- When specified, automatically enables --validate
- --overrides -- Pipeline overrides as NAME=VALUE, comma-separated.)";
+ When specified, automatically enables MSL validation
+ --overrides -- Override values as IDENTIFIER=VALUE, comma-separated.
+)";
Format parse_format(const std::string& fmt) {
(void)fmt;
@@ -215,18 +220,26 @@ Format infer_format(const std::string& filename) {
return Format::kNone;
}
-std::vector<std::string> split_on_comma(std::string list) {
+std::vector<std::string> split_on_char(std::string list, char c) {
std::vector<std::string> res;
std::stringstream str(list);
while (str.good()) {
std::string substr;
- getline(str, substr, ',');
+ getline(str, substr, c);
res.push_back(substr);
}
return res;
}
+std::vector<std::string> split_on_comma(std::string list) {
+ return split_on_char(list, ',');
+}
+
+std::vector<std::string> split_on_equal(std::string list) {
+ return split_on_char(list, '=');
+}
+
std::optional<uint64_t> parse_unsigned_number(std::string number) {
for (char c : number) {
if (!std::isdigit(c)) {
@@ -387,6 +400,8 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
} else if (arg == "-h" || arg == "--help") {
opts->show_help = true;
+ } else if (arg == "-v" || arg == "--verbose") {
+ opts->verbose = true;
} else if (arg == "--transform") {
++i;
if (i >= args.size()) {
@@ -405,8 +420,12 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
} else if (arg == "--validate") {
opts->validate = true;
} else if (arg == "--fxc") {
- opts->validate = true;
- opts->use_fxc = true;
+ ++i;
+ if (i >= args.size()) {
+ std::cerr << "Missing value for " << arg << std::endl;
+ return false;
+ }
+ opts->fxc_path = args[i];
} else if (arg == "--dxc") {
++i;
if (i >= args.size()) {
@@ -414,7 +433,6 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
return false;
}
opts->dxc_path = args[i];
- opts->validate = true;
} else if (arg == "--xcrun") {
++i;
if (i >= args.size()) {
@@ -429,7 +447,10 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
std::cerr << "Missing value for " << arg << std::endl;
return false;
}
- opts->overrides = split_on_comma(args[i]);
+ for (const auto& o : split_on_comma(args[i])) {
+ auto parts = split_on_equal(o);
+ opts->overrides.insert({parts[0], std::stod(parts[1])});
+ }
} else if (arg == "--hlsl-root-constant-binding-point") {
++i;
if (i >= args.size()) {
@@ -788,30 +809,86 @@ bool GenerateHlsl(const tint::Program* program, const Options& options) {
return false;
}
- if (options.validate) {
- tint::val::Result res;
- if (options.use_fxc) {
-#ifdef _WIN32
- res = tint::val::HlslUsingFXC(result.hlsl, result.entry_points, options.overrides);
-#else
- res.failed = true;
- res.output = "FXC can only be used on Windows. Sorry :X";
-#endif // _WIN32
- } else {
+ // If --fxc or --dxc was passed, then we must explicitly find and validate with that respective
+ // compiler.
+ const bool must_validate_dxc = !options.dxc_path.empty();
+ const bool must_validate_fxc = !options.fxc_path.empty();
+ if (options.validate || must_validate_dxc || must_validate_fxc) {
+ tint::val::Result dxc_res;
+ bool dxc_found = false;
+ if (options.validate || must_validate_dxc) {
auto dxc =
tint::utils::Command::LookPath(options.dxc_path.empty() ? "dxc" : options.dxc_path);
if (dxc.Found()) {
- res = tint::val::HlslUsingDXC(dxc.Path(), result.hlsl, result.entry_points,
- options.overrides);
- } else {
- res.failed = true;
- res.output = "DXC executable not found. Cannot validate";
+ dxc_found = true;
+
+ auto enable_list = program->AST().Enables();
+ bool dxc_require_16bit_types = false;
+ for (auto enable : enable_list) {
+ if (enable->extension == tint::ast::Extension::kF16) {
+ dxc_require_16bit_types = true;
+ break;
+ }
+ }
+
+ dxc_res = tint::val::HlslUsingDXC(dxc.Path(), result.hlsl, result.entry_points,
+ dxc_require_16bit_types);
+ } else if (must_validate_dxc) {
+ // DXC was explicitly requested. Error if it could not be found.
+ dxc_res.failed = true;
+ dxc_res.output =
+ "DXC executable '" + options.dxc_path + "' not found. Cannot validate";
}
}
- if (res.failed) {
- std::cerr << res.output << std::endl;
+
+ tint::val::Result fxc_res;
+ bool fxc_found = false;
+ if (options.validate || must_validate_fxc) {
+ auto fxc = tint::utils::Command::LookPath(
+ options.fxc_path.empty() ? tint::val::kFxcDLLName : options.fxc_path);
+
+#ifdef _WIN32
+ if (fxc.Found()) {
+ fxc_found = true;
+ fxc_res = tint::val::HlslUsingFXC(fxc.Path(), result.hlsl, result.entry_points);
+ } else if (must_validate_fxc) {
+ // FXC was explicitly requested. Error if it could not be found.
+ fxc_res.failed = true;
+ fxc_res.output = "FXC DLL '" + options.fxc_path + "' not found. Cannot validate";
+ }
+#else
+ if (must_validate_dxc) {
+ fxc_res.failed = true;
+ fxc_res.output = "FXC can only be used on Windows.";
+ }
+#endif // _WIN32
+ }
+
+ if (fxc_res.failed) {
+ std::cerr << "FXC validation failure:" << std::endl << fxc_res.output << std::endl;
+ }
+ if (dxc_res.failed) {
+ std::cerr << "DXC validation failure:" << std::endl << dxc_res.output << std::endl;
+ }
+ if (fxc_res.failed || dxc_res.failed) {
return false;
}
+ if (!fxc_found && !dxc_found) {
+ std::cerr << "Couldn't find FXC or DXC. Cannot validate" << std::endl;
+ return false;
+ }
+ if (options.verbose) {
+ if (fxc_found && !fxc_res.failed) {
+ std::cout << "Passed FXC validation" << std::endl;
+ std::cout << fxc_res.output;
+ std::cout << std::endl;
+ }
+ if (dxc_found && !dxc_res.failed) {
+ std::cout << "Passed DXC validation" << std::endl;
+ std::cout << dxc_res.output;
+ std::cout << std::endl;
+ }
+ }
}
return true;
@@ -930,23 +1007,73 @@ int main(int argc, const char** argv) {
struct TransformFactory {
const char* name;
- std::function<void(tint::transform::Manager& manager, tint::transform::DataMap& inputs)>
+ /// Build and adds the transform to the transform manager.
+ /// Parameters:
+ /// inspector - an inspector created from the parsed program
+ /// manager - the transform manager. Add transforms to this.
+ /// inputs - the input data to the transform manager. Add inputs to this.
+ /// Returns true on success, false on error (program will immediately exit)
+ std::function<bool(tint::inspector::Inspector& inspector,
+ tint::transform::Manager& manager,
+ tint::transform::DataMap& inputs)>
make;
};
std::vector<TransformFactory> transforms = {
{"first_index_offset",
- [](tint::transform::Manager& m, tint::transform::DataMap& i) {
+ [](tint::inspector::Inspector&, tint::transform::Manager& m, tint::transform::DataMap& i) {
i.Add<tint::transform::FirstIndexOffset::BindingPoint>(0, 0);
m.Add<tint::transform::FirstIndexOffset>();
+ return true;
}},
{"fold_trivial_single_use_lets",
- [](tint::transform::Manager& m, tint::transform::DataMap&) {
+ [](tint::inspector::Inspector&, tint::transform::Manager& m, tint::transform::DataMap&) {
m.Add<tint::transform::FoldTrivialSingleUseLets>();
+ return true;
+ }},
+ {"renamer",
+ [](tint::inspector::Inspector&, tint::transform::Manager& m, tint::transform::DataMap&) {
+ m.Add<tint::transform::Renamer>();
+ return true;
+ }},
+ {"robustness",
+ [](tint::inspector::Inspector&, tint::transform::Manager& m, tint::transform::DataMap&) {
+ m.Add<tint::transform::Robustness>();
+ return true;
+ }},
+ {"substitute_override",
+ [&](tint::inspector::Inspector& inspector, tint::transform::Manager& m,
+ tint::transform::DataMap& i) {
+ tint::transform::SubstituteOverride::Config cfg;
+
+ std::unordered_map<tint::OverrideId, double> values;
+ values.reserve(options.overrides.size());
+
+ for (const auto& [name, value] : options.overrides) {
+ if (name.empty()) {
+ std::cerr << "empty override name";
+ return false;
+ }
+ if (isdigit(name[0])) {
+ tint::OverrideId id{
+ static_cast<decltype(tint::OverrideId::value)>(atoi(name.c_str()))};
+ values.emplace(id, value);
+ } else {
+ auto override_names = inspector.GetNamedOverrideIds();
+ auto it = override_names.find(name);
+ if (it == override_names.end()) {
+ std::cerr << "unknown override '" << name << "'";
+ return false;
+ }
+ values.emplace(it->second, value);
+ }
+ }
+
+ cfg.map = std::move(values);
+
+ i.Add<tint::transform::SubstituteOverride::Config>(cfg);
+ m.Add<tint::transform::SubstituteOverride>();
+ return true;
}},
- {"renamer", [](tint::transform::Manager& m,
- tint::transform::DataMap&) { m.Add<tint::transform::Renamer>(); }},
- {"robustness", [](tint::transform::Manager& m,
- tint::transform::DataMap&) { m.Add<tint::transform::Robustness>(); }},
};
auto transform_names = [&] {
std::stringstream names;
@@ -1076,8 +1203,55 @@ int main(int argc, const char** argv) {
return 1;
}
+ tint::inspector::Inspector inspector(program.get());
+
+ if (options.dump_inspector_bindings) {
+ std::cout << std::string(80, '-') << std::endl;
+ auto entry_points = inspector.GetEntryPoints();
+ if (!inspector.error().empty()) {
+ std::cerr << "Failed to get entry points from Inspector: " << inspector.error()
+ << std::endl;
+ return 1;
+ }
+
+ for (auto& entry_point : entry_points) {
+ auto bindings = inspector.GetResourceBindings(entry_point.name);
+ if (!inspector.error().empty()) {
+ std::cerr << "Failed to get bindings from Inspector: " << inspector.error()
+ << std::endl;
+ return 1;
+ }
+ std::cout << "Entry Point = " << entry_point.name << std::endl;
+ for (auto& binding : bindings) {
+ std::cout << "\t[" << binding.bind_group << "][" << binding.binding
+ << "]:" << std::endl;
+ std::cout << "\t\t resource_type = " << ResourceTypeToString(binding.resource_type)
+ << std::endl;
+ std::cout << "\t\t dim = " << TextureDimensionToString(binding.dim) << std::endl;
+ std::cout << "\t\t sampled_kind = " << SampledKindToString(binding.sampled_kind)
+ << std::endl;
+ std::cout << "\t\t image_format = " << TexelFormatToString(binding.image_format)
+ << std::endl;
+ }
+ }
+ std::cout << std::string(80, '-') << std::endl;
+ }
+
tint::transform::Manager transform_manager;
tint::transform::DataMap transform_inputs;
+
+ // If overrides are provided, add the SubstituteOverride transform.
+ if (!options.overrides.empty()) {
+ for (auto& t : transforms) {
+ if (t.name == std::string("substitute_override")) {
+ if (!t.make(inspector, transform_manager, transform_inputs)) {
+ return 1;
+ }
+ break;
+ }
+ }
+ }
+
for (const auto& name : options.transforms) {
// TODO(dsinclair): The vertex pulling transform requires setup code to
// be run that needs user input. Should we find a way to support that here
@@ -1086,7 +1260,9 @@ int main(int argc, const char** argv) {
bool found = false;
for (auto& t : transforms) {
if (t.name == name) {
- t.make(transform_manager, transform_inputs);
+ if (!t.make(inspector, transform_manager, transform_inputs)) {
+ return 1;
+ }
found = true;
break;
}
@@ -1140,39 +1316,6 @@ int main(int argc, const char** argv) {
*program = std::move(out.program);
- if (options.dump_inspector_bindings) {
- std::cout << std::string(80, '-') << std::endl;
- tint::inspector::Inspector inspector(program.get());
- auto entry_points = inspector.GetEntryPoints();
- if (!inspector.error().empty()) {
- std::cerr << "Failed to get entry points from Inspector: " << inspector.error()
- << std::endl;
- return 1;
- }
-
- for (auto& entry_point : entry_points) {
- auto bindings = inspector.GetResourceBindings(entry_point.name);
- if (!inspector.error().empty()) {
- std::cerr << "Failed to get bindings from Inspector: " << inspector.error()
- << std::endl;
- return 1;
- }
- std::cout << "Entry Point = " << entry_point.name << std::endl;
- for (auto& binding : bindings) {
- std::cout << "\t[" << binding.bind_group << "][" << binding.binding
- << "]:" << std::endl;
- std::cout << "\t\t resource_type = " << ResourceTypeToString(binding.resource_type)
- << std::endl;
- std::cout << "\t\t dim = " << TextureDimensionToString(binding.dim) << std::endl;
- std::cout << "\t\t sampled_kind = " << SampledKindToString(binding.sampled_kind)
- << std::endl;
- std::cout << "\t\t image_format = " << TexelFormatToString(binding.image_format)
- << std::endl;
- }
- }
- std::cout << std::string(80, '-') << std::endl;
- }
-
bool success = false;
switch (options.format) {
case Format::kSpirv:
diff --git a/chromium/third_party/dawn/src/tint/demangler.cc b/chromium/third_party/dawn/src/tint/demangler.cc
index 0116be0ad43..d68a62a8259 100644
--- a/chromium/third_party/dawn/src/tint/demangler.cc
+++ b/chromium/third_party/dawn/src/tint/demangler.cc
@@ -49,7 +49,7 @@ std::string Demangler::Demangle(const SymbolTable& symbols, const std::string& s
auto len = end_idx - start_idx;
auto id = str.substr(start_idx, len);
- Symbol sym(std::stoi(id), symbols.ProgramID());
+ Symbol sym(static_cast<uint32_t>(std::stoi(id)), symbols.ProgramID());
out << symbols.NameFor(sym);
pos = end_idx;
diff --git a/chromium/third_party/dawn/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn b/chromium/third_party/dawn/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn
index 69ef3fef911..58a36ea5662 100644
--- a/chromium/third_party/dawn/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn
+++ b/chromium/third_party/dawn/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn
@@ -46,6 +46,8 @@ if (build_with_chromium) {
"expression_size.cc",
"expression_size.h",
"fuzzer.cc",
+ "jump_tracker.cc",
+ "jump_tracker.h",
"mutation.cc",
"mutation.h",
"mutation_finder.cc",
@@ -54,6 +56,8 @@ if (build_with_chromium) {
"mutation_finders/change_binary_operators.h",
"mutation_finders/change_unary_operators.cc",
"mutation_finders/change_unary_operators.h",
+ "mutation_finders/delete_statements.cc",
+ "mutation_finders/delete_statements.h",
"mutation_finders/replace_identifiers.cc",
"mutation_finders/replace_identifiers.h",
"mutation_finders/wrap_unary_operators.cc",
@@ -62,6 +66,8 @@ if (build_with_chromium) {
"mutations/change_binary_operator.h",
"mutations/change_unary_operator.cc",
"mutations/change_unary_operator.h",
+ "mutations/delete_statement.cc",
+ "mutations/delete_statement.h",
"mutations/replace_identifier.cc",
"mutations/replace_identifier.h",
"mutations/wrap_unary_operator.cc",
diff --git a/chromium/third_party/dawn/src/tint/inspector/entry_point.h b/chromium/third_party/dawn/src/tint/inspector/entry_point.h
index b9ac4e429e0..5d119d4a40a 100644
--- a/chromium/third_party/dawn/src/tint/inspector/entry_point.h
+++ b/chromium/third_party/dawn/src/tint/inspector/entry_point.h
@@ -15,10 +15,13 @@
#ifndef SRC_TINT_INSPECTOR_ENTRY_POINT_H_
#define SRC_TINT_INSPECTOR_ENTRY_POINT_H_
+#include <optional>
#include <string>
#include <tuple>
#include <vector>
+#include "tint/override_id.h"
+
#include "src/tint/ast/interpolate_attribute.h"
#include "src/tint/ast/pipeline_stage.h"
@@ -92,14 +95,13 @@ InterpolationType ASTToInspectorInterpolationType(ast::InterpolationType ast_typ
/// @returns the publicly visible equivalent
InterpolationSampling ASTToInspectorInterpolationSampling(ast::InterpolationSampling sampling);
-/// Reflection data about a pipeline overridable constant referenced by an entry
-/// point
-struct OverridableConstant {
- /// Name of the constant
+/// Reflection data about an override variable referenced by an entry point
+struct Override {
+ /// Name of the override
std::string name;
- /// ID of the constant
- uint16_t numeric_id;
+ /// ID of the override
+ OverrideId id;
/// Type of the scalar
enum class Type {
@@ -112,12 +114,24 @@ struct OverridableConstant {
/// Type of the scalar
Type type;
- /// Does this pipeline overridable constant have an initializer?
+ /// Does this override have an initializer?
bool is_initialized = false;
- /// Does this pipeline overridable constant have a numeric ID specified
- /// explicitly?
- bool is_numeric_id_specified = false;
+ /// Does this override have a numeric ID specified explicitly?
+ bool is_id_specified = false;
+};
+
+/// The pipeline stage
+enum class PipelineStage { kVertex, kFragment, kCompute };
+
+/// WorkgroupSize describes the dimensions of the workgroup grid for a compute shader.
+struct WorkgroupSize {
+ /// The 'x' dimension of the workgroup grid
+ uint32_t x = 1;
+ /// The 'y' dimension of the workgroup grid
+ uint32_t y = 1;
+ /// The 'z' dimension of the workgroup grid
+ uint32_t z = 1;
};
/// Reflection data for an entry point in the shader.
@@ -135,19 +149,17 @@ struct EntryPoint {
/// Remapped entry point name in the backend
std::string remapped_name;
/// The entry point stage
- ast::PipelineStage stage = ast::PipelineStage::kNone;
- /// The workgroup x size
- uint32_t workgroup_size_x = 0;
- /// The workgroup y size
- uint32_t workgroup_size_y = 0;
- /// The workgroup z size
- uint32_t workgroup_size_z = 0;
+ PipelineStage stage;
+ /// The workgroup size. If PipelineStage is kCompute and this holds no value, then the workgroup
+ /// size is derived from an override-expression. In this situation you first need to run the
+ /// tint::transform::SubstituteOverride transform before using the inspector.
+ std::optional<WorkgroupSize> workgroup_size;
/// List of the input variable accessed via this entry point.
std::vector<StageVariable> input_variables;
/// List of the output variable accessed via this entry point.
std::vector<StageVariable> output_variables;
/// List of the pipeline overridable constants accessed via this entry point.
- std::vector<OverridableConstant> overridable_constants;
+ std::vector<Override> overrides;
/// Does the entry point use the sample_mask builtin as an input builtin
/// variable.
bool input_sample_mask_used = false;
@@ -163,12 +175,6 @@ struct EntryPoint {
bool sample_index_used = false;
/// Does the entry point use the num_workgroups builtin
bool num_workgroups_used = false;
-
- /// @returns the size of the workgroup in {x,y,z} format
- std::tuple<uint32_t, uint32_t, uint32_t> workgroup_size() {
- return std::tuple<uint32_t, uint32_t, uint32_t>(workgroup_size_x, workgroup_size_y,
- workgroup_size_z);
- }
};
} // namespace tint::inspector
diff --git a/chromium/third_party/dawn/src/tint/inspector/inspector.cc b/chromium/third_party/dawn/src/tint/inspector/inspector.cc
index 569a1042e6b..60734709d8f 100644
--- a/chromium/third_party/dawn/src/tint/inspector/inspector.cc
+++ b/chromium/third_party/dawn/src/tint/inspector/inspector.cc
@@ -22,12 +22,17 @@
#include "src/tint/ast/extension.h"
#include "src/tint/ast/float_literal_expression.h"
#include "src/tint/ast/id_attribute.h"
+#include "src/tint/ast/int_literal_expression.h"
#include "src/tint/ast/interpolate_attribute.h"
#include "src/tint/ast/location_attribute.h"
#include "src/tint/ast/module.h"
+#include "src/tint/ast/override.h"
+#include "src/tint/ast/var.h"
#include "src/tint/sem/array.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
#include "src/tint/sem/f16.h"
#include "src/tint/sem/f32.h"
#include "src/tint/sem/function.h"
@@ -44,6 +49,7 @@
#include "src/tint/sem/vector.h"
#include "src/tint/sem/void.h"
#include "src/tint/utils/math.h"
+#include "src/tint/utils/string.h"
#include "src/tint/utils/unique_vector.h"
namespace tint::inspector {
@@ -101,7 +107,7 @@ std::tuple<ComponentType, CompositionType> CalculateComponentAndComposition(cons
std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
const sem::Type* type,
- const ast::AttributeList& attributes) {
+ utils::VectorRef<const ast::Attribute*> attributes) {
auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
if (type->is_integer_scalar_or_vector()) {
return {InterpolationType::kFlat, InterpolationSampling::kNone};
@@ -140,16 +146,32 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
EntryPoint entry_point;
entry_point.name = program_->Symbols().NameFor(func->symbol);
entry_point.remapped_name = program_->Symbols().NameFor(func->symbol);
- entry_point.stage = func->PipelineStage();
- auto wgsize = sem->WorkgroupSize();
- entry_point.workgroup_size_x = wgsize[0].value;
- entry_point.workgroup_size_y = wgsize[1].value;
- entry_point.workgroup_size_z = wgsize[2].value;
- if (wgsize[0].overridable_const || wgsize[1].overridable_const ||
- wgsize[2].overridable_const) {
- // TODO(crbug.com/tint/713): Handle overridable constants.
- TINT_ASSERT(Inspector, false);
+ switch (func->PipelineStage()) {
+ case ast::PipelineStage::kCompute: {
+ entry_point.stage = PipelineStage::kCompute;
+
+ auto wgsize = sem->WorkgroupSize();
+ if (!wgsize[0].overridable_const && !wgsize[1].overridable_const &&
+ !wgsize[2].overridable_const) {
+ entry_point.workgroup_size = {wgsize[0].value, wgsize[1].value,
+ wgsize[2].value};
+ }
+ break;
+ }
+ case ast::PipelineStage::kFragment: {
+ entry_point.stage = PipelineStage::kFragment;
+ break;
+ }
+ case ast::PipelineStage::kVertex: {
+ entry_point.stage = PipelineStage::kVertex;
+ break;
+ }
+ default: {
+ TINT_UNREACHABLE(Inspector, diagnostics_)
+ << "invalid pipeline stage for entry point '" << entry_point.name << "'";
+ break;
+ }
}
for (auto* param : sem->Parameters()) {
@@ -158,15 +180,15 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
entry_point.input_variables);
entry_point.input_position_used |= ContainsBuiltin(
- ast::Builtin::kPosition, param->Type(), param->Declaration()->attributes);
+ ast::BuiltinValue::kPosition, param->Type(), param->Declaration()->attributes);
entry_point.front_facing_used |= ContainsBuiltin(
- ast::Builtin::kFrontFacing, param->Type(), param->Declaration()->attributes);
+ ast::BuiltinValue::kFrontFacing, param->Type(), param->Declaration()->attributes);
entry_point.sample_index_used |= ContainsBuiltin(
- ast::Builtin::kSampleIndex, param->Type(), param->Declaration()->attributes);
+ ast::BuiltinValue::kSampleIndex, param->Type(), param->Declaration()->attributes);
entry_point.input_sample_mask_used |= ContainsBuiltin(
- ast::Builtin::kSampleMask, param->Type(), param->Declaration()->attributes);
+ ast::BuiltinValue::kSampleMask, param->Type(), param->Declaration()->attributes);
entry_point.num_workgroups_used |= ContainsBuiltin(
- ast::Builtin::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
+ ast::BuiltinValue::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
}
if (!sem->ReturnType()->Is<sem::Void>()) {
@@ -174,7 +196,7 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
entry_point.output_variables);
entry_point.output_sample_mask_used = ContainsBuiltin(
- ast::Builtin::kSampleMask, sem->ReturnType(), func->return_type_attributes);
+ ast::BuiltinValue::kSampleMask, sem->ReturnType(), func->return_type_attributes);
}
for (auto* var : sem->TransitivelyReferencedGlobals()) {
@@ -183,29 +205,29 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
auto name = program_->Symbols().NameFor(decl->symbol);
auto* global = var->As<sem::GlobalVariable>();
- if (global && global->IsOverridable()) {
- OverridableConstant overridable_constant;
- overridable_constant.name = name;
- overridable_constant.numeric_id = global->ConstantId();
+ if (global && global->Declaration()->Is<ast::Override>()) {
+ Override override;
+ override.name = name;
+ override.id = global->OverrideId();
auto* type = var->Type();
TINT_ASSERT(Inspector, type->is_scalar());
if (type->is_bool_scalar_or_vector()) {
- overridable_constant.type = OverridableConstant::Type::kBool;
+ override.type = Override::Type::kBool;
} else if (type->is_float_scalar()) {
- overridable_constant.type = OverridableConstant::Type::kFloat32;
+ override.type = Override::Type::kFloat32;
} else if (type->is_signed_integer_scalar()) {
- overridable_constant.type = OverridableConstant::Type::kInt32;
+ override.type = Override::Type::kInt32;
} else if (type->is_unsigned_integer_scalar()) {
- overridable_constant.type = OverridableConstant::Type::kUint32;
+ override.type = Override::Type::kUint32;
} else {
TINT_UNREACHABLE(Inspector, diagnostics_);
}
- overridable_constant.is_initialized = global->Declaration()->constructor;
- overridable_constant.is_numeric_id_specified =
+ override.is_initialized = global->Declaration()->constructor;
+ override.is_id_specified =
ast::HasAttribute<ast::IdAttribute>(global->Declaration()->attributes);
- entry_point.overridable_constants.push_back(overridable_constant);
+ entry_point.overrides.push_back(override);
}
}
@@ -215,37 +237,37 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
return result;
}
-std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
- std::map<uint32_t, Scalar> result;
+std::map<OverrideId, Scalar> Inspector::GetOverrideDefaultValues() {
+ std::map<OverrideId, Scalar> result;
for (auto* var : program_->AST().GlobalVariables()) {
auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
- if (!global || !global->IsOverridable()) {
+ if (!global || !global->Declaration()->Is<ast::Override>()) {
continue;
}
- // If there are conflicting defintions for a constant id, that is invalid
+ // If there are conflicting defintions for an override id, that is invalid
// WGSL, so the resolver should catch it. Thus here the inspector just
- // assumes all definitions of the constant id are the same, so only needs
- // to find the first reference to constant id.
- uint32_t constant_id = global->ConstantId();
- if (result.find(constant_id) != result.end()) {
+ // assumes all definitions of the override id are the same, so only needs
+ // to find the first reference to override id.
+ OverrideId override_id = global->OverrideId();
+ if (result.find(override_id) != result.end()) {
continue;
}
if (!var->constructor) {
- result[constant_id] = Scalar();
+ result[override_id] = Scalar();
continue;
}
auto* literal = var->constructor->As<ast::LiteralExpression>();
if (!literal) {
// This is invalid WGSL, but handling gracefully.
- result[constant_id] = Scalar();
+ result[override_id] = Scalar();
continue;
}
if (auto* l = literal->As<ast::BoolLiteralExpression>()) {
- result[constant_id] = Scalar(l->value);
+ result[override_id] = Scalar(l->value);
continue;
}
@@ -253,32 +275,32 @@ std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
switch (l->suffix) {
case ast::IntLiteralExpression::Suffix::kNone:
case ast::IntLiteralExpression::Suffix::kI:
- result[constant_id] = Scalar(static_cast<int32_t>(l->value));
+ result[override_id] = Scalar(static_cast<int32_t>(l->value));
continue;
case ast::IntLiteralExpression::Suffix::kU:
- result[constant_id] = Scalar(static_cast<uint32_t>(l->value));
+ result[override_id] = Scalar(static_cast<uint32_t>(l->value));
continue;
}
}
if (auto* l = literal->As<ast::FloatLiteralExpression>()) {
- result[constant_id] = Scalar(static_cast<float>(l->value));
+ result[override_id] = Scalar(static_cast<float>(l->value));
continue;
}
- result[constant_id] = Scalar();
+ result[override_id] = Scalar();
}
return result;
}
-std::map<std::string, uint32_t> Inspector::GetConstantNameToIdMap() {
- std::map<std::string, uint32_t> result;
+std::map<std::string, OverrideId> Inspector::GetNamedOverrideIds() {
+ std::map<std::string, OverrideId> result;
for (auto* var : program_->AST().GlobalVariables()) {
auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
- if (global && global->IsOverridable()) {
+ if (global && global->Declaration()->Is<ast::Override>()) {
auto name = program_->Symbols().NameFor(var->symbol);
- result[name] = global->ConstantId();
+ result[name] = global->OverrideId();
}
}
return result;
@@ -483,7 +505,7 @@ std::vector<ResourceBinding> Inspector::GetExternalTextureResourceBindings(
ResourceBinding::ResourceType::kExternalTexture);
}
-std::vector<sem::SamplerTexturePair> Inspector::GetSamplerTextureUses(
+utils::Vector<sem::SamplerTexturePair, 4> Inspector::GetSamplerTextureUses(
const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
@@ -548,9 +570,9 @@ uint32_t Inspector::GetWorkgroupStorageSize(const std::string& entry_point) {
std::vector<std::string> Inspector::GetUsedExtensionNames() {
auto& extensions = program_->Sem().Module()->Extensions();
std::vector<std::string> out;
- out.reserve(extensions.size());
+ out.reserve(extensions.Length());
for (auto ext : extensions) {
- out.push_back(ast::str(ext));
+ out.push_back(utils::ToString(ext));
}
return out;
}
@@ -562,7 +584,7 @@ std::vector<std::pair<std::string, Source>> Inspector::GetEnableDirectives() {
auto global_decls = program_->AST().GlobalDeclarations();
for (auto* node : global_decls) {
if (auto* ext = node->As<ast::Enable>()) {
- result.push_back({ast::str(ext->extension), ext->source});
+ result.push_back({utils::ToString(ext->extension), ext->source});
}
}
@@ -586,7 +608,7 @@ const ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
void Inspector::AddEntryPointInOutVariables(std::string name,
const sem::Type* type,
- const ast::AttributeList& attributes,
+ utils::VectorRef<const ast::Attribute*> attributes,
std::vector<StageVariable>& variables) const {
// Skip builtins.
if (ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
@@ -623,9 +645,9 @@ void Inspector::AddEntryPointInOutVariables(std::string name,
variables.push_back(stage_variable);
}
-bool Inspector::ContainsBuiltin(ast::Builtin builtin,
+bool Inspector::ContainsBuiltin(ast::BuiltinValue builtin,
const sem::Type* type,
- const ast::AttributeList& attributes) const {
+ utils::VectorRef<const ast::Attribute*> attributes) const {
auto* unwrapped_type = type->UnwrapRef();
if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
@@ -767,7 +789,7 @@ void Inspector::GenerateSamplerTargets() {
}
sampler_targets_ = std::make_unique<
- std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair>>>();
+ std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair, 4>>>();
auto& sem = program_->Sem();
@@ -810,28 +832,27 @@ void Inspector::GenerateSamplerTargets() {
continue;
}
- auto* t = c->args[texture_index];
- auto* s = c->args[sampler_index];
+ auto* t = c->args[static_cast<size_t>(texture_index)];
+ auto* s = c->args[static_cast<size_t>(sampler_index)];
- GetOriginatingResources(std::array<const ast::Expression*, 2>{t, s},
- [&](std::array<const sem::GlobalVariable*, 2> globals) {
- auto* texture = globals[0];
- sem::BindingPoint texture_binding_point = {
- texture->Declaration()->BindingPoint().group->value,
- texture->Declaration()->BindingPoint().binding->value};
+ GetOriginatingResources(
+ std::array<const ast::Expression*, 2>{t, s},
+ [&](std::array<const sem::GlobalVariable*, 2> globals) {
+ auto* texture = globals[0]->Declaration()->As<ast::Var>();
+ sem::BindingPoint texture_binding_point = {texture->BindingPoint().group->value,
+ texture->BindingPoint().binding->value};
- auto* sampler = globals[1];
- sem::BindingPoint sampler_binding_point = {
- sampler->Declaration()->BindingPoint().group->value,
- sampler->Declaration()->BindingPoint().binding->value};
+ auto* sampler = globals[1]->Declaration()->As<ast::Var>();
+ sem::BindingPoint sampler_binding_point = {sampler->BindingPoint().group->value,
+ sampler->BindingPoint().binding->value};
- for (auto* entry_point : entry_points) {
- const auto& ep_name = program_->Symbols().NameFor(
- entry_point->Declaration()->symbol);
- (*sampler_targets_)[ep_name].add(
- {sampler_binding_point, texture_binding_point});
- }
- });
+ for (auto* entry_point : entry_points) {
+ const auto& ep_name =
+ program_->Symbols().NameFor(entry_point->Declaration()->symbol);
+ (*sampler_targets_)[ep_name].Add(
+ {sampler_binding_point, texture_binding_point});
+ }
+ });
}
}
@@ -847,7 +868,7 @@ void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> ex
std::array<const sem::GlobalVariable*, N> globals{};
std::array<const sem::Parameter*, N> parameters{};
- utils::UniqueVector<const ast::CallExpression*> callsites;
+ utils::UniqueVector<const ast::CallExpression*, 8> callsites;
for (size_t i = 0; i < N; i++) {
const sem::Variable* source_var = sem.Get(exprs[i])->SourceVariable();
@@ -861,7 +882,7 @@ void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> ex
return;
}
for (auto* call : func->CallSites()) {
- callsites.add(call->Declaration());
+ callsites.Add(call->Declaration());
}
parameters[i] = param;
} else {
@@ -872,7 +893,7 @@ void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> ex
}
}
- if (callsites.size()) {
+ if (callsites.Length()) {
for (auto* call_expr : callsites) {
// Make a copy of the expressions for this callsite
std::array<const ast::Expression*, N> call_exprs = exprs;
diff --git a/chromium/third_party/dawn/src/tint/inspector/inspector.h b/chromium/third_party/dawn/src/tint/inspector/inspector.h
index a5aee178ea0..f3fe27008a9 100644
--- a/chromium/third_party/dawn/src/tint/inspector/inspector.h
+++ b/chromium/third_party/dawn/src/tint/inspector/inspector.h
@@ -23,6 +23,8 @@
#include <utility>
#include <vector>
+#include "tint/override_id.h"
+
#include "src/tint/inspector/entry_point.h"
#include "src/tint/inspector/resource_binding.h"
#include "src/tint/inspector/scalar.h"
@@ -53,11 +55,11 @@ class Inspector {
/// @returns vector of entry point information
std::vector<EntryPoint> GetEntryPoints();
- /// @returns map of const_id to initial value
- std::map<uint32_t, Scalar> GetConstantIDs();
+ /// @returns map of override identifier to initial value
+ std::map<OverrideId, Scalar> GetOverrideDefaultValues();
/// @returns map of module-constant name to pipeline constant ID
- std::map<std::string, uint32_t> GetConstantNameToIdMap();
+ std::map<std::string, OverrideId> GetNamedOverrideIds();
/// @param entry_point name of the entry point to get information about.
/// @returns the total size of shared storage required by an entry point,
@@ -120,7 +122,7 @@ class Inspector {
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the sampler/texture sampling pairs that are used
/// by that entry point.
- std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(const std::string& entry_point);
+ utils::Vector<sem::SamplerTexturePair, 4> GetSamplerTextureUses(const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @param placeholder the sampler binding point to use for texture-only
@@ -151,7 +153,8 @@ class Inspector {
private:
const Program* program_;
diag::List diagnostics_;
- std::unique_ptr<std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair>>>
+ std::unique_ptr<
+ std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair, 4>>>
sampler_targets_;
/// @param name name of the entry point to find
@@ -168,15 +171,15 @@ class Inspector {
/// @param variables the list to add the variables to
void AddEntryPointInOutVariables(std::string name,
const sem::Type* type,
- const ast::AttributeList& attributes,
+ utils::VectorRef<const ast::Attribute*> attributes,
std::vector<StageVariable>& variables) const;
/// Recursively determine if the type contains builtin.
/// If `type` is a struct, recurse into members to check for the attribute.
/// Otherwise, check `attributes` for the attribute.
- bool ContainsBuiltin(ast::Builtin builtin,
+ bool ContainsBuiltin(ast::BuiltinValue builtin,
const sem::Type* type,
- const ast::AttributeList& attributes) const;
+ utils::VectorRef<const ast::Attribute*> attributes) const;
/// Gathers all the texture resource bindings of the given type for the given
/// entry point.
diff --git a/chromium/third_party/dawn/src/tint/inspector/inspector_test.cc b/chromium/third_party/dawn/src/tint/inspector/inspector_test.cc
index 986e1692aac..cb46833b946 100644
--- a/chromium/third_party/dawn/src/tint/inspector/inspector_test.cc
+++ b/chromium/third_party/dawn/src/tint/inspector/inspector_test.cc
@@ -60,7 +60,7 @@ struct InspectorGetEntryPointInterpolateTestParams {
class InspectorGetEntryPointInterpolateTest
: public InspectorBuilder,
public testing::TestWithParam<InspectorGetEntryPointInterpolateTestParams> {};
-class InspectorGetConstantIDsTest : public InspectorBuilder, public testing::Test {};
+class InspectorGetOverrideDefaultValuesTest : public InspectorBuilder, public testing::Test {};
class InspectorGetConstantNameToIdMapTest : public InspectorBuilder, public testing::Test {};
class InspectorGetStorageSizeTest : public InspectorBuilder, public testing::Test {};
class InspectorGetResourceBindingsTest : public InspectorBuilder, public testing::Test {};
@@ -154,7 +154,7 @@ TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
}
TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
- MakeEmptyBodyFunction("foo", ast::AttributeList{
+ MakeEmptyBodyFunction("foo", utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -168,16 +168,18 @@ TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
ASSERT_EQ(1u, result.size());
EXPECT_EQ("foo", result[0].name);
EXPECT_EQ("foo", result[0].remapped_name);
- EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
+ EXPECT_EQ(PipelineStage::kFragment, result[0].stage);
}
TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
- MakeEmptyBodyFunction("foo", ast::AttributeList{
+ MakeEmptyBodyFunction("foo", utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
- MakeEmptyBodyFunction(
- "bar", ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ MakeEmptyBodyFunction("bar", utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
// TODO(dsinclair): Update to run the namer transform when available.
@@ -189,21 +191,23 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
ASSERT_EQ(2u, result.size());
EXPECT_EQ("foo", result[0].name);
EXPECT_EQ("foo", result[0].remapped_name);
- EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
+ EXPECT_EQ(PipelineStage::kFragment, result[0].stage);
EXPECT_EQ("bar", result[1].name);
EXPECT_EQ("bar", result[1].remapped_name);
- EXPECT_EQ(ast::PipelineStage::kCompute, result[1].stage);
+ EXPECT_EQ(PipelineStage::kCompute, result[1].stage);
}
TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
- MakeEmptyBodyFunction("func", {});
+ MakeEmptyBodyFunction("func", utils::Empty);
- MakeCallerBodyFunction(
- "foo", {"func"},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ MakeCallerBodyFunction("foo", utils::Vector{std::string("func")},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
- MakeCallerBodyFunction("bar", {"func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("bar", utils::Vector{std::string("func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -217,15 +221,17 @@ TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
ASSERT_EQ(2u, result.size());
EXPECT_EQ("foo", result[0].name);
EXPECT_EQ("foo", result[0].remapped_name);
- EXPECT_EQ(ast::PipelineStage::kCompute, result[0].stage);
+ EXPECT_EQ(PipelineStage::kCompute, result[0].stage);
EXPECT_EQ("bar", result[1].name);
EXPECT_EQ("bar", result[1].remapped_name);
- EXPECT_EQ(ast::PipelineStage::kFragment, result[1].stage);
+ EXPECT_EQ(PipelineStage::kFragment, result[1].stage);
}
TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
- MakeEmptyBodyFunction("foo", ast::AttributeList{Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(8_i, 2_i, 1_i)});
+ MakeEmptyBodyFunction("foo", utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(8_i, 2_i, 1_i),
+ });
Inspector& inspector = Build();
@@ -233,16 +239,18 @@ TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
- uint32_t x, y, z;
- std::tie(x, y, z) = result[0].workgroup_size();
- EXPECT_EQ(8u, x);
- EXPECT_EQ(2u, y);
- EXPECT_EQ(1u, z);
+ auto workgroup_size = result[0].workgroup_size;
+ ASSERT_TRUE(workgroup_size.has_value());
+ EXPECT_EQ(8u, workgroup_size->x);
+ EXPECT_EQ(2u, workgroup_size->y);
+ EXPECT_EQ(1u, workgroup_size->z);
}
TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
- MakeEmptyBodyFunction("foo",
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8_i, 2_i, 1_i)});
+ MakeEmptyBodyFunction("foo", utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(8_i, 2_i, 1_i),
+ });
Inspector& inspector = Build();
@@ -250,18 +258,18 @@ TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
- uint32_t x, y, z;
- std::tie(x, y, z) = result[0].workgroup_size();
- EXPECT_EQ(8u, x);
- EXPECT_EQ(2u, y);
- EXPECT_EQ(1u, z);
+ auto workgroup_size = result[0].workgroup_size;
+ ASSERT_TRUE(workgroup_size.has_value());
+ EXPECT_EQ(8u, workgroup_size->x);
+ EXPECT_EQ(2u, workgroup_size->y);
+ EXPECT_EQ(1u, workgroup_size->z);
}
TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
- MakeEmptyBodyFunction("func", {});
+ MakeEmptyBodyFunction("func", utils::Empty);
- MakeCallerBodyFunction("foo", {"func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("foo", utils::Vector{std::string("func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -281,9 +289,21 @@ TEST_P(InspectorGetEntryPointComponentAndCompositionTest, Test) {
std::tie(component, composition) = GetParam();
std::function<const ast::Type*()> tint_type = GetTypeFunction(component, composition);
- auto* in_var = Param("in_var", tint_type(), {Location(0u), Flat()});
- Func("foo", {in_var}, tint_type(), {Return("in_var")}, {Stage(ast::PipelineStage::kFragment)},
- {Location(0u)});
+ auto* in_var = Param("in_var", tint_type(),
+ utils::Vector{
+ Location(0u),
+ Flat(),
+ });
+ Func("foo", utils::Vector{in_var}, tint_type(),
+ utils::Vector{
+ Return("in_var"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0u),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
@@ -314,11 +334,31 @@ INSTANTIATE_TEST_SUITE_P(InspectorGetEntryPointTest,
CompositionType::kVec4)));
TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) {
- auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u), Flat()});
- auto* in_var1 = Param("in_var1", ty.u32(), {Location(1u), Flat()});
- auto* in_var4 = Param("in_var4", ty.u32(), {Location(4u), Flat()});
- Func("foo", {in_var0, in_var1, in_var4}, ty.u32(), {Return("in_var0")},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
+ auto* in_var0 = Param("in_var0", ty.u32(),
+ utils::Vector{
+ Location(0u),
+ Flat(),
+ });
+ auto* in_var1 = Param("in_var1", ty.u32(),
+ utils::Vector{
+ Location(1u),
+ Flat(),
+ });
+ auto* in_var4 = Param("in_var4", ty.u32(),
+ utils::Vector{
+ Location(4u),
+ Flat(),
+ });
+ Func("foo", utils::Vector{in_var0, in_var1, in_var4}, ty.u32(),
+ utils::Vector{
+ Return("in_var0"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0u),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
@@ -351,13 +391,37 @@ TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) {
}
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
- auto* in_var_foo = Param("in_var_foo", ty.u32(), {Location(0u), Flat()});
- Func("foo", {in_var_foo}, ty.u32(), {Return("in_var_foo")},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
+ auto* in_var_foo = Param("in_var_foo", ty.u32(),
+ utils::Vector{
+ Location(0u),
+ Flat(),
+ });
+ Func("foo", utils::Vector{in_var_foo}, ty.u32(),
+ utils::Vector{
+ Return("in_var_foo"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0u),
+ });
- auto* in_var_bar = Param("in_var_bar", ty.u32(), {Location(0u), Flat()});
- Func("bar", {in_var_bar}, ty.u32(), {Return("in_var_bar")},
- {Stage(ast::PipelineStage::kFragment)}, {Location(1u)});
+ auto* in_var_bar = Param("in_var_bar", ty.u32(),
+ utils::Vector{
+ Location(0u),
+ Flat(),
+ });
+ Func("bar", utils::Vector{in_var_bar}, ty.u32(),
+ utils::Vector{
+ Return("in_var_bar"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(1u),
+ });
Inspector& inspector = Build();
@@ -394,10 +458,24 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
}
TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
- auto* in_var0 = Param("in_var0", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
- auto* in_var1 = Param("in_var1", ty.f32(), {Location(0u)});
- Func("foo", {in_var0, in_var1}, ty.f32(), {Return("in_var1")},
- {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
+ auto* in_var0 = Param("in_var0", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleIndex),
+ });
+ auto* in_var1 = Param("in_var1", ty.f32(),
+ utils::Vector{
+ Location(0u),
+ });
+ Func("foo", utils::Vector{in_var0, in_var1}, ty.f32(),
+ utils::Vector{
+ Return("in_var1"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFragDepth),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
@@ -415,9 +493,21 @@ TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
}
TEST_F(InspectorGetEntryPointTest, InOutStruct) {
- auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
- Func("foo", {Param("param", ty.Of(interface))}, ty.Of(interface), {Return("param")},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* interface = MakeInOutStruct("interface", utils::Vector{
+ InOutInfo{"a", 0u},
+ InOutInfo{"b", 1u},
+ });
+ Func("foo",
+ utils::Vector{
+ Param("param", ty.Of(interface)),
+ },
+ ty.Of(interface),
+ utils::Vector{
+ Return("param"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
@@ -447,11 +537,21 @@ TEST_F(InspectorGetEntryPointTest, InOutStruct) {
}
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutSharedStruct) {
- auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
- Func("foo", {}, ty.Of(interface), {Return(Construct(ty.Of(interface)))},
- {Stage(ast::PipelineStage::kFragment)});
- Func("bar", {Param("param", ty.Of(interface))}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* interface = MakeInOutStruct("interface", utils::Vector{
+ InOutInfo{"a", 0u},
+ InOutInfo{"b", 1u},
+ });
+ Func("foo", utils::Empty, ty.Of(interface),
+ utils::Vector{
+ Return(Construct(ty.Of(interface))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
+ Func("bar", utils::Vector{Param("param", ty.Of(interface))}, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
@@ -485,12 +585,27 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutSharedStruct) {
}
TEST_F(InspectorGetEntryPointTest, MixInOutVariablesAndStruct) {
- auto* struct_a = MakeInOutStruct("struct_a", {{"a", 0u}, {"b", 1u}});
- auto* struct_b = MakeInOutStruct("struct_b", {{"a", 2u}});
+ auto* struct_a = MakeInOutStruct("struct_a", utils::Vector{
+ InOutInfo{"a", 0u},
+ InOutInfo{"b", 1u},
+ });
+ auto* struct_b = MakeInOutStruct("struct_b", utils::Vector{
+ InOutInfo{"a", 2u},
+ });
Func("foo",
- {Param("param_a", ty.Of(struct_a)), Param("param_b", ty.Of(struct_b)),
- Param("param_c", ty.f32(), {Location(3u)}), Param("param_d", ty.f32(), {Location(4u)})},
- ty.Of(struct_a), {Return("param_a")}, {Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Param("param_a", ty.Of(struct_a)),
+ Param("param_b", ty.Of(struct_b)),
+ Param("param_c", ty.f32(), utils::Vector{Location(3u)}),
+ Param("param_d", ty.f32(), utils::Vector{Location(4u)}),
+ },
+ ty.Of(struct_a),
+ utils::Vector{
+ Return("param_a"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
@@ -531,168 +646,209 @@ TEST_F(InspectorGetEntryPointTest, MixInOutVariablesAndStruct) {
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
}
-TEST_F(InspectorGetEntryPointTest, OverridableConstantUnreferenced) {
- AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
- MakeEmptyBodyFunction("ep_func", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+TEST_F(InspectorGetEntryPointTest, OverrideUnreferenced) {
+ Override("foo", ty.f32(), nullptr);
+ MakeEmptyBodyFunction("ep_func", utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- EXPECT_EQ(0u, result[0].overridable_constants.size());
+ EXPECT_EQ(0u, result[0].overrides.size());
}
-TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByEntryPoint) {
- AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideReferencedByEntryPoint) {
+ Override("foo", ty.f32(), nullptr);
MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- ASSERT_EQ(1u, result[0].overridable_constants.size());
- EXPECT_EQ("foo", result[0].overridable_constants[0].name);
+ ASSERT_EQ(1u, result[0].overrides.size());
+ EXPECT_EQ("foo", result[0].overrides[0].name);
}
-TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByCallee) {
- AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
- MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
- MakeCallerBodyFunction("ep_func", {"callee_func"},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+TEST_F(InspectorGetEntryPointTest, OverrideReferencedByCallee) {
+ Override("foo", ty.f32(), nullptr);
+ MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), utils::Empty);
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("callee_func")},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- ASSERT_EQ(1u, result[0].overridable_constants.size());
- EXPECT_EQ("foo", result[0].overridable_constants[0].name);
+ ASSERT_EQ(1u, result[0].overrides.size());
+ EXPECT_EQ("foo", result[0].overrides[0].name);
}
-TEST_F(InspectorGetEntryPointTest, OverridableConstantSomeReferenced) {
- AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
- AddOverridableConstantWithID("bar", 2, ty.f32(), nullptr);
- MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
- MakeCallerBodyFunction("ep_func", {"callee_func"},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+TEST_F(InspectorGetEntryPointTest, OverrideSomeReferenced) {
+ Override("foo", ty.f32(), nullptr,
+ utils::Vector{
+ Id(1),
+ });
+ Override("bar", ty.f32(), nullptr,
+ utils::Vector{
+ Id(2),
+ });
+ MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), utils::Empty);
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("callee_func")},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- ASSERT_EQ(1u, result[0].overridable_constants.size());
- EXPECT_EQ("foo", result[0].overridable_constants[0].name);
- EXPECT_EQ(1, result[0].overridable_constants[0].numeric_id);
+ ASSERT_EQ(1u, result[0].overrides.size());
+ EXPECT_EQ("foo", result[0].overrides[0].name);
+ EXPECT_EQ(1, result[0].overrides[0].id.value);
}
-TEST_F(InspectorGetEntryPointTest, OverridableConstantTypes) {
- AddOverridableConstantWithoutID("bool_var", ty.bool_(), nullptr);
- AddOverridableConstantWithoutID("float_var", ty.f32(), nullptr);
- AddOverridableConstantWithoutID("u32_var", ty.u32(), nullptr);
- AddOverridableConstantWithoutID("i32_var", ty.i32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideTypes) {
+ Override("bool_var", ty.bool_(), nullptr);
+ Override("float_var", ty.f32(), nullptr);
+ Override("u32_var", ty.u32(), nullptr);
+ Override("i32_var", ty.i32(), nullptr);
- MakePlainGlobalReferenceBodyFunction("bool_func", "bool_var", ty.bool_(), {});
- MakePlainGlobalReferenceBodyFunction("float_func", "float_var", ty.f32(), {});
- MakePlainGlobalReferenceBodyFunction("u32_func", "u32_var", ty.u32(), {});
- MakePlainGlobalReferenceBodyFunction("i32_func", "i32_var", ty.i32(), {});
+ MakePlainGlobalReferenceBodyFunction("bool_func", "bool_var", ty.bool_(), utils::Empty);
+ MakePlainGlobalReferenceBodyFunction("float_func", "float_var", ty.f32(), utils::Empty);
+ MakePlainGlobalReferenceBodyFunction("u32_func", "u32_var", ty.u32(), utils::Empty);
+ MakePlainGlobalReferenceBodyFunction("i32_func", "i32_var", ty.i32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"bool_func", "float_func", "u32_func", "i32_func"},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ MakeCallerBodyFunction(
+ "ep_func", utils::Vector{std::string("bool_func"), "float_func", "u32_func", "i32_func"},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- ASSERT_EQ(4u, result[0].overridable_constants.size());
- EXPECT_EQ("bool_var", result[0].overridable_constants[0].name);
- EXPECT_EQ(inspector::OverridableConstant::Type::kBool, result[0].overridable_constants[0].type);
- EXPECT_EQ("float_var", result[0].overridable_constants[1].name);
- EXPECT_EQ(inspector::OverridableConstant::Type::kFloat32,
- result[0].overridable_constants[1].type);
- EXPECT_EQ("u32_var", result[0].overridable_constants[2].name);
- EXPECT_EQ(inspector::OverridableConstant::Type::kUint32,
- result[0].overridable_constants[2].type);
- EXPECT_EQ("i32_var", result[0].overridable_constants[3].name);
- EXPECT_EQ(inspector::OverridableConstant::Type::kInt32,
- result[0].overridable_constants[3].type);
-}
-
-TEST_F(InspectorGetEntryPointTest, OverridableConstantInitialized) {
- AddOverridableConstantWithoutID("foo", ty.f32(), Expr(0_f));
+ ASSERT_EQ(4u, result[0].overrides.size());
+ EXPECT_EQ("bool_var", result[0].overrides[0].name);
+ EXPECT_EQ(inspector::Override::Type::kBool, result[0].overrides[0].type);
+ EXPECT_EQ("float_var", result[0].overrides[1].name);
+ EXPECT_EQ(inspector::Override::Type::kFloat32, result[0].overrides[1].type);
+ EXPECT_EQ("u32_var", result[0].overrides[2].name);
+ EXPECT_EQ(inspector::Override::Type::kUint32, result[0].overrides[2].type);
+ EXPECT_EQ("i32_var", result[0].overrides[3].name);
+ EXPECT_EQ(inspector::Override::Type::kInt32, result[0].overrides[3].type);
+}
+
+TEST_F(InspectorGetEntryPointTest, OverrideInitialized) {
+ Override("foo", ty.f32(), Expr(0_f));
MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- ASSERT_EQ(1u, result[0].overridable_constants.size());
- EXPECT_EQ("foo", result[0].overridable_constants[0].name);
- EXPECT_TRUE(result[0].overridable_constants[0].is_initialized);
+ ASSERT_EQ(1u, result[0].overrides.size());
+ EXPECT_EQ("foo", result[0].overrides[0].name);
+ EXPECT_TRUE(result[0].overrides[0].is_initialized);
}
-TEST_F(InspectorGetEntryPointTest, OverridableConstantUninitialized) {
- AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideUninitialized) {
+ Override("foo", ty.f32(), nullptr);
MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- ASSERT_EQ(1u, result[0].overridable_constants.size());
- EXPECT_EQ("foo", result[0].overridable_constants[0].name);
+ ASSERT_EQ(1u, result[0].overrides.size());
+ EXPECT_EQ("foo", result[0].overrides[0].name);
- EXPECT_FALSE(result[0].overridable_constants[0].is_initialized);
+ EXPECT_FALSE(result[0].overrides[0].is_initialized);
}
-TEST_F(InspectorGetEntryPointTest, OverridableConstantNumericIDSpecified) {
- AddOverridableConstantWithoutID("foo_no_id", ty.f32(), nullptr);
- AddOverridableConstantWithID("foo_id", 1234, ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideNumericIDSpecified) {
+ Override("foo_no_id", ty.f32(), nullptr);
+ Override("foo_id", ty.f32(), nullptr,
+ utils::Vector{
+ Id(1234),
+ });
- MakePlainGlobalReferenceBodyFunction("no_id_func", "foo_no_id", ty.f32(), {});
- MakePlainGlobalReferenceBodyFunction("id_func", "foo_id", ty.f32(), {});
+ MakePlainGlobalReferenceBodyFunction("no_id_func", "foo_no_id", ty.f32(), utils::Empty);
+ MakePlainGlobalReferenceBodyFunction("id_func", "foo_id", ty.f32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"no_id_func", "id_func"},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("no_id_func"), "id_func"},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- ASSERT_EQ(2u, result[0].overridable_constants.size());
- EXPECT_EQ("foo_no_id", result[0].overridable_constants[0].name);
- EXPECT_EQ("foo_id", result[0].overridable_constants[1].name);
- EXPECT_EQ(1234, result[0].overridable_constants[1].numeric_id);
+ ASSERT_EQ(2u, result[0].overrides.size());
+ EXPECT_EQ("foo_no_id", result[0].overrides[0].name);
+ EXPECT_EQ("foo_id", result[0].overrides[1].name);
+ EXPECT_EQ(1234, result[0].overrides[1].id.value);
- EXPECT_FALSE(result[0].overridable_constants[0].is_numeric_id_specified);
- EXPECT_TRUE(result[0].overridable_constants[1].is_numeric_id_specified);
+ EXPECT_FALSE(result[0].overrides[0].is_id_specified);
+ EXPECT_TRUE(result[0].overrides[1].is_id_specified);
}
-TEST_F(InspectorGetEntryPointTest, NonOverridableConstantSkipped) {
- auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
+TEST_F(InspectorGetEntryPointTest, NonOverrideSkipped) {
+ auto* foo_struct_type = MakeUniformBufferType("foo_type", utils::Vector{
+ ty.i32(),
+ });
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
- MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
- MakeCallerBodyFunction("ep_func", {"ub_func"}, {Stage(ast::PipelineStage::kFragment)});
+ MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
- EXPECT_EQ(0u, result[0].overridable_constants.size());
+ EXPECT_EQ(0u, result[0].overrides.size());
}
TEST_F(InspectorGetEntryPointTest, BuiltinNotReferenced) {
- MakeEmptyBodyFunction("ep_func", {Stage(ast::PipelineStage::kFragment)});
+ MakeEmptyBodyFunction("ep_func", utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -708,8 +864,17 @@ TEST_F(InspectorGetEntryPointTest, BuiltinNotReferenced) {
}
TEST_F(InspectorGetEntryPointTest, InputSampleMaskSimpleReferenced) {
- auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ auto* in_var = Param("in_var", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleMask),
+ });
+ Func("ep_func", utils::Vector{in_var}, ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -720,12 +885,23 @@ TEST_F(InspectorGetEntryPointTest, InputSampleMaskSimpleReferenced) {
}
TEST_F(InspectorGetEntryPointTest, InputSampleMaskStructReferenced) {
- ast::StructMemberList members;
- members.push_back(Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}));
+ utils::Vector members{
+ Member("inner_position", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleMask)}),
+ };
+
Structure("in_struct", members);
- auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.type_name("in_struct"), utils::Empty),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -736,9 +912,20 @@ TEST_F(InspectorGetEntryPointTest, InputSampleMaskStructReferenced) {
}
TEST_F(InspectorGetEntryPointTest, OutputSampleMaskSimpleReferenced) {
- auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
- Func("ep_func", {in_var}, ty.u32(), {Return("in_var")}, {Stage(ast::PipelineStage::kFragment)},
- {Builtin(ast::Builtin::kSampleMask)});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleMask)}),
+ },
+ ty.u32(),
+ utils::Vector{
+ Return("in_var"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleMask),
+ });
Inspector& inspector = Build();
@@ -749,13 +936,19 @@ TEST_F(InspectorGetEntryPointTest, OutputSampleMaskSimpleReferenced) {
}
TEST_F(InspectorGetEntryPointTest, OutputSampleMaskStructReferenced) {
- ast::StructMemberList members;
- members.push_back(Member("inner_sample_mask", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}));
- Structure("out_struct", members);
-
- Func("ep_func", {}, ty.type_name("out_struct"),
- {Decl(Var("out_var", ty.type_name("out_struct"))), Return("out_var")},
- {Stage(ast::PipelineStage::kFragment)}, {});
+ Structure("out_struct", utils::Vector{
+ Member("inner_sample_mask", ty.u32(),
+ utils::Vector{Builtin(ast::BuiltinValue::kSampleMask)}),
+ });
+
+ Func("ep_func", utils::Empty, ty.type_name("out_struct"),
+ utils::Vector{
+ Decl(Var("out_var", ty.type_name("out_struct"))),
+ Return("out_var"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -766,8 +959,17 @@ TEST_F(InspectorGetEntryPointTest, OutputSampleMaskStructReferenced) {
}
TEST_F(InspectorGetEntryPointTest, InputPositionSimpleReferenced) {
- auto* in_var = Param("in_var", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -778,12 +980,22 @@ TEST_F(InspectorGetEntryPointTest, InputPositionSimpleReferenced) {
}
TEST_F(InspectorGetEntryPointTest, InputPositionStructReferenced) {
- ast::StructMemberList members;
- members.push_back(Member("inner_position", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}));
- Structure("in_struct", members);
- auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+ Structure("in_struct", utils::Vector{
+ Member("inner_position", ty.vec4<f32>(),
+ utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+ });
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.type_name("in_struct"), utils::Empty),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -794,8 +1006,17 @@ TEST_F(InspectorGetEntryPointTest, InputPositionStructReferenced) {
}
TEST_F(InspectorGetEntryPointTest, FrontFacingSimpleReferenced) {
- auto* in_var = Param("in_var", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)});
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.bool_(), utils::Vector{Builtin(ast::BuiltinValue::kFrontFacing)}),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -806,12 +1027,22 @@ TEST_F(InspectorGetEntryPointTest, FrontFacingSimpleReferenced) {
}
TEST_F(InspectorGetEntryPointTest, FrontFacingStructReferenced) {
- ast::StructMemberList members;
- members.push_back(Member("inner_position", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)}));
- Structure("in_struct", members);
- auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+ Structure("in_struct", utils::Vector{
+ Member("inner_position", ty.bool_(),
+ utils::Vector{Builtin(ast::BuiltinValue::kFrontFacing)}),
+ });
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.type_name("in_struct"), utils::Empty),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -822,8 +1053,17 @@ TEST_F(InspectorGetEntryPointTest, FrontFacingStructReferenced) {
}
TEST_F(InspectorGetEntryPointTest, SampleIndexSimpleReferenced) {
- auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -834,12 +1074,22 @@ TEST_F(InspectorGetEntryPointTest, SampleIndexSimpleReferenced) {
}
TEST_F(InspectorGetEntryPointTest, SampleIndexStructReferenced) {
- ast::StructMemberList members;
- members.push_back(Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)}));
- Structure("in_struct", members);
- auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+ Structure("in_struct", utils::Vector{
+ Member("inner_position", ty.u32(),
+ utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+ });
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.type_name("in_struct"), utils::Empty),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -850,9 +1100,16 @@ TEST_F(InspectorGetEntryPointTest, SampleIndexStructReferenced) {
}
TEST_F(InspectorGetEntryPointTest, NumWorkgroupsSimpleReferenced) {
- auto* in_var = Param("in_var", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)});
- Func("ep_func", {in_var}, ty.void_(), {Return()},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.vec3<u32>(),
+ utils::Vector{Builtin(ast::BuiltinValue::kNumWorkgroups)}),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, utils::Empty);
Inspector& inspector = Build();
@@ -863,14 +1120,20 @@ TEST_F(InspectorGetEntryPointTest, NumWorkgroupsSimpleReferenced) {
}
TEST_F(InspectorGetEntryPointTest, NumWorkgroupsStructReferenced) {
- ast::StructMemberList members;
- members.push_back(
- Member("inner_position", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)}));
- Structure("in_struct", members);
- auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+ Structure("in_struct", utils::Vector{
+ Member("inner_position", ty.vec3<u32>(),
+ utils::Vector{Builtin(ast::BuiltinValue::kNumWorkgroups)}),
+ });
- Func("ep_func", {in_var}, ty.void_(), {Return()},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.type_name("in_struct"), utils::Empty),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, utils::Empty);
Inspector& inspector = Build();
@@ -881,12 +1144,21 @@ TEST_F(InspectorGetEntryPointTest, NumWorkgroupsStructReferenced) {
}
TEST_F(InspectorGetEntryPointTest, ImplicitInterpolate) {
- ast::StructMemberList members;
- members.push_back(Member("struct_inner", ty.f32(), {Location(0)}));
- Structure("in_struct", members);
- auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+ Structure("in_struct", utils::Vector{
+ Member("struct_inner", ty.f32(), utils::Vector{Location(0)}),
+ });
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.type_name("in_struct"), utils::Empty),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -900,13 +1172,24 @@ TEST_F(InspectorGetEntryPointTest, ImplicitInterpolate) {
TEST_P(InspectorGetEntryPointInterpolateTest, Test) {
auto& params = GetParam();
- ast::StructMemberList members;
- members.push_back(Member("struct_inner", ty.f32(),
- {Interpolate(params.in_type, params.in_sampling), Location(0)}));
- Structure("in_struct", members);
- auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+ Structure(
+ "in_struct",
+ utils::Vector{
+ Member("struct_inner", ty.f32(),
+ utils::Vector{Interpolate(params.in_type, params.in_sampling), Location(0)}),
+ });
- Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("ep_func",
+ utils::Vector{
+ Param("in_var", ty.type_name("in_struct"), utils::Empty),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -950,132 +1233,179 @@ INSTANTIATE_TEST_SUITE_P(
ast::InterpolationType::kFlat, ast::InterpolationSampling::kNone,
InterpolationType::kFlat, InterpolationSampling::kNone}));
-TEST_F(InspectorGetConstantIDsTest, Bool) {
- AddOverridableConstantWithID("foo", 1, ty.bool_(), nullptr);
- AddOverridableConstantWithID("bar", 20, ty.bool_(), Expr(true));
- AddOverridableConstantWithID("baz", 300, ty.bool_(), Expr(false));
+TEST_F(InspectorGetOverrideDefaultValuesTest, Bool) {
+ Override("foo", ty.bool_(), nullptr,
+ utils::Vector{
+ Id(1),
+ });
+ Override("bar", ty.bool_(), Expr(true),
+ utils::Vector{
+ Id(20),
+ });
+ Override("baz", ty.bool_(), Expr(false),
+ utils::Vector{
+ Id(300),
+ });
Inspector& inspector = Build();
- auto result = inspector.GetConstantIDs();
+ auto result = inspector.GetOverrideDefaultValues();
ASSERT_EQ(3u, result.size());
- ASSERT_TRUE(result.find(1) != result.end());
- EXPECT_TRUE(result[1].IsNull());
+ ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+ EXPECT_TRUE(result[OverrideId{1}].IsNull());
- ASSERT_TRUE(result.find(20) != result.end());
- EXPECT_TRUE(result[20].IsBool());
- EXPECT_TRUE(result[20].AsBool());
+ ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+ EXPECT_TRUE(result[OverrideId{20}].IsBool());
+ EXPECT_TRUE(result[OverrideId{20}].AsBool());
- ASSERT_TRUE(result.find(300) != result.end());
- EXPECT_TRUE(result[300].IsBool());
- EXPECT_FALSE(result[300].AsBool());
+ ASSERT_TRUE(result.find(OverrideId{300}) != result.end());
+ EXPECT_TRUE(result[OverrideId{300}].IsBool());
+ EXPECT_FALSE(result[OverrideId{300}].AsBool());
}
-TEST_F(InspectorGetConstantIDsTest, U32) {
- AddOverridableConstantWithID("foo", 1, ty.u32(), nullptr);
- AddOverridableConstantWithID("bar", 20, ty.u32(), Expr(42_u));
+TEST_F(InspectorGetOverrideDefaultValuesTest, U32) {
+ Override("foo", ty.u32(), nullptr,
+ utils::Vector{
+ Id(1),
+ });
+ Override("bar", ty.u32(), Expr(42_u),
+ utils::Vector{
+ Id(20),
+ });
Inspector& inspector = Build();
- auto result = inspector.GetConstantIDs();
+ auto result = inspector.GetOverrideDefaultValues();
ASSERT_EQ(2u, result.size());
- ASSERT_TRUE(result.find(1) != result.end());
- EXPECT_TRUE(result[1].IsNull());
+ ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+ EXPECT_TRUE(result[OverrideId{1}].IsNull());
- ASSERT_TRUE(result.find(20) != result.end());
- EXPECT_TRUE(result[20].IsU32());
- EXPECT_EQ(42u, result[20].AsU32());
+ ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+ EXPECT_TRUE(result[OverrideId{20}].IsU32());
+ EXPECT_EQ(42u, result[OverrideId{20}].AsU32());
}
-TEST_F(InspectorGetConstantIDsTest, I32) {
- AddOverridableConstantWithID("foo", 1, ty.i32(), nullptr);
- AddOverridableConstantWithID("bar", 20, ty.i32(), Expr(-42_i));
- AddOverridableConstantWithID("baz", 300, ty.i32(), Expr(42_i));
+TEST_F(InspectorGetOverrideDefaultValuesTest, I32) {
+ Override("foo", ty.i32(), nullptr,
+ utils::Vector{
+ Id(1),
+ });
+ Override("bar", ty.i32(), Expr(-42_i),
+ utils::Vector{
+ Id(20),
+ });
+ Override("baz", ty.i32(), Expr(42_i),
+ utils::Vector{
+ Id(300),
+ });
Inspector& inspector = Build();
- auto result = inspector.GetConstantIDs();
+ auto result = inspector.GetOverrideDefaultValues();
ASSERT_EQ(3u, result.size());
- ASSERT_TRUE(result.find(1) != result.end());
- EXPECT_TRUE(result[1].IsNull());
+ ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+ EXPECT_TRUE(result[OverrideId{1}].IsNull());
- ASSERT_TRUE(result.find(20) != result.end());
- EXPECT_TRUE(result[20].IsI32());
- EXPECT_EQ(-42, result[20].AsI32());
+ ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+ EXPECT_TRUE(result[OverrideId{20}].IsI32());
+ EXPECT_EQ(-42, result[OverrideId{20}].AsI32());
- ASSERT_TRUE(result.find(300) != result.end());
- EXPECT_TRUE(result[300].IsI32());
- EXPECT_EQ(42, result[300].AsI32());
+ ASSERT_TRUE(result.find(OverrideId{300}) != result.end());
+ EXPECT_TRUE(result[OverrideId{300}].IsI32());
+ EXPECT_EQ(42, result[OverrideId{300}].AsI32());
}
-TEST_F(InspectorGetConstantIDsTest, Float) {
- AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
- AddOverridableConstantWithID("bar", 20, ty.f32(), Expr(0_f));
- AddOverridableConstantWithID("baz", 300, ty.f32(), Expr(-10_f));
- AddOverridableConstantWithID("x", 4000, ty.f32(), Expr(15_f));
+TEST_F(InspectorGetOverrideDefaultValuesTest, Float) {
+ Override("foo", ty.f32(), nullptr,
+ utils::Vector{
+ Id(1),
+ });
+ Override("bar", ty.f32(), Expr(0_f),
+ utils::Vector{
+ Id(20),
+ });
+ Override("baz", ty.f32(), Expr(-10_f),
+ utils::Vector{
+ Id(300),
+ });
+ Override("x", ty.f32(), Expr(15_f),
+ utils::Vector{
+ Id(4000),
+ });
Inspector& inspector = Build();
- auto result = inspector.GetConstantIDs();
+ auto result = inspector.GetOverrideDefaultValues();
ASSERT_EQ(4u, result.size());
- ASSERT_TRUE(result.find(1) != result.end());
- EXPECT_TRUE(result[1].IsNull());
+ ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+ EXPECT_TRUE(result[OverrideId{1}].IsNull());
- ASSERT_TRUE(result.find(20) != result.end());
- EXPECT_TRUE(result[20].IsFloat());
- EXPECT_FLOAT_EQ(0.0f, result[20].AsFloat());
+ ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+ EXPECT_TRUE(result[OverrideId{20}].IsFloat());
+ EXPECT_FLOAT_EQ(0.0f, result[OverrideId{20}].AsFloat());
- ASSERT_TRUE(result.find(300) != result.end());
- EXPECT_TRUE(result[300].IsFloat());
- EXPECT_FLOAT_EQ(-10.0f, result[300].AsFloat());
+ ASSERT_TRUE(result.find(OverrideId{300}) != result.end());
+ EXPECT_TRUE(result[OverrideId{300}].IsFloat());
+ EXPECT_FLOAT_EQ(-10.0f, result[OverrideId{300}].AsFloat());
- ASSERT_TRUE(result.find(4000) != result.end());
- EXPECT_TRUE(result[4000].IsFloat());
- EXPECT_FLOAT_EQ(15.0f, result[4000].AsFloat());
+ ASSERT_TRUE(result.find(OverrideId{4000}) != result.end());
+ EXPECT_TRUE(result[OverrideId{4000}].IsFloat());
+ EXPECT_FLOAT_EQ(15.0f, result[OverrideId{4000}].AsFloat());
}
TEST_F(InspectorGetConstantNameToIdMapTest, WithAndWithoutIds) {
- AddOverridableConstantWithID("v1", 1, ty.f32(), nullptr);
- AddOverridableConstantWithID("v20", 20, ty.f32(), nullptr);
- AddOverridableConstantWithID("v300", 300, ty.f32(), nullptr);
- auto* a = AddOverridableConstantWithoutID("a", ty.f32(), nullptr);
- auto* b = AddOverridableConstantWithoutID("b", ty.f32(), nullptr);
- auto* c = AddOverridableConstantWithoutID("c", ty.f32(), nullptr);
-
- Inspector& inspector = Build();
-
- auto result = inspector.GetConstantNameToIdMap();
+ Override("v1", ty.f32(), nullptr,
+ utils::Vector{
+ Id(1),
+ });
+ Override("v20", ty.f32(), nullptr,
+ utils::Vector{
+ Id(20),
+ });
+ Override("v300", ty.f32(), nullptr,
+ utils::Vector{
+ Id(300),
+ });
+ auto* a = Override("a", ty.f32(), nullptr);
+ auto* b = Override("b", ty.f32(), nullptr);
+ auto* c = Override("c", ty.f32(), nullptr);
+
+ Inspector& inspector = Build();
+
+ auto result = inspector.GetNamedOverrideIds();
ASSERT_EQ(6u, result.size());
ASSERT_TRUE(result.count("v1"));
- EXPECT_EQ(result["v1"], 1u);
+ EXPECT_EQ(result["v1"].value, 1u);
ASSERT_TRUE(result.count("v20"));
- EXPECT_EQ(result["v20"], 20u);
+ EXPECT_EQ(result["v20"].value, 20u);
ASSERT_TRUE(result.count("v300"));
- EXPECT_EQ(result["v300"], 300u);
+ EXPECT_EQ(result["v300"].value, 300u);
ASSERT_TRUE(result.count("a"));
ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(a));
- EXPECT_EQ(result["a"], program_->Sem().Get<sem::GlobalVariable>(a)->ConstantId());
+ EXPECT_EQ(result["a"], program_->Sem().Get<sem::GlobalVariable>(a)->OverrideId());
ASSERT_TRUE(result.count("b"));
ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(b));
- EXPECT_EQ(result["b"], program_->Sem().Get<sem::GlobalVariable>(b)->ConstantId());
+ EXPECT_EQ(result["b"], program_->Sem().Get<sem::GlobalVariable>(b)->OverrideId());
ASSERT_TRUE(result.count("c"));
ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(c));
- EXPECT_EQ(result["c"], program_->Sem().Get<sem::GlobalVariable>(c)->ConstantId());
+ EXPECT_EQ(result["c"], program_->Sem().Get<sem::GlobalVariable>(c)->OverrideId());
}
TEST_F(InspectorGetStorageSizeTest, Empty) {
- MakeEmptyBodyFunction(
- "ep_func", ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ MakeEmptyBodyFunction("ep_func", utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
EXPECT_EQ(0u, inspector.GetStorageSize("ep_func"));
}
@@ -1084,13 +1414,16 @@ TEST_F(InspectorGetStorageSizeTest, Simple_NonStruct) {
AddUniformBuffer("ub_var", ty.i32(), 0, 0);
AddStorageBuffer("sb_var", ty.i32(), ast::Access::kReadWrite, 1, 0);
AddStorageBuffer("rosb_var", ty.i32(), ast::Access::kRead, 1, 1);
- Func("ep_func", {}, ty.void_(),
- {
+ Func("ep_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("ub", nullptr, Expr("ub_var"))),
Decl(Let("sb", nullptr, Expr("sb_var"))),
Decl(Let("rosb", nullptr, Expr("rosb_var"))),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
@@ -1098,20 +1431,36 @@ TEST_F(InspectorGetStorageSizeTest, Simple_NonStruct) {
}
TEST_F(InspectorGetStorageSizeTest, Simple_Struct) {
- auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32(), ty.i32()});
+ auto* ub_struct_type = MakeUniformBufferType("ub_type", utils::Vector{
+ ty.i32(),
+ ty.i32(),
+ });
AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
- MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
-
- auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
+ MakeStructVariableReferenceBodyFunction("ub_func", "ub_var",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
+
+ auto sb = MakeStorageBufferTypes("sb_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
-
- auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
+ MakeStructVariableReferenceBodyFunction("sb_func", "sb_var",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
+
+ auto ro_sb = MakeStorageBufferTypes("rosb_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
- MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"ub_func", "sb_func", "rosb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func"), "sb_func", "rosb_func"},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -1123,11 +1472,14 @@ TEST_F(InspectorGetStorageSizeTest, Simple_Struct) {
TEST_F(InspectorGetStorageSizeTest, NonStructVec3) {
AddUniformBuffer("ub_var", ty.vec3<f32>(), 0, 0);
- Func("ep_func", {}, ty.void_(),
- {
+ Func("ep_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("ub", nullptr, Expr("ub_var"))),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
@@ -1135,13 +1487,18 @@ TEST_F(InspectorGetStorageSizeTest, NonStructVec3) {
}
TEST_F(InspectorGetStorageSizeTest, StructVec3) {
- auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.vec3<f32>()});
+ auto* ub_struct_type = MakeUniformBufferType("ub_type", utils::Vector{
+ ty.vec3<f32>(),
+ });
AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
- Func("ep_func", {}, ty.void_(),
- {
+ Func("ep_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("ub", nullptr, Expr("ub_var"))),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
@@ -1149,8 +1506,8 @@ TEST_F(InspectorGetStorageSizeTest, StructVec3) {
}
TEST_F(InspectorGetResourceBindingsTest, Empty) {
- MakeCallerBodyFunction("ep_func", {},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1162,23 +1519,39 @@ TEST_F(InspectorGetResourceBindingsTest, Empty) {
}
TEST_F(InspectorGetResourceBindingsTest, Simple) {
- auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32()});
+ auto* ub_struct_type = MakeUniformBufferType("ub_type", utils::Vector{
+ ty.i32(),
+ });
AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
- MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
-
- auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
+ MakeStructVariableReferenceBodyFunction("ub_func", "ub_var",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
+
+ auto sb = MakeStorageBufferTypes("sb_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
-
- auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
+ MakeStructVariableReferenceBodyFunction("sb_func", "sb_var",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
+
+ auto ro_sb = MakeStorageBufferTypes("rosb_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
- MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
auto* s_texture_type = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
AddResource("s_texture", s_texture_type, 2, 0);
AddSampler("s_var", 3, 0);
AddGlobalVariable("s_coords", ty.f32());
- MakeSamplerReferenceBodyFunction("s_func", "s_texture", "s_var", "s_coords", ty.f32(), {});
+ MakeSamplerReferenceBodyFunction("s_func", "s_texture", "s_var", "s_coords", ty.f32(),
+ utils::Empty);
auto* cs_depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
AddResource("cs_texture", cs_depth_texture_type, 3, 1);
@@ -1186,22 +1559,32 @@ TEST_F(InspectorGetResourceBindingsTest, Simple) {
AddGlobalVariable("cs_coords", ty.vec2<f32>());
AddGlobalVariable("cs_depth", ty.f32());
MakeComparisonSamplerReferenceBodyFunction("cs_func", "cs_texture", "cs_var", "cs_coords",
- "cs_depth", ty.f32(), {});
+ "cs_depth", ty.f32(), utils::Empty);
auto* depth_ms_texture_type = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
AddResource("depth_ms_texture", depth_ms_texture_type, 3, 3);
- Func("depth_ms_func", {}, ty.void_(), {Ignore("depth_ms_texture")});
+ Func("depth_ms_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Ignore("depth_ms_texture"),
+ });
auto* st_type = MakeStorageTextureTypes(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint);
AddStorageTexture("st_var", st_type, 4, 0);
- MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), {});
-
- MakeCallerBodyFunction(
- "ep_func",
- {"ub_func", "sb_func", "rosb_func", "s_func", "cs_func", "depth_ms_func", "st_func"},
- ast::AttributeList{
- Stage(ast::PipelineStage::kFragment),
- });
+ MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), utils::Empty);
+
+ MakeCallerBodyFunction("ep_func",
+ utils::Vector{
+ std::string("ub_func"),
+ std::string("sb_func"),
+ std::string("rosb_func"),
+ std::string("s_func"),
+ std::string("cs_func"),
+ std::string("depth_ms_func"),
+ std::string("st_func"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -1256,13 +1639,18 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingEntryPoint) {
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonEntryPointFunc) {
- auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
+ auto* foo_struct_type = MakeUniformBufferType("foo_type", utils::Vector{
+ ty.i32(),
+ });
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
- MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1275,10 +1663,10 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonEntryPointFunc) {
TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple_NonStruct) {
AddUniformBuffer("foo_ub", ty.i32(), 0, 0);
- MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.i32(), {});
+ MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.i32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1296,13 +1684,18 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple_NonStruct) {
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple_Struct) {
- auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
+ auto* foo_struct_type = MakeUniformBufferType("foo_type", utils::Vector{
+ ty.i32(),
+ });
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
- MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1320,14 +1713,22 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple_Struct) {
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleMembers) {
- auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32(), ty.u32(), ty.f32()});
+ auto* foo_struct_type = MakeUniformBufferType("foo_type", utils::Vector{
+ ty.i32(),
+ ty.u32(),
+ ty.f32(),
+ });
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
- {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
-
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ MemberInfo{1, ty.u32()},
+ MemberInfo{2, ty.f32()},
+ });
+
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1345,13 +1746,18 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleMembers) {
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingPadding) {
- auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.vec3<f32>()});
+ auto* foo_struct_type = MakeUniformBufferType("foo_type", utils::Vector{
+ ty.vec3<f32>(),
+ });
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
- MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.vec3<f32>()}});
+ MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
+ utils::Vector{
+ MemberInfo{0, ty.vec3<f32>()},
+ });
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1370,10 +1776,10 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingPadding) {
TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonStructVec3) {
AddUniformBuffer("foo_ub", ty.vec3<f32>(), 0, 0);
- MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), {});
+ MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1391,14 +1797,22 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonStructVec3) {
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleUniformBuffers) {
- auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32(), ty.u32(), ty.f32()});
+ auto* ub_struct_type = MakeUniformBufferType("ub_type", utils::Vector{
+ ty.i32(),
+ ty.u32(),
+ ty.f32(),
+ });
AddUniformBuffer("ub_foo", ty.Of(ub_struct_type), 0, 0);
AddUniformBuffer("ub_bar", ty.Of(ub_struct_type), 0, 1);
AddUniformBuffer("ub_baz", ty.Of(ub_struct_type), 2, 0);
auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
MakeStructVariableReferenceBodyFunction(func_name, var_name,
- {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ MemberInfo{1, ty.u32()},
+ MemberInfo{2, ty.f32()},
+ });
};
AddReferenceFunc("ub_foo_func", "ub_foo");
AddReferenceFunc("ub_bar_func", "ub_bar");
@@ -1408,10 +1822,14 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleUniformBuffers) {
return create<ast::CallStatement>(Call(callee));
};
- Func("ep_func", ast::VariableList(), ty.void_(),
- ast::StatementList{FuncCall("ub_foo_func"), FuncCall("ub_bar_func"),
- FuncCall("ub_baz_func"), Return()},
- ast::AttributeList{
+ Func("ep_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ FuncCall("ub_foo_func"),
+ FuncCall("ub_bar_func"),
+ FuncCall("ub_baz_func"),
+ Return(),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1444,15 +1862,21 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
// Manually create uniform buffer to make sure it had a valid layout (array
// with elem stride of 16, and that is 16-byte aligned within the struct)
auto* foo_struct_type = Structure(
- "foo_type", {Member("0i32", ty.i32()),
- Member("b", ty.array(ty.u32(), 4_u, /*stride*/ 16), {MemberAlign(16)})});
+ "foo_type",
+ utils::Vector{
+ Member("0i32", ty.i32()),
+ Member("b", ty.array(ty.u32(), 4_u, /*stride*/ 16), utils::Vector{MemberAlign(16)}),
+ });
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
- MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1471,10 +1895,10 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple_NonStruct) {
AddStorageBuffer("foo_sb", ty.i32(), ast::Access::kReadWrite, 0, 0);
- MakePlainGlobalReferenceBodyFunction("sb_func", "foo_sb", ty.i32(), {});
+ MakePlainGlobalReferenceBodyFunction("sb_func", "foo_sb", ty.i32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1492,13 +1916,18 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple_NonStruct) {
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple_Struct) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1516,7 +1945,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple_Struct) {
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
ty.i32(),
ty.u32(),
ty.f32(),
@@ -1524,10 +1953,14 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
- {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
-
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ MemberInfo{1, ty.u32()},
+ MemberInfo{2, ty.f32()},
+ });
+
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1545,7 +1978,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
- auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
+ auto sb_struct_type = MakeStorageBufferTypes("sb_type", utils::Vector{
ty.i32(),
ty.u32(),
ty.f32(),
@@ -1556,7 +1989,11 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
MakeStructVariableReferenceBodyFunction(func_name, var_name,
- {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ MemberInfo{1, ty.u32()},
+ MemberInfo{2, ty.f32()},
+ });
};
AddReferenceFunc("sb_foo_func", "sb_foo");
AddReferenceFunc("sb_bar_func", "sb_bar");
@@ -1566,14 +2003,14 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
return create<ast::CallStatement>(Call(callee));
};
- Func("ep_func", ast::VariableList(), ty.void_(),
- ast::StatementList{
+ Func("ep_func", utils::Empty, ty.void_(),
+ utils::Vector{
FuncCall("sb_foo_func"),
FuncCall("sb_bar_func"),
FuncCall("sb_baz_func"),
Return(),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1603,13 +2040,19 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
+ ty.i32(),
+ ty.array<u32, 4>(),
+ });
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1627,16 +2070,19 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
ty.i32(),
ty.array<u32>(),
});
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1654,13 +2100,18 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
+ ty.vec3<f32>(),
+ });
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.vec3<f32>()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.vec3<f32>()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1679,10 +2130,10 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
TEST_F(InspectorGetStorageBufferResourceBindingsTest, NonStructVec3) {
AddStorageBuffer("foo_ub", ty.vec3<f32>(), ast::Access::kReadWrite, 0, 0);
- MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), {});
+ MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"ub_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1700,13 +2151,18 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, NonStructVec3) {
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1718,13 +2174,18 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1742,7 +2203,7 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
- auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
+ auto sb_struct_type = MakeStorageBufferTypes("sb_type", utils::Vector{
ty.i32(),
ty.u32(),
ty.f32(),
@@ -1753,7 +2214,11 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, MultipleStorageBuf
auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
MakeStructVariableReferenceBodyFunction(func_name, var_name,
- {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ MemberInfo{1, ty.u32()},
+ MemberInfo{2, ty.f32()},
+ });
};
AddReferenceFunc("sb_foo_func", "sb_foo");
AddReferenceFunc("sb_bar_func", "sb_bar");
@@ -1763,14 +2228,14 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, MultipleStorageBuf
return create<ast::CallStatement>(Call(callee));
};
- Func("ep_func", ast::VariableList(), ty.void_(),
- ast::StatementList{
+ Func("ep_func", utils::Empty, ty.void_(),
+ utils::Vector{
FuncCall("sb_foo_func"),
FuncCall("sb_bar_func"),
FuncCall("sb_baz_func"),
Return(),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1800,16 +2265,19 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, MultipleStorageBuf
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
ty.i32(),
ty.array<u32, 4>(),
});
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1827,16 +2295,19 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
ty.i32(),
ty.array<u32>(),
});
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1854,13 +2325,18 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingRuntimeA
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
- auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+ auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
+ ty.i32(),
+ });
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
- MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
- MakeCallerBodyFunction("ep_func", {"sb_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1878,7 +2354,7 @@ TEST_F(InspectorGetSamplerResourceBindingsTest, Simple) {
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1894,7 +2370,7 @@ TEST_F(InspectorGetSamplerResourceBindingsTest, Simple) {
}
TEST_F(InspectorGetSamplerResourceBindingsTest, NoSampler) {
- MakeEmptyBodyFunction("ep_func", ast::AttributeList{
+ MakeEmptyBodyFunction("ep_func", utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1913,10 +2389,10 @@ TEST_F(InspectorGetSamplerResourceBindingsTest, InFunction) {
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler", "foo_coords",
- ty.f32(), {});
+ ty.f32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"foo_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("foo_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1938,7 +2414,7 @@ TEST_F(InspectorGetSamplerResourceBindingsTest, UnknownEntryPoint) {
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1957,7 +2433,7 @@ TEST_F(InspectorGetSamplerResourceBindingsTest, SkipsComparisonSamplers) {
MakeComparisonSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
"foo_depth", ty.f32(),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1978,7 +2454,7 @@ TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, Simple) {
MakeComparisonSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
"foo_depth", ty.f32(),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -1994,7 +2470,7 @@ TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, Simple) {
}
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, NoSampler) {
- MakeEmptyBodyFunction("ep_func", ast::AttributeList{
+ MakeEmptyBodyFunction("ep_func", utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2014,10 +2490,10 @@ TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, InFunction) {
AddGlobalVariable("foo_depth", ty.f32());
MakeComparisonSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler",
- "foo_coords", "foo_depth", ty.f32(), {});
+ "foo_coords", "foo_depth", ty.f32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"foo_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("foo_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2041,7 +2517,7 @@ TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, UnknownEntryPoint) {
MakeComparisonSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
"foo_depth", ty.f32(),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2058,7 +2534,7 @@ TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, SkipsSamplers) {
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2071,7 +2547,7 @@ TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, SkipsSamplers) {
}
TEST_F(InspectorGetSampledTextureResourceBindingsTest, Empty) {
- MakeEmptyBodyFunction("foo", ast::AttributeList{
+ MakeEmptyBodyFunction("foo", utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2093,7 +2569,7 @@ TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam, textureSample) {
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
GetBaseType(GetParam().sampled_kind),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2143,7 +2619,7 @@ TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam, textureSamp
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
"foo_array_index", GetBaseType(GetParam().sampled_kind),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2179,11 +2655,11 @@ TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam, textureLoad
AddGlobalVariable("foo_coords", coord_type);
AddGlobalVariable("foo_sample_index", ty.i32());
- Func("ep", ast::VariableList(), ty.void_(),
- ast::StatementList{
+ Func("ep", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call("textureLoad", "foo_texture", "foo_coords", "foo_sample_index")),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2221,7 +2697,7 @@ INSTANTIATE_TEST_SUITE_P(
inspector::ResourceBinding::SampledKind::kUInt}));
TEST_F(InspectorGetMultisampledArrayTextureResourceBindingsTest, Empty) {
- MakeEmptyBodyFunction("foo", ast::AttributeList{
+ MakeEmptyBodyFunction("foo", utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2244,7 +2720,7 @@ TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam, DISABL
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
"foo_array_index", GetBaseType(GetParam().sampled_kind),
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2276,7 +2752,7 @@ INSTANTIATE_TEST_SUITE_P(
inspector::ResourceBinding::SampledKind::kUInt}));
TEST_F(InspectorGetStorageTextureResourceBindingsTest, Empty) {
- MakeEmptyBodyFunction("ep", ast::AttributeList{
+ MakeEmptyBodyFunction("ep", utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2323,7 +2799,9 @@ TEST_P(InspectorGetStorageTextureResourceBindingsTestWithParam, Simple) {
ASSERT_FALSE(dim_type == nullptr);
MakeStorageTextureBodyFunction("ep", "st_var", dim_type,
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
Inspector& inspector = Build();
@@ -2403,11 +2881,11 @@ TEST_P(InspectorGetDepthTextureResourceBindingsTestWithParam, textureDimensions)
auto* depth_texture_type = ty.depth_texture(GetParam().type_dim);
AddResource("dt", depth_texture_type, 0, 0);
- Func("ep", ast::VariableList(), ty.void_(),
- ast::StatementList{
+ Func("ep", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call("textureDimensions", "dt")),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2440,11 +2918,11 @@ TEST_F(InspectorGetDepthMultisampledTextureResourceBindingsTest, textureDimensio
auto* depth_ms_texture_type = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
AddResource("tex", depth_ms_texture_type, 0, 0);
- Func("ep", ast::VariableList(), ty.void_(),
- ast::StatementList{
+ Func("ep", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call("textureDimensions", "tex")),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2464,11 +2942,11 @@ TEST_F(InspectorGetExternalTextureResourceBindingsTest, Simple) {
auto* external_texture_type = ty.external_texture();
AddResource("et", external_texture_type, 0, 0);
- Func("ep", ast::VariableList(), ty.void_(),
- ast::StatementList{
+ Func("ep", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call("textureDimensions", "et")),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -2493,7 +2971,7 @@ fn main() {
auto result = inspector.GetSamplerTextureUses("main");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(0u, result.size());
+ ASSERT_EQ(0u, result.Length());
}
TEST_F(InspectorGetSamplerTextureUsesTest, Simple) {
@@ -2511,7 +2989,7 @@ fn main(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("main");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2575,7 +3053,7 @@ fn main(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("main");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2602,7 +3080,7 @@ fn main(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("main");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2629,7 +3107,7 @@ fn main(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("main");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2656,7 +3134,7 @@ fn main(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("main");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2710,7 +3188,7 @@ fn direct(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("via_call");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2722,7 +3200,7 @@ fn direct(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("via_ptr");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2734,7 +3212,7 @@ fn direct(@location(0) fragUV: vec2<f32>,
auto result = inspector.GetSamplerTextureUses("direct");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
- ASSERT_EQ(1u, result.size());
+ ASSERT_EQ(1u, result.Length());
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
@@ -2744,18 +3222,20 @@ fn direct(@location(0) fragUV: vec2<f32>,
}
TEST_F(InspectorGetWorkgroupStorageSizeTest, Empty) {
- MakeEmptyBodyFunction(
- "ep_func", ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ MakeEmptyBodyFunction("ep_func", utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
Inspector& inspector = Build();
EXPECT_EQ(0u, inspector.GetWorkgroupStorageSize("ep_func"));
}
TEST_F(InspectorGetWorkgroupStorageSizeTest, Simple) {
AddWorkgroupStorage("wg_f32", ty.f32());
- MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
+ MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"f32_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("f32_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -2767,17 +3247,22 @@ TEST_F(InspectorGetWorkgroupStorageSizeTest, Simple) {
TEST_F(InspectorGetWorkgroupStorageSizeTest, CompoundTypes) {
// This struct should occupy 68 bytes. 4 from the i32 field, and another 64
// from the 4-element array with 16-byte stride.
- auto* wg_struct_type =
- MakeStructType("WgStruct", {ty.i32(), ty.array(ty.i32(), 4_u, /*stride=*/16)});
+ auto* wg_struct_type = MakeStructType("WgStruct", utils::Vector{
+ ty.i32(),
+ ty.array(ty.i32(), 4_u, /*stride=*/16),
+ });
AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
- MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var", {{0, ty.i32()}});
+ MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
+ utils::Vector{
+ MemberInfo{0, ty.i32()},
+ });
// Plus another 4 bytes from this other workgroup-class f32.
AddWorkgroupStorage("wg_f32", ty.f32());
- MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
+ MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"wg_struct_func", "f32_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("wg_struct_func"), "f32_func"},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -2790,10 +3275,10 @@ TEST_F(InspectorGetWorkgroupStorageSizeTest, AlignmentPadding) {
// vec3<f32> has an alignment of 16 but a size of 12. We leverage this to test
// that our padded size calculation for workgroup storage is accurate.
AddWorkgroupStorage("wg_vec3", ty.vec3<f32>());
- MakePlainGlobalReferenceBodyFunction("wg_func", "wg_vec3", ty.vec3<f32>(), {});
+ MakePlainGlobalReferenceBodyFunction("wg_func", "wg_vec3", ty.vec3<f32>(), utils::Empty);
- MakeCallerBodyFunction("ep_func", {"wg_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("wg_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -2808,13 +3293,19 @@ TEST_F(InspectorGetWorkgroupStorageSizeTest, StructAlignment) {
// here the struct is expected to occupy 1024 bytes of workgroup storage.
const auto* wg_struct_type = MakeStructTypeFromMembers(
"WgStruct",
- {MakeStructMember(0, ty.f32(), {create<ast::StructMemberAlignAttribute>(1024)})});
+ utils::Vector{
+ MakeStructMember(0, ty.f32(),
+ utils::Vector{create<ast::StructMemberAlignAttribute>(1024u)}),
+ });
AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
- MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var", {{0, ty.f32()}});
+ MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
+ utils::Vector{
+ MemberInfo{0, ty.f32()},
+ });
- MakeCallerBodyFunction("ep_func", {"wg_struct_func"},
- ast::AttributeList{
+ MakeCallerBodyFunction("ep_func", utils::Vector{std::string("wg_struct_func")},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/inspector/resource_binding.cc b/chromium/third_party/dawn/src/tint/inspector/resource_binding.cc
index 3efb59e57b1..6434ac2601a 100644
--- a/chromium/third_party/dawn/src/tint/inspector/resource_binding.cc
+++ b/chromium/third_party/dawn/src/tint/inspector/resource_binding.cc
@@ -104,7 +104,7 @@ ResourceBinding::TexelFormat TypeTexelFormatToResourceBindingTexelFormat(
return ResourceBinding::TexelFormat::kRgba32Sint;
case ast::TexelFormat::kRgba32Float:
return ResourceBinding::TexelFormat::kRgba32Float;
- case ast::TexelFormat::kNone:
+ case ast::TexelFormat::kInvalid:
return ResourceBinding::TexelFormat::kNone;
}
return ResourceBinding::TexelFormat::kNone;
diff --git a/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.cc b/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.cc
index 074f29c8581..5b89d7cbd74 100644
--- a/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.cc
+++ b/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.cc
@@ -27,32 +27,36 @@ namespace tint::inspector {
InspectorBuilder::InspectorBuilder() = default;
InspectorBuilder::~InspectorBuilder() = default;
-void InspectorBuilder::MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes) {
- Func(name, ast::VariableList(), ty.void_(), ast::StatementList{Return()}, attributes);
+void InspectorBuilder::MakeEmptyBodyFunction(std::string name,
+ utils::VectorRef<const ast::Attribute*> attributes) {
+ Func(name, utils::Empty, ty.void_(), utils::Vector{Return()}, attributes);
}
void InspectorBuilder::MakeCallerBodyFunction(std::string caller,
- std::vector<std::string> callees,
- ast::AttributeList attributes) {
- ast::StatementList body;
- body.reserve(callees.size() + 1);
+ utils::VectorRef<std::string> callees,
+ utils::VectorRef<const ast::Attribute*> attributes) {
+ utils::Vector<const ast::Statement*, 8> body;
+ body.Reserve(callees.Length() + 1);
for (auto callee : callees) {
- body.push_back(CallStmt(Call(callee)));
+ body.Push(CallStmt(Call(callee)));
}
- body.push_back(Return());
+ body.Push(Return());
- Func(caller, ast::VariableList(), ty.void_(), body, attributes);
+ Func(caller, utils::Empty, ty.void_(), body, attributes);
}
-const ast::Struct* InspectorBuilder::MakeInOutStruct(
- std::string name,
- std::vector<std::tuple<std::string, uint32_t>> inout_vars) {
- ast::StructMemberList members;
+const ast::Struct* InspectorBuilder::MakeInOutStruct(std::string name,
+ utils::VectorRef<InOutInfo> inout_vars) {
+ utils::Vector<const ast::StructMember*, 8> members;
for (auto var : inout_vars) {
std::string member_name;
uint32_t location;
std::tie(member_name, location) = var;
- members.push_back(Member(member_name, ty.u32(), {Location(location), Flat()}));
+ members.Push(Member(member_name, ty.u32(),
+ utils::Vector{
+ Location(location),
+ Flat(),
+ }));
}
return Structure(name, members);
}
@@ -61,17 +65,15 @@ const ast::Function* InspectorBuilder::MakePlainGlobalReferenceBodyFunction(
std::string func,
std::string var,
const ast::Type* type,
- ast::AttributeList attributes) {
- ast::StatementList stmts;
- stmts.emplace_back(Decl(Var("local_" + var, type)));
- stmts.emplace_back(Assign("local_" + var, var));
- stmts.emplace_back(Return());
-
- return Func(func, ast::VariableList(), ty.void_(), stmts, attributes);
+ utils::VectorRef<const ast::Attribute*> attributes) {
+ utils::Vector<const ast::Statement*, 3> stmts;
+ stmts.Push(Decl(Var("local_" + var, type)));
+ stmts.Push(Assign("local_" + var, var));
+ stmts.Push(Return());
+ return Func(func, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
}
-bool InspectorBuilder::ContainsName(const std::vector<StageVariable>& vec,
- const std::string& name) {
+bool InspectorBuilder::ContainsName(utils::VectorRef<StageVariable> vec, const std::string& name) {
for (auto& s : vec) {
if (s.name == name) {
return true;
@@ -84,35 +86,38 @@ std::string InspectorBuilder::StructMemberName(size_t idx, const ast::Type* type
return std::to_string(idx) + type->FriendlyName(Symbols());
}
-const ast::Struct* InspectorBuilder::MakeStructType(const std::string& name,
- std::vector<const ast::Type*> member_types) {
- ast::StructMemberList members;
+const ast::Struct* InspectorBuilder::MakeStructType(
+ const std::string& name,
+ utils::VectorRef<const ast::Type*> member_types) {
+ utils::Vector<const ast::StructMember*, 8> members;
for (auto* type : member_types) {
- members.push_back(MakeStructMember(members.size(), type, {}));
+ members.Push(MakeStructMember(members.Length(), type, {}));
}
return MakeStructTypeFromMembers(name, std::move(members));
}
-const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(const std::string& name,
- ast::StructMemberList members) {
+const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(
+ const std::string& name,
+ utils::VectorRef<const ast::StructMember*> members) {
return Structure(name, std::move(members));
}
-const ast::StructMember* InspectorBuilder::MakeStructMember(size_t index,
- const ast::Type* type,
- ast::AttributeList attributes) {
+const ast::StructMember* InspectorBuilder::MakeStructMember(
+ size_t index,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Attribute*> attributes) {
return Member(StructMemberName(index, type), type, std::move(attributes));
}
const ast::Struct* InspectorBuilder::MakeUniformBufferType(
const std::string& name,
- std::vector<const ast::Type*> member_types) {
+ utils::VectorRef<const ast::Type*> member_types) {
return MakeStructType(name, member_types);
}
std::function<const ast::TypeName*()> InspectorBuilder::MakeStorageBufferTypes(
const std::string& name,
- std::vector<const ast::Type*> member_types) {
+ utils::VectorRef<const ast::Type*> member_types) {
MakeStructType(name, member_types);
return [this, name] { return ty.type_name(name); };
}
@@ -121,15 +126,15 @@ void InspectorBuilder::AddUniformBuffer(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding) {
- Global(name, type, ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(binding),
- create<ast::GroupAttribute>(group),
- });
+ GlobalVar(name, type, ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(binding),
+ create<ast::GroupAttribute>(group),
+ });
}
void InspectorBuilder::AddWorkgroupStorage(const std::string& name, const ast::Type* type) {
- Global(name, type, ast::StorageClass::kWorkgroup);
+ GlobalVar(name, type, ast::StorageClass::kWorkgroup);
}
void InspectorBuilder::AddStorageBuffer(const std::string& name,
@@ -137,25 +142,25 @@ void InspectorBuilder::AddStorageBuffer(const std::string& name,
ast::Access access,
uint32_t group,
uint32_t binding) {
- Global(name, type, ast::StorageClass::kStorage, access,
- ast::AttributeList{
- create<ast::BindingAttribute>(binding),
- create<ast::GroupAttribute>(group),
- });
+ GlobalVar(name, type, ast::StorageClass::kStorage, access,
+ utils::Vector{
+ create<ast::BindingAttribute>(binding),
+ create<ast::GroupAttribute>(group),
+ });
}
void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
std::string func_name,
std::string struct_name,
- std::vector<std::tuple<size_t, const ast::Type*>> members) {
- ast::StatementList stmts;
+ utils::VectorRef<std::tuple<size_t, const ast::Type*>> members) {
+ utils::Vector<const ast::Statement*, 8> stmts;
for (auto member : members) {
size_t member_idx;
const ast::Type* member_type;
std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type);
- stmts.emplace_back(Decl(Var("local" + member_name, member_type)));
+ stmts.Push(Decl(Var("local" + member_name, member_type)));
}
for (auto member : members) {
@@ -164,45 +169,45 @@ void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type);
- stmts.emplace_back(Assign("local" + member_name, MemberAccessor(struct_name, member_name)));
+ stmts.Push(Assign("local" + member_name, MemberAccessor(struct_name, member_name)));
}
- stmts.emplace_back(Return());
+ stmts.Push(Return());
- Func(func_name, ast::VariableList(), ty.void_(), stmts, ast::AttributeList{});
+ Func(func_name, utils::Empty, ty.void_(), stmts);
}
void InspectorBuilder::AddSampler(const std::string& name, uint32_t group, uint32_t binding) {
- Global(name, sampler_type(),
- ast::AttributeList{
- create<ast::BindingAttribute>(binding),
- create<ast::GroupAttribute>(group),
- });
+ GlobalVar(name, sampler_type(),
+ utils::Vector{
+ create<ast::BindingAttribute>(binding),
+ create<ast::GroupAttribute>(group),
+ });
}
void InspectorBuilder::AddComparisonSampler(const std::string& name,
uint32_t group,
uint32_t binding) {
- Global(name, comparison_sampler_type(),
- ast::AttributeList{
- create<ast::BindingAttribute>(binding),
- create<ast::GroupAttribute>(group),
- });
+ GlobalVar(name, comparison_sampler_type(),
+ utils::Vector{
+ create<ast::BindingAttribute>(binding),
+ create<ast::GroupAttribute>(group),
+ });
}
void InspectorBuilder::AddResource(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding) {
- Global(name, type,
- ast::AttributeList{
- create<ast::BindingAttribute>(binding),
- create<ast::GroupAttribute>(group),
- });
+ GlobalVar(name, type,
+ utils::Vector{
+ create<ast::BindingAttribute>(binding),
+ create<ast::GroupAttribute>(group),
+ });
}
void InspectorBuilder::AddGlobalVariable(const std::string& name, const ast::Type* type) {
- Global(name, type, ast::StorageClass::kPrivate);
+ GlobalVar(name, type, ast::StorageClass::kPrivate);
}
const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
@@ -211,17 +216,15 @@ const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
const std::string& sampler_name,
const std::string& coords_name,
const ast::Type* base_type,
- ast::AttributeList attributes) {
+ utils::VectorRef<const ast::Attribute*> attributes) {
std::string result_name = "sampler_result";
- ast::StatementList stmts;
- stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4))));
-
- stmts.emplace_back(
- Assign(result_name, Call("textureSample", texture_name, sampler_name, coords_name)));
- stmts.emplace_back(Return());
-
- return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+ utils::Vector stmts{
+ Decl(Var(result_name, ty.vec(base_type, 4))),
+ Assign(result_name, Call("textureSample", texture_name, sampler_name, coords_name)),
+ Return(),
+ };
+ return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
}
const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
@@ -231,18 +234,16 @@ const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
const std::string& coords_name,
const std::string& array_index,
const ast::Type* base_type,
- ast::AttributeList attributes) {
+ utils::VectorRef<const ast::Attribute*> attributes) {
std::string result_name = "sampler_result";
- ast::StatementList stmts;
-
- stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4))));
-
- stmts.emplace_back(Assign("sampler_result", Call("textureSample", texture_name, sampler_name,
- coords_name, array_index)));
- stmts.emplace_back(Return());
-
- return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+ utils::Vector stmts{
+ Decl(Var("sampler_result", ty.vec(base_type, 4))),
+ Assign("sampler_result",
+ Call("textureSample", texture_name, sampler_name, coords_name, array_index)),
+ Return(),
+ };
+ return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
}
const ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction(
@@ -252,17 +253,16 @@ const ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunctio
const std::string& coords_name,
const std::string& depth_name,
const ast::Type* base_type,
- ast::AttributeList attributes) {
+ utils::VectorRef<const ast::Attribute*> attributes) {
std::string result_name = "sampler_result";
- ast::StatementList stmts;
-
- stmts.emplace_back(Decl(Var("sampler_result", base_type)));
- stmts.emplace_back(Assign("sampler_result", Call("textureSampleCompare", texture_name,
- sampler_name, coords_name, depth_name)));
- stmts.emplace_back(Return());
-
- return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+ utils::Vector stmts{
+ Decl(Var("sampler_result", base_type)),
+ Assign("sampler_result",
+ Call("textureSampleCompare", texture_name, sampler_name, coords_name, depth_name)),
+ Return(),
+ };
+ return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
}
const ast::Type* InspectorBuilder::GetBaseType(ResourceBinding::SampledKind sampled_kind) {
@@ -285,11 +285,11 @@ const ast::Type* InspectorBuilder::GetCoordsType(ast::TextureDimension dim,
return scalar;
case ast::TextureDimension::k2d:
case ast::TextureDimension::k2dArray:
- return create<ast::Vector>(scalar, 2);
+ return create<ast::Vector>(scalar, 2u);
case ast::TextureDimension::k3d:
case ast::TextureDimension::kCube:
case ast::TextureDimension::kCubeArray:
- return create<ast::Vector>(scalar, 3);
+ return create<ast::Vector>(scalar, 3u);
default:
[=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
}
@@ -305,25 +305,25 @@ void InspectorBuilder::AddStorageTexture(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding) {
- Global(name, type,
- ast::AttributeList{
- create<ast::BindingAttribute>(binding),
- create<ast::GroupAttribute>(group),
- });
+ GlobalVar(name, type,
+ utils::Vector{
+ create<ast::BindingAttribute>(binding),
+ create<ast::GroupAttribute>(group),
+ });
}
const ast::Function* InspectorBuilder::MakeStorageTextureBodyFunction(
const std::string& func_name,
const std::string& st_name,
const ast::Type* dim_type,
- ast::AttributeList attributes) {
- ast::StatementList stmts;
-
- stmts.emplace_back(Decl(Var("dim", dim_type)));
- stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name)));
- stmts.emplace_back(Return());
-
- return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+ utils::VectorRef<const ast::Attribute*> attributes) {
+ utils::Vector stmts{
+ Decl(Var("dim", dim_type)),
+ Assign("dim", Call("textureDimensions", st_name)),
+ Return(),
+ };
+
+ return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
}
std::function<const ast::Type*()> InspectorBuilder::GetTypeFunction(ComponentType component,
diff --git a/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.h b/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.h
index 391e1a1479c..fe43c69ea4e 100644
--- a/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.h
+++ b/chromium/third_party/dawn/src/tint/inspector/test_inspector_builder.h
@@ -44,28 +44,31 @@ class InspectorBuilder : public ProgramBuilder {
/// Generates an empty function
/// @param name name of the function created
/// @param attributes the function attributes
- void MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes);
+ void MakeEmptyBodyFunction(std::string name,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that calls other functions
/// @param caller name of the function created
/// @param callees names of the functions to be called
/// @param attributes the function attributes
void MakeCallerBodyFunction(std::string caller,
- std::vector<std::string> callees,
- ast::AttributeList attributes);
+ utils::VectorRef<std::string> callees,
+ utils::VectorRef<const ast::Attribute*> attributes);
+
+ /// InOutInfo is a tuple of name and location for a structure member
+ using InOutInfo = std::tuple<std::string, uint32_t>;
/// Generates a struct that contains user-defined IO members
/// @param name the name of the generated struct
/// @param inout_vars tuples of {name, loc} that will be the struct members
/// @returns a structure object
- const ast::Struct* MakeInOutStruct(std::string name,
- std::vector<std::tuple<std::string, uint32_t>> inout_vars);
+ const ast::Struct* MakeInOutStruct(std::string name, utils::VectorRef<InOutInfo> inout_vars);
// TODO(crbug.com/tint/697): Remove this.
/// Add In/Out variables to the global variables
/// @param inout_vars tuples of {in, out} that will be added as entries to the
/// global variables
- void AddInOutVariables(std::vector<std::tuple<std::string, std::string>> inout_vars);
+ void AddInOutVariables(utils::VectorRef<std::tuple<std::string, std::string>> inout_vars);
// TODO(crbug.com/tint/697): Remove this.
/// Generates a function that references in/out variables
@@ -73,9 +76,10 @@ class InspectorBuilder : public ProgramBuilder {
/// @param inout_vars tuples of {in, out} that will be converted into out = in
/// calls in the function body
/// @param attributes the function attributes
- void MakeInOutVariableBodyFunction(std::string name,
- std::vector<std::tuple<std::string, std::string>> inout_vars,
- ast::AttributeList attributes);
+ void MakeInOutVariableBodyFunction(
+ std::string name,
+ utils::VectorRef<std::tuple<std::string, std::string>> inout_vars,
+ utils::VectorRef<const ast::Attribute*> attributes);
// TODO(crbug.com/tint/697): Remove this.
/// Generates a function that references in/out variables and calls another
@@ -89,34 +93,8 @@ class InspectorBuilder : public ProgramBuilder {
const ast::Function* MakeInOutVariableCallerBodyFunction(
std::string caller,
std::string callee,
- std::vector<std::tuple<std::string, std::string>> inout_vars,
- ast::AttributeList attributes);
-
- /// Add a pipeline constant to the global variables, with a specific ID.
- /// @param name name of the variable to add
- /// @param id id number for the constant id
- /// @param type type of the variable
- /// @param constructor val to initialize the constant with, if NULL no
- /// constructor will be added.
- /// @returns the constant that was created
- const ast::Variable* AddOverridableConstantWithID(std::string name,
- uint32_t id,
- const ast::Type* type,
- const ast::Expression* constructor) {
- return Override(name, type, constructor, {Id(id)});
- }
-
- /// Add a pipeline constant to the global variables, without a specific ID.
- /// @param name name of the variable to add
- /// @param type type of the variable
- /// @param constructor val to initialize the constant with, if NULL no
- /// constructor will be added.
- /// @returns the constant that was created
- const ast::Variable* AddOverridableConstantWithoutID(std::string name,
- const ast::Type* type,
- const ast::Expression* constructor) {
- return Override(name, type, constructor);
- }
+ utils::VectorRef<std::tuple<std::string, std::string>> inout_vars,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that references module-scoped, plain-typed constant
/// or variable.
@@ -125,15 +103,16 @@ class InspectorBuilder : public ProgramBuilder {
/// @param type type of the const being referenced
/// @param attributes the function attributes
/// @returns a function object
- const ast::Function* MakePlainGlobalReferenceBodyFunction(std::string func,
- std::string var,
- const ast::Type* type,
- ast::AttributeList attributes);
+ const ast::Function* MakePlainGlobalReferenceBodyFunction(
+ std::string func,
+ std::string var,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// @param vec Vector of StageVariable to be searched
/// @param name Name to be searching for
/// @returns true if name is in vec, otherwise false
- bool ContainsName(const std::vector<StageVariable>& vec, const std::string& name);
+ bool ContainsName(utils::VectorRef<StageVariable> vec, const std::string& name);
/// Builds a string for accessing a member in a generated struct
/// @param idx index of member
@@ -146,14 +125,15 @@ class InspectorBuilder : public ProgramBuilder {
/// @param member_types a vector of member types
/// @returns a struct type
const ast::Struct* MakeStructType(const std::string& name,
- std::vector<const ast::Type*> member_types);
+ utils::VectorRef<const ast::Type*> member_types);
/// Generates a struct type from a list of member nodes.
/// @param name name for the struct type
/// @param members a vector of members
/// @returns a struct type
- const ast::Struct* MakeStructTypeFromMembers(const std::string& name,
- ast::StructMemberList members);
+ const ast::Struct* MakeStructTypeFromMembers(
+ const std::string& name,
+ utils::VectorRef<const ast::StructMember*> members);
/// Generates a struct member with a specified index and type.
/// @param index index of the field within the struct
@@ -162,14 +142,14 @@ class InspectorBuilder : public ProgramBuilder {
/// @returns a struct member
const ast::StructMember* MakeStructMember(size_t index,
const ast::Type* type,
- ast::AttributeList attributes);
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Generates types appropriate for using in an uniform buffer
/// @param name name for the type
/// @param member_types a vector of member types
/// @returns a struct type that has the layout for an uniform buffer.
const ast::Struct* MakeUniformBufferType(const std::string& name,
- std::vector<const ast::Type*> member_types);
+ utils::VectorRef<const ast::Type*> member_types);
/// Generates types appropriate for using in a storage buffer
/// @param name name for the type
@@ -177,7 +157,7 @@ class InspectorBuilder : public ProgramBuilder {
/// @returns a function that returns the created structure.
std::function<const ast::TypeName*()> MakeStorageBufferTypes(
const std::string& name,
- std::vector<const ast::Type*> member_types);
+ utils::VectorRef<const ast::Type*> member_types);
/// Adds an uniform buffer variable to the program
/// @param name the name of the variable
@@ -206,14 +186,16 @@ class InspectorBuilder : public ProgramBuilder {
uint32_t group,
uint32_t binding);
+ /// MemberInfo is a tuple of member index and type.
+ using MemberInfo = std::tuple<size_t, const ast::Type*>;
+
/// Generates a function that references a specific struct variable
/// @param func_name name of the function created
/// @param struct_name name of the struct variabler to be accessed
/// @param members list of members to access, by index and type
- void MakeStructVariableReferenceBodyFunction(
- std::string func_name,
- std::string struct_name,
- std::vector<std::tuple<size_t, const ast::Type*>> members);
+ void MakeStructVariableReferenceBodyFunction(std::string func_name,
+ std::string struct_name,
+ utils::VectorRef<MemberInfo> members);
/// Adds a regular sampler variable to the program
/// @param name the name of the variable
@@ -250,12 +232,13 @@ class InspectorBuilder : public ProgramBuilder {
/// @param base_type sampler base type
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
- const ast::Function* MakeSamplerReferenceBodyFunction(const std::string& func_name,
- const std::string& texture_name,
- const std::string& sampler_name,
- const std::string& coords_name,
- const ast::Type* base_type,
- ast::AttributeList attributes);
+ const ast::Function* MakeSamplerReferenceBodyFunction(
+ const std::string& func_name,
+ const std::string& texture_name,
+ const std::string& sampler_name,
+ const std::string& coords_name,
+ const ast::Type* base_type,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that references a specific sampler variable
/// @param func_name name of the function created
@@ -266,13 +249,14 @@ class InspectorBuilder : public ProgramBuilder {
/// @param base_type sampler base type
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
- const ast::Function* MakeSamplerReferenceBodyFunction(const std::string& func_name,
- const std::string& texture_name,
- const std::string& sampler_name,
- const std::string& coords_name,
- const std::string& array_index,
- const ast::Type* base_type,
- ast::AttributeList attributes);
+ const ast::Function* MakeSamplerReferenceBodyFunction(
+ const std::string& func_name,
+ const std::string& texture_name,
+ const std::string& sampler_name,
+ const std::string& coords_name,
+ const std::string& array_index,
+ const ast::Type* base_type,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that references a specific comparison sampler
/// variable.
@@ -284,13 +268,14 @@ class InspectorBuilder : public ProgramBuilder {
/// @param base_type sampler base type
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
- const ast::Function* MakeComparisonSamplerReferenceBodyFunction(const std::string& func_name,
- const std::string& texture_name,
- const std::string& sampler_name,
- const std::string& coords_name,
- const std::string& depth_name,
- const ast::Type* base_type,
- ast::AttributeList attributes);
+ const ast::Function* MakeComparisonSamplerReferenceBodyFunction(
+ const std::string& func_name,
+ const std::string& texture_name,
+ const std::string& sampler_name,
+ const std::string& coords_name,
+ const std::string& depth_name,
+ const ast::Type* base_type,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Gets an appropriate type for the data in a given texture type.
/// @param sampled_kind type of in the texture
@@ -326,10 +311,11 @@ class InspectorBuilder : public ProgramBuilder {
/// @param dim_type type expected by textureDimensons to return
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
- const ast::Function* MakeStorageTextureBodyFunction(const std::string& func_name,
- const std::string& st_name,
- const ast::Type* dim_type,
- ast::AttributeList attributes);
+ const ast::Function* MakeStorageTextureBodyFunction(
+ const std::string& func_name,
+ const std::string& st_name,
+ const ast::Type* dim_type,
+ utils::VectorRef<const ast::Attribute*> attributes);
/// Get a generator function that returns a type appropriate for a stage
/// variable with the given combination of component and composition type.
diff --git a/chromium/third_party/dawn/src/tint/intrinsics.def b/chromium/third_party/dawn/src/tint/intrinsics.def
index 5ac57739a26..2b84d45fb3e 100644
--- a/chromium/third_party/dawn/src/tint/intrinsics.def
+++ b/chromium/third_party/dawn/src/tint/intrinsics.def
@@ -23,14 +23,48 @@
// Enumerators //
////////////////////////////////////////////////////////////////////////////////
+// https://gpuweb.github.io/gpuweb/wgsl/#builtin-values
+enum builtin_value {
+ position
+ vertex_index
+ instance_index
+ front_facing
+ frag_depth
+ local_invocation_id
+ local_invocation_index
+ global_invocation_id
+ workgroup_id
+ num_workgroups
+ sample_index
+ sample_mask
+ @internal point_size
+}
+
+// https://gpuweb.github.io/gpuweb/wgsl/#extension
+enum extension {
+ // WGSL Extension "f16"
+ f16
+ // An extension for the experimental feature "chromium_experimental_dp4a".
+ // See crbug.com/tint/1497 for more details
+ chromium_experimental_dp4a
+ // A Chromium-specific extension for disabling uniformity analysis.
+ chromium_disable_uniformity_analysis
+ // A Chromium-specific extension for push constants
+ chromium_experimental_push_constant
+}
+
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
enum storage_class {
+ @internal none
function
private
workgroup
uniform
storage
+ push_constant
@internal handle
+ @internal in
+ @internal out
}
// https://gpuweb.github.io/gpuweb/wgsl/#memory-access-mode
@@ -71,11 +105,12 @@ enum texel_format {
// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
type bool
-@precedence(4) @display("abstract-float") type af
-@precedence(3) @display("abstract-int") type ai
-@precedence(2) type i32
-@precedence(1) type u32
-@precedence(0) type f32
+@precedence(5) @display("abstract-float") type fa
+@precedence(4) @display("abstract-int") type ia
+@precedence(3) type i32
+@precedence(2) type u32
+@precedence(1) type f32
+@precedence(0) type f16
type vec2<T>
type vec3<T>
type vec4<T>
@@ -113,10 +148,10 @@ type texture_storage_2d_array<F: texel_format, A: access>
type texture_storage_3d<F: texel_format, A: access>
type texture_external
-type __modf_result
-@display("__modf_result_vec{N}") type __modf_result_vec<N: num>
-type __frexp_result
-@display("__frexp_result_vec{N}") type __frexp_result_vec<N: num>
+@display("__modf_result_{T}") type __modf_result<T>
+@display("__modf_result_vec{N}_{T}") type __modf_result_vec<N: num, T>
+@display("__frexp_result_{T}") type __frexp_result<T>
+@display("__frexp_result_vec{N}_{T}") type __frexp_result_vec<N: num, T>
type __atomic_compare_exchange_result<T>
@@ -126,16 +161,25 @@ type __atomic_compare_exchange_result<T>
// A type matcher that can match one or more types. //
////////////////////////////////////////////////////////////////////////////////
+match abstract_or_scalar: ia | fa | f32 | f16 | i32 | u32 | bool
+match scalar: f32 | f16 | i32 | u32 | bool
+match scalar_no_f32: i32 | f16 | u32 | bool
+match scalar_no_f16: f32 | i32 | u32 | bool
+match scalar_no_i32: f32 | f16 | u32 | bool
+match scalar_no_u32: f32 | f16 | i32 | bool
+match scalar_no_bool: f32 | f16 | i32 | u32
+match fia_fiu32_f16: fa | ia | f32 | i32 | u32 | f16
+match fia_fi32_f16: fa | ia | f32 | i32 | f16
+match fia_fiu32: fa | ia | f32 | i32 | u32
+match fa_f32: fa | f32
+match fa_f32_f16: fa | f32 | f16
+match ia_iu32: ia | i32 | u32
+match fiu32_f16: f32 | i32 | u32 | f16
match fiu32: f32 | i32 | u32
+match fi32_f16: f32 | i32 | f16
match fi32: f32 | i32
+match f32_f16: f32 | f16
match iu32: i32 | u32
-match scalar: f32 | i32 | u32 | bool
-match abstract_or_scalar: ai | af | f32 | i32 | u32 | bool
-match af_f32: af | f32
-match scalar_no_f32: i32 | u32 | bool
-match scalar_no_i32: f32 | u32 | bool
-match scalar_no_u32: f32 | i32 | bool
-match scalar_no_bool: f32 | i32 | u32
////////////////////////////////////////////////////////////////////////////////
// Enum matchers //
@@ -146,17 +190,38 @@ match scalar_no_bool: f32 | i32 | u32
////////////////////////////////////////////////////////////////////////////////
// https://gpuweb.github.io/gpuweb/wgsl/#texel-formats
-match f32_texel_format:
- rgba8unorm | rgba8snorm | rgba16float | r32float | rg32float | rgba32float
-match i32_texel_format:
- rgba8sint | rgba16sint | r32sint | rg32sint | rgba32sint
-match u32_texel_format:
- rgba8uint | rgba16uint | r32uint | rg32uint | rgba32uint
-
-match write_only: write
-
-match function_private_workgroup: function | private | workgroup
-match workgroup_or_storage: workgroup | storage
+match f32_texel_format
+ : texel_format.rgba8unorm
+ | texel_format.rgba8snorm
+ | texel_format.rgba16float
+ | texel_format.r32float
+ | texel_format.rg32float
+ | texel_format.rgba32float
+match i32_texel_format
+ : texel_format.rgba8sint
+ | texel_format.rgba16sint
+ | texel_format.r32sint
+ | texel_format.rg32sint
+ | texel_format.rgba32sint
+match u32_texel_format
+ : texel_format.rgba8uint
+ | texel_format.rgba16uint
+ | texel_format.r32uint
+ | texel_format.rg32uint
+ | texel_format.rgba32uint
+
+match write: access.write
+match read_write: access.read_write
+
+match function_private_workgroup
+ : storage_class.function
+ | storage_class.private
+ | storage_class.workgroup
+match workgroup_or_storage
+ : storage_class.workgroup
+ | storage_class.storage
+match storage
+ : storage_class.storage
////////////////////////////////////////////////////////////////////////////////
// Builtin Functions //
@@ -325,42 +390,48 @@ match workgroup_or_storage: workgroup | storage
////////////////////////////////////////////////////////////////////////////////
// https://gpuweb.github.io/gpuweb/wgsl/#builtin-functions
-fn abs<T: fiu32>(T) -> T
-fn abs<N: num, T: fiu32>(vec<N, T>) -> vec<N, T>
-fn acos(f32) -> f32
-fn acos<N: num>(vec<N, f32>) -> vec<N, f32>
+fn abs<T: fiu32_f16>(T) -> T
+fn abs<N: num, T: fiu32_f16>(vec<N, T>) -> vec<N, T>
+fn acos<T: f32_f16>(T) -> T
+fn acos<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn acosh<T: f32_f16>(T) -> T
+fn acosh<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn all(bool) -> bool
fn all<N: num>(vec<N, bool>) -> bool
fn any(bool) -> bool
fn any<N: num>(vec<N, bool>) -> bool
fn arrayLength<T, A: access>(ptr<storage, array<T>, A>) -> u32
-fn asin(f32) -> f32
-fn asin<N: num>(vec<N, f32>) -> vec<N, f32>
-fn atan(f32) -> f32
-fn atan<N: num>(vec<N, f32>) -> vec<N, f32>
-fn atan2(f32, f32) -> f32
-fn atan2<N: num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32>
-fn ceil(f32) -> f32
-fn ceil<N: num>(vec<N, f32>) -> vec<N, f32>
-fn clamp<T: fiu32>(T, T, T) -> T
-fn clamp<N: num, T: fiu32>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
-fn cos(f32) -> f32
-fn cos<N: num>(vec<N, f32>) -> vec<N, f32>
-fn cosh(f32) -> f32
-fn cosh<N: num>(vec<N, f32>) -> vec<N, f32>
+fn asin<T: f32_f16>(T) -> T
+fn asin<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn asinh<T: f32_f16>(T) -> T
+fn asinh<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn atan<T: f32_f16>(T) -> T
+fn atan<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+@const fn atan2<T: fa_f32_f16>(T, T) -> T
+@const fn atan2<T: fa_f32_f16, N: num>(vec<N, T>, vec<N, T>) -> vec<N, T>
+fn atanh<T: f32_f16>(T) -> T
+fn atanh<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn ceil<T: f32_f16>(T) -> T
+fn ceil<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+@const fn clamp<T: fia_fiu32_f16>(T, T, T) -> T
+@const fn clamp<T: fia_fiu32_f16, N: num>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+fn cos<T: f32_f16>(T) -> T
+fn cos<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn cosh<T: f32_f16>(T) -> T
+fn cosh<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn countLeadingZeros<T: iu32>(T) -> T
fn countLeadingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
fn countOneBits<T: iu32>(T) -> T
fn countOneBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
fn countTrailingZeros<T: iu32>(T) -> T
fn countTrailingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-fn cross(vec3<f32>, vec3<f32>) -> vec3<f32>
-fn degrees(f32) -> f32
-fn degrees<N: num>(vec<N, f32>) -> vec<N, f32>
-fn determinant<N: num>(mat<N, N, f32>) -> f32
-fn distance(f32, f32) -> f32
-fn distance<N: num>(vec<N, f32>, vec<N, f32>) -> f32
-fn dot<N: num, T: fiu32>(vec<N, T>, vec<N, T>) -> T
+fn cross<T: f32_f16>(vec3<T>, vec3<T>) -> vec3<T>
+fn degrees<T: f32_f16>(T) -> T
+fn degrees<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn determinant<N: num, T: f32_f16>(mat<N, N, T>) -> T
+fn distance<T: f32_f16>(T, T) -> T
+fn distance<N: num, T: f32_f16>(vec<N, T>, vec<N, T>) -> T
+fn dot<N: num, T: fiu32_f16>(vec<N, T>, vec<N, T>) -> T
fn dot4I8Packed(u32, u32) -> i32
fn dot4U8Packed(u32, u32) -> u32
@stage("fragment") fn dpdx(f32) -> f32
@@ -375,25 +446,25 @@ fn dot4U8Packed(u32, u32) -> u32
@stage("fragment") fn dpdyCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
@stage("fragment") fn dpdyFine(f32) -> f32
@stage("fragment") fn dpdyFine<N: num>(vec<N, f32>) -> vec<N, f32>
-fn exp(f32) -> f32
-fn exp<N: num>(vec<N, f32>) -> vec<N, f32>
-fn exp2(f32) -> f32
-fn exp2<N: num>(vec<N, f32>) -> vec<N, f32>
+fn exp<T: f32_f16>(T) -> T
+fn exp<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn exp2<T: f32_f16>(T) -> T
+fn exp2<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn extractBits<T: iu32>(T, u32, u32) -> T
fn extractBits<N: num, T: iu32>(vec<N, T>, u32, u32) -> vec<N, T>
-fn faceForward<N: num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32>
+fn faceForward<N: num, T: f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
fn firstLeadingBit<T: iu32>(T) -> T
fn firstLeadingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
fn firstTrailingBit<T: iu32>(T) -> T
fn firstTrailingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-fn floor(f32) -> f32
-fn floor<N: num>(vec<N, f32>) -> vec<N, f32>
-fn fma(f32, f32, f32) -> f32
-fn fma<N: num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32>
-fn fract(f32) -> f32
-fn fract<N: num>(vec<N, f32>) -> vec<N, f32>
-fn frexp(f32) -> __frexp_result
-fn frexp<N: num>(vec<N, f32>) -> __frexp_result_vec<N>
+fn floor<T: f32_f16>(T) -> T
+fn floor<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn fma<T: f32_f16>(T, T, T) -> T
+fn fma<N: num, T: f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+fn fract<T: f32_f16>(T) -> T
+fn fract<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn frexp<T: f32_f16>(T) -> __frexp_result<T>
+fn frexp<N: num, T: f32_f16>(vec<N, T>) -> __frexp_result_vec<N, T>
@stage("fragment") fn fwidth(f32) -> f32
@stage("fragment") fn fwidth<N: num>(vec<N, f32>) -> vec<N, f32>
@stage("fragment") fn fwidthCoarse(f32) -> f32
@@ -402,66 +473,64 @@ fn frexp<N: num>(vec<N, f32>) -> __frexp_result_vec<N>
@stage("fragment") fn fwidthFine<N: num>(vec<N, f32>) -> vec<N, f32>
fn insertBits<T: iu32>(T, T, u32, u32) -> T
fn insertBits<N: num, T: iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T>
-fn inverseSqrt(f32) -> f32
-fn inverseSqrt<N: num>(vec<N, f32>) -> vec<N, f32>
-fn ldexp(f32, i32) -> f32
-fn ldexp<N: num>(vec<N, f32>, vec<N, i32>) -> vec<N, f32>
-fn length(f32) -> f32
-fn length<N: num>(vec<N, f32>) -> f32
-fn log(f32) -> f32
-fn log<N: num>(vec<N, f32>) -> vec<N, f32>
-fn log2(f32) -> f32
-fn log2<N: num>(vec<N, f32>) -> vec<N, f32>
-fn max<T: fiu32>(T, T) -> T
-fn max<N: num, T: fiu32>(vec<N, T>, vec<N, T>) -> vec<N, T>
-fn min<T: fiu32>(T, T) -> T
-fn min<N: num, T: fiu32>(vec<N, T>, vec<N, T>) -> vec<N, T>
-fn mix(f32, f32, f32) -> f32
-fn mix<N: num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32>
-fn mix<N: num>(vec<N, f32>, vec<N, f32>, f32) -> vec<N, f32>
-fn modf(f32) -> __modf_result
-fn modf<N: num>(vec<N, f32>) -> __modf_result_vec<N>
-fn normalize<N: num>(vec<N, f32>) -> vec<N, f32>
+fn inverseSqrt<T: f32_f16>(T) -> T
+fn inverseSqrt<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn ldexp<T: f32_f16>(T, i32) -> T
+fn ldexp<N: num, T: f32_f16>(vec<N, T>, vec<N, i32>) -> vec<N, T>
+fn length<T: f32_f16>(T) -> T
+fn length<N: num, T: f32_f16>(vec<N, T>) -> T
+fn log<T: f32_f16>(T) -> T
+fn log<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn log2<T: f32_f16>(T) -> T
+fn log2<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn max<T: fiu32_f16>(T, T) -> T
+fn max<N: num, T: fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+fn min<T: fiu32_f16>(T, T) -> T
+fn min<N: num, T: fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+fn mix<T: f32_f16>(T, T, T) -> T
+fn mix<N: num, T: f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+fn mix<N: num, T: f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
+fn modf<T: f32_f16>(T) -> __modf_result<T>
+fn modf<N: num, T: f32_f16>(vec<N, T>) -> __modf_result_vec<N, T>
+fn normalize<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn pack2x16float(vec2<f32>) -> u32
fn pack2x16snorm(vec2<f32>) -> u32
fn pack2x16unorm(vec2<f32>) -> u32
fn pack4x8snorm(vec4<f32>) -> u32
fn pack4x8unorm(vec4<f32>) -> u32
-fn pow(f32, f32) -> f32
-fn pow<N: num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32>
-fn radians(f32) -> f32
-fn radians<N: num>(vec<N, f32>) -> vec<N, f32>
-fn reflect<N: num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32>
-fn refract<N: num>(vec<N, f32>, vec<N, f32>, f32) -> vec<N, f32>
+fn pow<T: f32_f16>(T, T) -> T
+fn pow<N: num, T: f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+fn radians<T: f32_f16>(T) -> T
+fn radians<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn reflect<N: num, T: f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+fn refract<N: num, T: f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
fn reverseBits<T: iu32>(T) -> T
fn reverseBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-fn round(f32) -> f32
-fn round<N: num>(vec<N, f32>) -> vec<N, f32>
+fn round<T: f32_f16>(T) -> T
+fn round<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn select<T: scalar>(T, T, bool) -> T
fn select<T: scalar, N: num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T>
fn select<N: num, T: scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T>
-fn sign(f32) -> f32
-fn sign<N: num>(vec<N, f32>) -> vec<N, f32>
-fn sin(f32) -> f32
-fn sin<N: num>(vec<N, f32>) -> vec<N, f32>
-fn sinh(f32) -> f32
-fn sinh<N: num>(vec<N, f32>) -> vec<N, f32>
-fn smoothstep(f32, f32, f32) -> f32
-fn smoothstep<N: num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32>
-@deprecated fn smoothStep(f32, f32, f32) -> f32
-@deprecated fn smoothStep<N: num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32>
-fn sqrt(f32) -> f32
-fn sqrt<N: num>(vec<N, f32>) -> vec<N, f32>
-fn step(f32, f32) -> f32
-fn step<N: num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32>
+fn sign<T: f32_f16>(T) -> T
+fn sign<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn sin<T: f32_f16>(T) -> T
+fn sin<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn sinh<T: f32_f16>(T) -> T
+fn sinh<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn smoothstep<T: f32_f16>(T, T, T) -> T
+fn smoothstep<N: num, T: f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+fn sqrt<T: f32_f16>(T) -> T
+fn sqrt<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn step<T: f32_f16>(T, T) -> T
+fn step<N: num, T: f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
@stage("compute") fn storageBarrier()
-fn tan(f32) -> f32
-fn tan<N: num>(vec<N, f32>) -> vec<N, f32>
-fn tanh(f32) -> f32
-fn tanh<N: num>(vec<N, f32>) -> vec<N, f32>
-fn transpose<M: num, N: num>(mat<M, N, f32>) -> mat<N, M, f32>
-fn trunc(f32) -> f32
-fn trunc<N: num>(vec<N, f32>) -> vec<N, f32>
+fn tan<T: f32_f16>(T) -> T
+fn tan<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn tanh<T: f32_f16>(T) -> T
+fn tanh<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
+fn transpose<M: num, N: num, T: f32_f16>(mat<M, N, T>) -> mat<N, M, T>
+fn trunc<T: f32_f16>(T) -> T
+fn trunc<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn unpack2x16float(u32) -> vec2<f32>
fn unpack2x16snorm(u32) -> vec2<f32>
fn unpack2x16unorm(u32) -> vec2<f32>
@@ -491,10 +560,10 @@ fn textureDimensions(texture: texture_depth_cube, level: i32) -> vec2<i32>
fn textureDimensions(texture: texture_depth_cube_array) -> vec2<i32>
fn textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2<i32>
fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<i32>
-fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_1d<F, A>) -> i32
-fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_2d<F, A>) -> vec2<i32>
-fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_2d_array<F, A>) -> vec2<i32>
-fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_3d<F, A>) -> vec3<i32>
+fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_1d<F, A>) -> i32
+fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d<F, A>) -> vec2<i32>
+fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> vec2<i32>
+fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_3d<F, A>) -> vec3<i32>
fn textureDimensions(texture: texture_external) -> vec2<i32>
fn textureGather<T: fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T>
fn textureGather<T: fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T>
@@ -518,7 +587,7 @@ fn textureNumLayers<T: fiu32>(texture: texture_2d_array<T>) -> i32
fn textureNumLayers<T: fiu32>(texture: texture_cube_array<T>) -> i32
fn textureNumLayers(texture: texture_depth_2d_array) -> i32
fn textureNumLayers(texture: texture_depth_cube_array) -> i32
-fn textureNumLayers<F: texel_format, A: write_only>(texture: texture_storage_2d_array<F, A>) -> i32
+fn textureNumLayers<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> i32
fn textureNumLevels<T: fiu32>(texture: texture_1d<T>) -> i32
fn textureNumLevels<T: fiu32>(texture: texture_2d<T>) -> i32
fn textureNumLevels<T: fiu32>(texture: texture_2d_array<T>) -> i32
@@ -628,134 +697,166 @@ fn textureLoad(texture: texture_external, coords: vec2<i32>) -> vec4<f32>
////////////////////////////////////////////////////////////////////////////////
// Zero value constructors
-ctor i32() -> i32
-ctor u32() -> u32
-ctor f32() -> f32
-ctor bool() -> bool
-ctor vec2<T: scalar>() -> vec2<T>
-ctor vec3<T: scalar>() -> vec3<T>
-ctor vec4<T: scalar>() -> vec4<T>
-ctor mat2x2() -> mat2x2<f32>
-ctor mat2x3() -> mat2x3<f32>
-ctor mat2x4() -> mat2x4<f32>
-ctor mat3x2() -> mat3x2<f32>
-ctor mat3x3() -> mat3x3<f32>
-ctor mat3x4() -> mat3x4<f32>
-ctor mat4x2() -> mat4x2<f32>
-ctor mat4x3() -> mat4x3<f32>
-ctor mat4x4() -> mat4x4<f32>
+@const("Zero") ctor i32() -> i32
+@const("Zero") ctor u32() -> u32
+@const("Zero") ctor f32() -> f32
+@const("Zero") ctor f16() -> f16
+@const("Zero") ctor bool() -> bool
+@const("Zero") ctor vec2<T: scalar>() -> vec2<T>
+@const("Zero") ctor vec3<T: scalar>() -> vec3<T>
+@const("Zero") ctor vec4<T: scalar>() -> vec4<T>
+@const("Zero") ctor mat2x2<T: f32_f16>() -> mat2x2<T>
+@const("Zero") ctor mat2x3<T: f32_f16>() -> mat2x3<T>
+@const("Zero") ctor mat2x4<T: f32_f16>() -> mat2x4<T>
+@const("Zero") ctor mat3x2<T: f32_f16>() -> mat3x2<T>
+@const("Zero") ctor mat3x3<T: f32_f16>() -> mat3x3<T>
+@const("Zero") ctor mat3x4<T: f32_f16>() -> mat3x4<T>
+@const("Zero") ctor mat4x2<T: f32_f16>() -> mat4x2<T>
+@const("Zero") ctor mat4x3<T: f32_f16>() -> mat4x3<T>
+@const("Zero") ctor mat4x4<T: f32_f16>() -> mat4x4<T>
// Identity constructors
-ctor i32(i32) -> i32
-ctor u32(u32) -> u32
-ctor f32(f32) -> f32
-ctor bool(bool) -> bool
-ctor vec2<T: scalar>(vec2<T>) -> vec2<T>
-ctor vec3<T: scalar>(vec3<T>) -> vec3<T>
-ctor vec4<T: scalar>(vec4<T>) -> vec4<T>
-ctor mat2x2<f32>(mat2x2<f32>) -> mat2x2<f32>
-ctor mat2x3<f32>(mat2x3<f32>) -> mat2x3<f32>
-ctor mat2x4<f32>(mat2x4<f32>) -> mat2x4<f32>
-ctor mat3x2<f32>(mat3x2<f32>) -> mat3x2<f32>
-ctor mat3x3<f32>(mat3x3<f32>) -> mat3x3<f32>
-ctor mat3x4<f32>(mat3x4<f32>) -> mat3x4<f32>
-ctor mat4x2<f32>(mat4x2<f32>) -> mat4x2<f32>
-ctor mat4x3<f32>(mat4x3<f32>) -> mat4x3<f32>
-ctor mat4x4<f32>(mat4x4<f32>) -> mat4x4<f32>
-
-// Vector constructors
-ctor vec2<T: abstract_or_scalar>(T) -> vec2<T>
-ctor vec2<T: abstract_or_scalar>(x: T, y: T) -> vec2<T>
-ctor vec3<T: abstract_or_scalar>(T) -> vec3<T>
-ctor vec3<T: abstract_or_scalar>(x: T, y: T, z: T) -> vec3<T>
-ctor vec3<T: abstract_or_scalar>(xy: vec2<T>, z: T) -> vec3<T>
-ctor vec3<T: abstract_or_scalar>(x: T, yz: vec2<T>) -> vec3<T>
-ctor vec4<T: abstract_or_scalar>(T) -> vec4<T>
-ctor vec4<T: abstract_or_scalar>(x: T, y: T, z: T, w: T) -> vec4<T>
-ctor vec4<T: abstract_or_scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T>
-ctor vec4<T: abstract_or_scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T>
-ctor vec4<T: abstract_or_scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T>
-ctor vec4<T: abstract_or_scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T>
-ctor vec4<T: abstract_or_scalar>(xyz: vec3<T>, w: T) -> vec4<T>
-ctor vec4<T: abstract_or_scalar>(x: T, zyw: vec3<T>) -> vec4<T>
-
-// Matrix constructors
-ctor mat2x2<T: af_f32>(T) -> mat2x2<T>
-ctor mat2x2<T: af_f32>(T, T,
- T, T) -> mat2x2<T>
-ctor mat2x2<T: af_f32>(vec2<T>, vec2<T>) -> mat2x2<T>
-
-ctor mat2x3<T: af_f32>(T) -> mat2x3<T>
-ctor mat2x3<T: af_f32>(T, T, T,
- T, T, T) -> mat2x3<T>
-ctor mat2x3<T: af_f32>(vec3<T>, vec3<T>) -> mat2x3<T>
-
-ctor mat2x4<T: af_f32>(T) -> mat2x4<T>
-ctor mat2x4<T: af_f32>(T, T, T, T,
- T, T, T, T) -> mat2x4<T>
-ctor mat2x4<T: af_f32>(vec4<T>, vec4<T>) -> mat2x4<T>
-
-ctor mat3x2<T: af_f32>(T) -> mat3x2<T>
-ctor mat3x2<T: af_f32>(T, T,
- T, T,
- T, T) -> mat3x2<T>
-ctor mat3x2<T: af_f32>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T>
-
-ctor mat3x3<T: af_f32>(T) -> mat3x3<T>
-ctor mat3x3<T: af_f32>(T, T, T,
- T, T, T,
- T, T, T) -> mat3x3<T>
-ctor mat3x3<T: af_f32>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T>
-
-ctor mat3x4<T: af_f32>(T) -> mat3x4<T>
-ctor mat3x4<T: af_f32>(T, T, T, T,
- T, T, T, T,
- T, T, T, T) -> mat3x4<T>
-ctor mat3x4<T: af_f32>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T>
-
-ctor mat4x2<T: af_f32>(T) -> mat4x2<T>
-ctor mat4x2<T: af_f32>(T, T,
- T, T,
- T, T,
- T, T) -> mat4x2<T>
-ctor mat4x2<T: af_f32>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T>
-
-ctor mat4x3<T: af_f32>(T) -> mat4x3<T>
-ctor mat4x3<T: af_f32>(T, T, T,
- T, T, T,
- T, T, T,
- T, T, T) -> mat4x3<T>
-ctor mat4x3<T: af_f32>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T>
-
-ctor mat4x4<T: af_f32>(T) -> mat4x4<T>
-ctor mat4x4<T: af_f32>(T, T, T, T,
- T, T, T, T,
- T, T, T, T,
- T, T, T, T) -> mat4x4<T>
-ctor mat4x4<T: af_f32>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T>
+@const("Identity") ctor i32(i32) -> i32
+@const("Identity") ctor u32(u32) -> u32
+@const("Identity") ctor f32(f32) -> f32
+@const("Identity") ctor f16(f16) -> f16
+@const("Identity") ctor bool(bool) -> bool
+@const("Identity") ctor vec2<T: scalar>(vec2<T>) -> vec2<T>
+@const("Identity") ctor vec3<T: scalar>(vec3<T>) -> vec3<T>
+@const("Identity") ctor vec4<T: scalar>(vec4<T>) -> vec4<T>
+@const("Identity") ctor mat2x2<T: f32_f16>(mat2x2<T>) -> mat2x2<T>
+@const("Identity") ctor mat2x3<T: f32_f16>(mat2x3<T>) -> mat2x3<T>
+@const("Identity") ctor mat2x4<T: f32_f16>(mat2x4<T>) -> mat2x4<T>
+@const("Identity") ctor mat3x2<T: f32_f16>(mat3x2<T>) -> mat3x2<T>
+@const("Identity") ctor mat3x3<T: f32_f16>(mat3x3<T>) -> mat3x3<T>
+@const("Identity") ctor mat3x4<T: f32_f16>(mat3x4<T>) -> mat3x4<T>
+@const("Identity") ctor mat4x2<T: f32_f16>(mat4x2<T>) -> mat4x2<T>
+@const("Identity") ctor mat4x3<T: f32_f16>(mat4x3<T>) -> mat4x3<T>
+@const("Identity") ctor mat4x4<T: f32_f16>(mat4x4<T>) -> mat4x4<T>
+
+// Vector constructors (splat)
+@const("VecSplat") ctor vec2<T: abstract_or_scalar>(T) -> vec2<T>
+@const("VecSplat") ctor vec3<T: abstract_or_scalar>(T) -> vec3<T>
+@const("VecSplat") ctor vec4<T: abstract_or_scalar>(T) -> vec4<T>
+
+// Vector constructors (scalar)
+@const("VecCtorS") ctor vec2<T: abstract_or_scalar>(x: T, y: T) -> vec2<T>
+@const("VecCtorS") ctor vec3<T: abstract_or_scalar>(x: T, y: T, z: T) -> vec3<T>
+@const("VecCtorS") ctor vec4<T: abstract_or_scalar>(x: T, y: T, z: T, w: T) -> vec4<T>
+
+// Vector constructors (mixed)
+@const("VecCtorM") ctor vec3<T: abstract_or_scalar>(xy: vec2<T>, z: T) -> vec3<T>
+@const("VecCtorM") ctor vec3<T: abstract_or_scalar>(x: T, yz: vec2<T>) -> vec3<T>
+@const("VecCtorM") ctor vec4<T: abstract_or_scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T>
+@const("VecCtorM") ctor vec4<T: abstract_or_scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T>
+@const("VecCtorM") ctor vec4<T: abstract_or_scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T>
+@const("VecCtorM") ctor vec4<T: abstract_or_scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T>
+@const("VecCtorM") ctor vec4<T: abstract_or_scalar>(xyz: vec3<T>, w: T) -> vec4<T>
+@const("VecCtorM") ctor vec4<T: abstract_or_scalar>(x: T, zyw: vec3<T>) -> vec4<T>
+
+// Matrix constructors (scalar)
+@const("MatCtorS")
+ctor mat2x2<T: fa_f32_f16>(T, T,
+ T, T) -> mat2x2<T>
+@const("MatCtorS")
+ctor mat2x3<T: fa_f32_f16>(T, T, T,
+ T, T, T) -> mat2x3<T>
+@const("MatCtorS")
+ctor mat2x4<T: fa_f32_f16>(T, T, T, T,
+ T, T, T, T) -> mat2x4<T>
+@const("MatCtorS")
+ctor mat3x2<T: fa_f32_f16>(T, T,
+ T, T,
+ T, T) -> mat3x2<T>
+@const("MatCtorS")
+ctor mat3x3<T: fa_f32_f16>(T, T, T,
+ T, T, T,
+ T, T, T) -> mat3x3<T>
+@const("MatCtorS")
+ctor mat3x4<T: fa_f32_f16>(T, T, T, T,
+ T, T, T, T,
+ T, T, T, T) -> mat3x4<T>
+@const("MatCtorS")
+ctor mat4x2<T: fa_f32_f16>(T, T,
+ T, T,
+ T, T,
+ T, T) -> mat4x2<T>
+@const("MatCtorS")
+ctor mat4x3<T: fa_f32_f16>(T, T, T,
+ T, T, T,
+ T, T, T,
+ T, T, T) -> mat4x3<T>
+@const("MatCtorS")
+ctor mat4x4<T: fa_f32_f16>(T, T, T, T,
+ T, T, T, T,
+ T, T, T, T,
+ T, T, T, T) -> mat4x4<T>
+
+// Matrix constructors (column vectors)
+@const("MatCtorV")
+ctor mat2x2<T: fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T>
+@const("MatCtorV")
+ctor mat2x3<T: fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T>
+@const("MatCtorV")
+ctor mat2x4<T: fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T>
+@const("MatCtorV")
+ctor mat3x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T>
+@const("MatCtorV")
+ctor mat3x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T>
+@const("MatCtorV")
+ctor mat3x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T>
+@const("MatCtorV")
+ctor mat4x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T>
+@const("MatCtorV")
+ctor mat4x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T>
+@const("MatCtorV")
+ctor mat4x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T>
////////////////////////////////////////////////////////////////////////////////
// Type conversions //
////////////////////////////////////////////////////////////////////////////////
-conv f32<T: scalar_no_f32>(T) -> f32
-conv i32<T: scalar_no_i32>(T) -> i32
-conv u32<T: scalar_no_u32>(T) -> u32
-conv bool<T: scalar_no_bool>(T) -> bool
-
-conv vec2<T: f32, U: scalar_no_f32>(vec2<U>) -> vec2<f32>
-conv vec2<T: i32, U: scalar_no_i32>(vec2<U>) -> vec2<i32>
-conv vec2<T: u32, U: scalar_no_u32>(vec2<U>) -> vec2<u32>
-conv vec2<T: bool, U: scalar_no_bool>(vec2<U>) -> vec2<bool>
-
-conv vec3<T: f32, U: scalar_no_f32>(vec3<U>) -> vec3<f32>
-conv vec3<T: i32, U: scalar_no_i32>(vec3<U>) -> vec3<i32>
-conv vec3<T: u32, U: scalar_no_u32>(vec3<U>) -> vec3<u32>
-conv vec3<T: bool, U: scalar_no_bool>(vec3<U>) -> vec3<bool>
-
-conv vec4<T: f32, U: scalar_no_f32>(vec4<U>) -> vec4<f32>
-conv vec4<T: i32, U: scalar_no_i32>(vec4<U>) -> vec4<i32>
-conv vec4<T: u32, U: scalar_no_u32>(vec4<U>) -> vec4<u32>
-conv vec4<T: bool, U: scalar_no_bool>(vec4<U>) -> vec4<bool>
+@const conv f32<T: scalar_no_f32>(T) -> f32
+@const conv f16<T: scalar_no_f16>(T) -> f16
+@const conv i32<T: scalar_no_i32>(T) -> i32
+@const conv u32<T: scalar_no_u32>(T) -> u32
+@const conv bool<T: scalar_no_bool>(T) -> bool
+
+@const conv vec2<T: f32, U: scalar_no_f32>(vec2<U>) -> vec2<f32>
+@const conv vec2<T: f16, U: scalar_no_f16>(vec2<U>) -> vec2<f16>
+@const conv vec2<T: i32, U: scalar_no_i32>(vec2<U>) -> vec2<i32>
+@const conv vec2<T: u32, U: scalar_no_u32>(vec2<U>) -> vec2<u32>
+@const conv vec2<T: bool, U: scalar_no_bool>(vec2<U>) -> vec2<bool>
+
+@const conv vec3<T: f32, U: scalar_no_f32>(vec3<U>) -> vec3<f32>
+@const conv vec3<T: f16, U: scalar_no_f16>(vec3<U>) -> vec3<f16>
+@const conv vec3<T: i32, U: scalar_no_i32>(vec3<U>) -> vec3<i32>
+@const conv vec3<T: u32, U: scalar_no_u32>(vec3<U>) -> vec3<u32>
+@const conv vec3<T: bool, U: scalar_no_bool>(vec3<U>) -> vec3<bool>
+
+@const conv vec4<T: f32, U: scalar_no_f32>(vec4<U>) -> vec4<f32>
+@const conv vec4<T: f16, U: scalar_no_f16>(vec4<U>) -> vec4<f16>
+@const conv vec4<T: i32, U: scalar_no_i32>(vec4<U>) -> vec4<i32>
+@const conv vec4<T: u32, U: scalar_no_u32>(vec4<U>) -> vec4<u32>
+@const conv vec4<T: bool, U: scalar_no_bool>(vec4<U>) -> vec4<bool>
+
+@const conv mat2x2<T: f16>(mat2x2<f32>) -> mat2x2<f16>
+@const conv mat2x2<T: f32>(mat2x2<f16>) -> mat2x2<f32>
+@const conv mat2x3<T: f16>(mat2x3<f32>) -> mat2x3<f16>
+@const conv mat2x3<T: f32>(mat2x3<f16>) -> mat2x3<f32>
+@const conv mat2x4<T: f16>(mat2x4<f32>) -> mat2x4<f16>
+@const conv mat2x4<T: f32>(mat2x4<f16>) -> mat2x4<f32>
+@const conv mat3x2<T: f16>(mat3x2<f32>) -> mat3x2<f16>
+@const conv mat3x2<T: f32>(mat3x2<f16>) -> mat3x2<f32>
+@const conv mat3x3<T: f16>(mat3x3<f32>) -> mat3x3<f16>
+@const conv mat3x3<T: f32>(mat3x3<f16>) -> mat3x3<f32>
+@const conv mat3x4<T: f16>(mat3x4<f32>) -> mat3x4<f16>
+@const conv mat3x4<T: f32>(mat3x4<f16>) -> mat3x4<f32>
+@const conv mat4x2<T: f16>(mat4x2<f32>) -> mat4x2<f16>
+@const conv mat4x2<T: f32>(mat4x2<f16>) -> mat4x2<f32>
+@const conv mat4x3<T: f16>(mat4x3<f32>) -> mat4x3<f16>
+@const conv mat4x3<T: f32>(mat4x3<f16>) -> mat4x3<f32>
+@const conv mat4x4<T: f16>(mat4x4<f32>) -> mat4x4<f16>
+@const conv mat4x4<T: f32>(mat4x4<f16>) -> mat4x4<f32>
////////////////////////////////////////////////////////////////////////////////
// Operators //
@@ -776,46 +877,46 @@ conv vec4<T: bool, U: scalar_no_bool>(vec4<U>) -> vec4<bool>
op ! (bool) -> bool
op ! <N: num> (vec<N, bool>) -> vec<N, bool>
-op ~ <T: iu32>(T) -> T
-op ~ <T: iu32, N: num> (vec<N, T>) -> vec<N, T>
+@const op ~ <T: ia_iu32>(T) -> T
+@const op ~ <T: ia_iu32, N: num> (vec<N, T>) -> vec<N, T>
-op - <T: fi32>(T) -> T
-op - <T: fi32, N: num> (vec<N, T>) -> vec<N, T>
+@const("UnaryMinus") op - <T: fia_fi32_f16>(T) -> T
+@const("UnaryMinus") op - <T: fia_fi32_f16, N: num> (vec<N, T>) -> vec<N, T>
////////////////////////////////////////////////////////////////////////////////
// Binary Operators //
////////////////////////////////////////////////////////////////////////////////
-op + <T: fiu32>(T, T) -> T
-op + <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-op + <T: fiu32, N: num> (vec<N, T>, T) -> vec<N, T>
-op + <T: fiu32, N: num> (T, vec<N, T>) -> vec<N, T>
-op + <N: num, M: num> (mat<N, M, f32>, mat<N, M, f32>) -> mat<N, M, f32>
-
-op - <T: fiu32>(T, T) -> T
-op - <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-op - <T: fiu32, N: num> (vec<N, T>, T) -> vec<N, T>
-op - <T: fiu32, N: num> (T, vec<N, T>) -> vec<N, T>
-op - <N: num, M: num> (mat<N, M, f32>, mat<N, M, f32>) -> mat<N, M, f32>
-
-op * <T: fiu32>(T, T) -> T
-op * <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-op * <T: fiu32, N: num> (vec<N, T>, T) -> vec<N, T>
-op * <T: fiu32, N: num> (T, vec<N, T>) -> vec<N, T>
-op * <N: num, M: num> (f32, mat<N, M, f32>) -> mat<N, M, f32>
-op * <N: num, M: num> (mat<N, M, f32>, f32) -> mat<N, M, f32>
-op * <C: num, R: num> (mat<C, R, f32>, vec<C, f32>) -> vec<R, f32>
-op * <C: num, R: num> (vec<R, f32>, mat<C, R, f32>) -> vec<C, f32>
-op * <K: num, C: num, R: num> (mat<K, R, f32>, mat<C, K, f32>) -> mat<C, R, f32>
-
-op / <T: fiu32>(T, T) -> T
-op / <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-op / <T: fiu32, N: num> (vec<N, T>, T) -> vec<N, T>
-op / <T: fiu32, N: num> (T, vec<N, T>) -> vec<N, T>
-
-op % <T: fiu32>(T, T) -> T
-op % <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-op % <T: fiu32, N: num> (vec<N, T>, T) -> vec<N, T>
-op % <T: fiu32, N: num> (T, vec<N, T>) -> vec<N, T>
+@const op + <T: fia_fiu32_f16>(T, T) -> T
+@const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@const op + <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@const op + <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
+
+@const op - <T: fia_fiu32_f16>(T, T) -> T
+@const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@const op - <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@const op - <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
+
+op * <T: fiu32_f16>(T, T) -> T
+op * <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+op * <T: fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+op * <T: fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+op * <T: f32_f16, N: num, M: num> (T, mat<N, M, T>) -> mat<N, M, T>
+op * <T: f32_f16, N: num, M: num> (mat<N, M, T>, T) -> mat<N, M, T>
+op * <T: f32_f16, C: num, R: num> (mat<C, R, T>, vec<C, T>) -> vec<R, T>
+op * <T: f32_f16, C: num, R: num> (vec<R, T>, mat<C, R, T>) -> vec<C, T>
+op * <T: f32_f16, K: num, C: num, R: num> (mat<K, R, T>, mat<C, K, T>) -> mat<C, R, T>
+
+op / <T: fiu32_f16>(T, T) -> T
+op / <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+op / <T: fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+op / <T: fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+
+op % <T: fiu32_f16>(T, T) -> T
+op % <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+op % <T: fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+op % <T: fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
op ^ <T: iu32>(T, T) -> T
op ^ <T: iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
@@ -839,17 +940,17 @@ op == <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
op != <T: scalar>(T, T) -> bool
op != <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
-op < <T: fiu32>(T, T) -> bool
-op < <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+op < <T: fiu32_f16>(T, T) -> bool
+op < <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
-op > <T: fiu32>(T, T) -> bool
-op > <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+op > <T: fiu32_f16>(T, T) -> bool
+op > <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
-op <= <T: fiu32>(T, T) -> bool
-op <= <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+op <= <T: fiu32_f16>(T, T) -> bool
+op <= <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
-op >= <T: fiu32>(T, T) -> bool
-op >= <T: fiu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+op >= <T: fiu32_f16>(T, T) -> bool
+op >= <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
op << <T: iu32>(T, u32) -> T
op << <T: iu32, N: num> (vec<N, T>, vec<N, u32>) -> vec<N, T>
diff --git a/chromium/third_party/dawn/src/tint/number.cc b/chromium/third_party/dawn/src/tint/number.cc
index 3ead5b041ca..91dbb45f830 100644
--- a/chromium/third_party/dawn/src/tint/number.cc
+++ b/chromium/third_party/dawn/src/tint/number.cc
@@ -15,9 +15,12 @@
#include "src/tint/number.h"
#include <algorithm>
+#include <cmath>
#include <cstring>
#include <ostream>
+#include "src/tint/debug.h"
+
namespace tint {
std::ostream& operator<<(std::ostream& out, ConversionFailure failure) {
@@ -31,27 +34,278 @@ std::ostream& operator<<(std::ostream& out, ConversionFailure failure) {
}
f16::type f16::Quantize(f16::type value) {
- if (value > kHighest) {
+ if (value > kHighestValue) {
return std::numeric_limits<f16::type>::infinity();
}
- if (value < kLowest) {
+ if (value < kLowestValue) {
return -std::numeric_limits<f16::type>::infinity();
}
// Below value must be within the finite range of a f16.
+ // Assert we use binary32 (i.e. float) as underlying type, which has 4 bytes.
+ static_assert(std::is_same<f16::type, float>());
+ const uint32_t sign_mask = 0x80000000u; // Mask for the sign bit
+ const uint32_t exponent_mask = 0x7f800000u; // Mask for 8 exponent bits
+
uint32_t u32;
memcpy(&u32, &value, 4);
- if ((u32 & 0x7fffffffu) == 0) { // ~sign
+
+ if ((u32 & ~sign_mask) == 0) {
return value; // +/- zero
}
- if ((u32 & 0x7f800000) == 0x7f800000) { // exponent all 1's
+ if ((u32 & exponent_mask) == exponent_mask) { // exponent all 1's
return value; // inf or nan
}
- // f32 bits : 1 sign, 8 exponent, 23 mantissa
- // f16 bits : 1 sign, 5 exponent, 10 mantissa
- // Mask the value to preserve the sign, exponent and most-significant 10 mantissa bits.
- u32 = u32 & 0xffffe000u;
+
+ // We are now going to quantize a f32 number into subnormal f16 and store the result value back
+ // into a f32 variable. Notice that all subnormal f16 values are just normal f32 values. Below
+ // will show that we can do this quantization by just masking out 13 or more lowest mantissa
+ // bits of the original f32 number.
+ //
+ // Note:
+ // f32 has 1 sign bit, 8 exponent bits for biased exponent (i.e. unbiased exponent + 127), and
+ // 23 mantissa bits. Binary form: s_eeeeeeee_mmmmmmmmmmmmmmmmmmmmmmm
+ // f16 has 1 sign bit, 5 exponent bits for biased exponent (i.e. unbiased exponent + 15), and
+ // 10 mantissa bits. Binary form: s_eeeee_mmmmmmmmmm
+ // The largest finite f16 number has a biased exponent of 11110 in binary, or 30 decimal, and so
+ // a unbiased exponent of 30 - 15 = 15.
+ // The smallest finite f16 number has a biased exponent of 00001 in binary, or 1 decimal, and so
+ // a unbiased exponent of 1 - 15 = -14.
+ //
+ // We may follow the argument below:
+ // 1. All normal or subnormal f16 values, range from 0x1.p-24 to 0x1.ffcp15, are exactly
+ // representable by normal f32 number.
+ // 1.1. We can denote the set of all f32 number that are exact representation of finite f16
+ // values by `R`.
+ // 1.2. We can do the quantization by mapping a normal f32 value v (in the f16 finite range)
+ // to a certain f32 number v' in the set R, which is the largest (by the meaning of absolute
+ // value) one among all values in R that are no larger than v.
+ // 2. We can decide whether a given normal f32 number v is in the set R, by looking at its
+ // mantissa bits and biased exponent `e`. Recall that biased exponent e is unbiased exponent +
+ // 127, and in the range of 1 to 254 for normal f32 number.
+ // 2.1. If e >= 143, i.e. abs(v) >= 2^16 > f16::kHighestValue = 0x1.ffcp15, v is larger than
+ // any finite f16 value and can not be in set R. 2.2. If 142 >= e >= 113, or
+ // f16::kHighestValue >= abs(v) >= f16::kSmallestValue = 2^-14, v falls in the range of normal
+ // f16 values. In this case, v is in the set R iff the lowest 13 mantissa bits are all 0. (See
+ // below for proof)
+ // 2.2.1. If we let v' be v with lowest 13 mantissa bits masked to 0, v' will be in set R
+ // and the largest one in set R that no larger than v. Such v' is the quantized value of v.
+ // 2.3. If 112 >= e >= 103, i.e. 2^-14 > abs(v) >= f16::kSmallestSubnormalValue = 2^-24, v
+ // falls in the range of subnormal f16 values. In this case, v is in the set R iff the lowest
+ // 126-e mantissa bits are all 0. Notice that 126-e is in range 14 to 23, inclusive. (See
+ // below for proof)
+ // 2.3.1. If we let v' be v with lowest 126-e mantissa bits masked to 0, v' will be in set R
+ // and the largest on in set R that no larger than v. Such v' is the quantized value of v.
+ // 2.4. If 2^-24 > abs(v) > 0, i.e. 103 > e, v is smaller than any finite f16 value and not
+ // equal to 0.0, thus can not be in set R.
+ // 2.5. If abs(v) = 0, v is in set R and is just +-0.0.
+ //
+ // Proof for 2.2:
+ // Any normal f16 number, in binary form, s_eeeee_mmmmmmmmmm, has value
+ // (s==0?1:-1)*(1+uint(mmmmm_mmmmm)*(2^-10))*2^(uint(eeeee)-15)
+ // in which unit(bbbbb) means interprete binary pattern "bbbbb" as unsigned binary number,
+ // and we have 1 <= uint(eeeee) <= 30.
+ // This value is equal to a normal f32 number with binary
+ // s_EEEEEEEE_mmmmmmmmmm0000000000000
+ // where uint(EEEEEEEE) = uint(eeeee) + 112, so that unbiased exponent keep unchanged
+ // uint(EEEEEEEE) - 127 = uint(eeeee) - 15
+ // and its value is
+ // (s==0?1:-1)*(1+uint(mmmmm_mmmmm_00000_00000_000)*(2^-23))*2^(uint(EEEEEEEE)-127)
+ // == (s==0?1:-1)*(1+uint(mmmmm_mmmmm)*(2^-10))*2^(uint(eeeee)-15)
+ // Notice that uint(EEEEEEEE) is in range [113, 142], showing that it is a normal f32 number.
+ // So we proof that any normal f16 number can be exactly representd by a normal f32 number
+ // with biased exponent in range [113,142] and the lowest 13 mantissa bits 0.
+ // On the other hand, since mantissa bits mmmmmmmmmm are arbitrary, the value of any f32
+ // that has a biased exponent in range [113, 142] and lowest 13 mantissa bits zero is equal
+ // to a normal f16 value. Hence we proof 2.2.
+ //
+ // Proof for 2.3:
+ // Any subnormal f16 number has a binary form of s_00000_mmmmmmmmmm, and its value is
+ // (s==0?1:-1)*uint(mmmmmmmmmm)*(2^-10)*(2^-14) = (s==0?1:-1)*uint(mmmmmmmmmm)*(2^-24).
+ // We discuss on bit pattern of mantissa bits mmmmmmmmmm.
+ // Case 1: mantissa bits has no leading zero bit, s_00000_1mmmmmmmmm
+ // In this case the value is
+ // (s==0?1:-1)*uint(1mmmm_mmmmm)*(2^-10)*(2^-14)
+ // == (s==0?1:-1)*(uint(1_mmmmm_mmmm)*(2^-9))*(2^-15)
+ // == (s==0?1:-1)*(1+uint(mmmmm_mmmm)*(2^-9))*(2^-15)
+ // == (s==0?1:-1)*(1+uint(mmmmm_mmmm0_00000_00000_000)*(2^-23))*(2^-15)
+ // which is equal to the value of normal f32 number
+ // s_EEEEEEEE_mmmmm_mmmm0_00000_00000_000
+ // where uint(EEEEEEEE) = -15 + 127 = 112. Hence we proof that any subnormal f16 number
+ // with no leading zero mantissa bit can be exactly represented by a f32 number with
+ // biased exponent 112 and the lowest 14 mantissa bits zero, and the value of any f32
+ // number with biased exponent 112 and the lowest 14 mantissa bits zero are equal to a
+ // subnormal f16 number with no leading zero mantissa bit.
+ // Case 2: mantissa bits has 1 leading zero bit, s_00000_01mmmmmmmm
+ // In this case the value is
+ // (s==0?1:-1)*uint(01mmm_mmmmm)*(2^-10)*(2^-14)
+ // == (s==0?1:-1)*(uint(01_mmmmm_mmm)*(2^-8))*(2^-16)
+ // == (s==0?1:-1)*(1+uint(mmmmm_mmm)*(2^-8))*(2^-16)
+ // == (s==0?1:-1)*(1+uint(mmmmm_mmm00_00000_00000_000)*(2^-23))*(2^-16)
+ // which is equal to the value of normal f32 number
+ // s_EEEEEEEE_mmmmm_mmm00_00000_00000_000
+ // where uint(EEEEEEEE) = -16 + 127 = 111. Hence we proof that any subnormal f16 number
+ // with 1 leading zero mantissa bit can be exactly represented by a f32 number with
+ // biased exponent 111 and the lowest 15 mantissa bits zero, and the value of any f32
+ // number with biased exponent 111 and the lowest 15 mantissa bits zero are equal to a
+ // subnormal f16 number with 1 leading zero mantissa bit.
+ // Case 3 to case 8: ......
+ // Case 9: mantissa bits has 8 leading zero bit, s_00000_000000001m
+ // In this case the value is
+ // (s==0?1:-1)*uint(00000_0001m)*(2^-10)*(2^-14)
+ // == (s==0?1:-1)*(uint(000000001_m)*(2^-1))*(2^-23)
+ // == (s==0?1:-1)*(1+uint(m)*(2^-1))*(2^-23)
+ // == (s==0?1:-1)*(1+uint(m0000_00000_00000_00000_000)*(2^-23))*(2^-23)
+ // which is equal to the value of normal f32 number
+ // s_EEEEEEEE_m0000_00000_00000_00000_000
+ // where uint(EEEEEEEE) = -23 + 127 = 104. Hence we proof that any subnormal f16 number
+ // with 8 leading zero mantissa bit can be exactly represented by a f32 number with
+ // biased exponent 104 and the lowest 22 mantissa bits zero, and the value of any f32
+ // number with biased exponent 104 and the lowest 22 mantissa bits zero are equal to a
+ // subnormal f16 number with 8 leading zero mantissa bit.
+ // Case 10: mantissa bits has 9 leading zero bit, s_00000_0000000001
+ // In this case the value is just +-2^-24 = +-0x1.0p-24,
+ // the f32 number has biased exponent 103 and all 23 mantissa bits zero.
+ // Case 11: mantissa bits has 10 leading zero bit, s_00000_0000000000, just 0.0
+ // Concluding all these case, we proof that any subnormal f16 number with N leading zero
+ // mantissa bit can be exactly represented by a f32 number with biased exponent 112-N and the
+ // lowest 14+N mantissa bits zero, and the value of any f32 number with biased exponent 112-N (=
+ // e) and the lowest 14+N (= 126-e) mantissa bits zero are equal to a subnormal f16 number with
+ // N leading zero mantissa bit. N is in range [0, 9], so the f32 number's biased exponent e is
+ // in range [103, 112], or unbiased exponent in [-24, -15].
+
+ float abs_value = std::fabs(value);
+ if (abs_value >= kSmallestValue) {
+ // Value falls in the normal f16 range, quantize it to a normal f16 value by masking out
+ // lowest 13 mantissa bits.
+ u32 = u32 & ~((1u << 13) - 1);
+ } else if (abs_value >= kSmallestSubnormalValue) {
+ // Value should be quantized to a subnormal f16 value.
+
+ // Get the biased exponent `e` of f32 value, e.g. value 127 representing exponent 2^0.
+ uint32_t biased_exponent_original = (u32 & exponent_mask) >> 23;
+ // Since we ensure that kSmallestValue = 0x1f-14 > abs(value) >= kSmallestSubnormalValue =
+ // 0x1f-24, value will have a unbiased exponent in range -24 to -15 (inclusive), and the
+ // corresponding biased exponent in f32 is in range 103 to 112 (inclusive).
+ TINT_ASSERT(Semantic,
+ (103 <= biased_exponent_original) && (biased_exponent_original <= 112));
+
+ // As we have proved, masking out the lowest 126-e mantissa bits of input value will result
+ // in a valid subnormal f16 value, which is exactly the required quantization result.
+ uint32_t discard_bits = 126 - biased_exponent_original; // In range 14 to 23 (inclusive)
+ TINT_ASSERT(Semantic, (14 <= discard_bits) && (discard_bits <= 23));
+ uint32_t discard_mask = (1u << discard_bits) - 1;
+ u32 = u32 & ~discard_mask;
+ } else {
+ // value is too small that it can't even be represented as subnormal f16 number. Quantize
+ // to zero.
+ return value > 0 ? 0.0 : -0.0;
+ }
memcpy(&value, &u32, 4);
return value;
}
+uint16_t f16::BitsRepresentation() const {
+ constexpr uint16_t f16_nan = 0x7e00u;
+ constexpr uint16_t f16_pos_inf = 0x7c00u;
+ constexpr uint16_t f16_neg_inf = 0xfc00u;
+
+ // Assert we use binary32 (i.e. float) as underlying type, which has 4 bytes.
+ static_assert(std::is_same<f16::type, float>());
+
+ // The stored value in f16 object must be already quantized, so it should be either NaN, +/-
+ // Inf, or exactly representable by normal or subnormal f16.
+
+ if (std::isnan(value)) {
+ return f16_nan;
+ }
+
+ if (std::isinf(value)) {
+ return value > 0 ? f16_pos_inf : f16_neg_inf;
+ }
+
+ // Now quantized_value must be a finite f16 exactly-representable value.
+ // The following table shows exponent cases for all finite f16 exactly-representable value.
+ // ---------------------------------------------------------------------------
+ // | Value category | Unbiased exp | F16 biased exp | F32 biased exp |
+ // |------------------|----------------|------------------|------------------|
+ // | +/- zero | \ | 0 | 0 |
+ // | Subnormal f16 | [-24, -15] | 0 | [103, 112] |
+ // | Normal f16 | [-14, 15] | [1, 30] | [113, 142] |
+ // ---------------------------------------------------------------------------
+
+ constexpr uint32_t max_f32_biased_exp_for_f16_normal_number = 142;
+ constexpr uint32_t min_f32_biased_exp_for_f16_normal_number = 113;
+ constexpr uint32_t max_f32_biased_exp_for_f16_subnormal_number = 112;
+ constexpr uint32_t min_f32_biased_exp_for_f16_subnormal_number = 103;
+
+ constexpr uint32_t f32_sign_mask = 0x80000000u;
+ constexpr uint32_t f32_exp_mask = 0x7f800000u;
+ constexpr uint32_t f32_mantissa_mask = 0x007fffffu;
+ constexpr uint32_t f32_mantissa_bis_number = 23;
+ constexpr uint32_t f32_exp_bias = 127;
+
+ constexpr uint16_t f16_sign_mask = 0x8000u;
+ constexpr uint16_t f16_exp_mask = 0x7c00u;
+ constexpr uint16_t f16_mantissa_mask = 0x03ffu;
+ constexpr uint32_t f16_mantissa_bis_number = 10;
+ constexpr uint32_t f16_exp_bias = 15;
+
+ uint32_t f32_bit_pattern;
+ memcpy(&f32_bit_pattern, &value, 4);
+ uint32_t f32_biased_exponent = (f32_bit_pattern & f32_exp_mask) >> f32_mantissa_bis_number;
+ uint32_t f32_mantissa = f32_bit_pattern & f32_mantissa_mask;
+
+ uint16_t f16_sign_part = static_cast<uint16_t>((f32_bit_pattern & f32_sign_mask) >> 16);
+ TINT_ASSERT(Semantic, (f16_sign_part & ~f16_sign_mask) == 0);
+
+ if ((f32_bit_pattern & ~f32_sign_mask) == 0) {
+ // +/- zero
+ return f16_sign_part;
+ }
+
+ if ((min_f32_biased_exp_for_f16_normal_number <= f32_biased_exponent) &&
+ (f32_biased_exponent <= max_f32_biased_exp_for_f16_normal_number)) {
+ // Normal f16
+ uint32_t f16_biased_exponent = f32_biased_exponent - f32_exp_bias + f16_exp_bias;
+ uint16_t f16_exp_part =
+ static_cast<uint16_t>(f16_biased_exponent << f16_mantissa_bis_number);
+ uint16_t f16_mantissa_part = static_cast<uint16_t>(
+ f32_mantissa >> (f32_mantissa_bis_number - f16_mantissa_bis_number));
+
+ TINT_ASSERT(Semantic, (f16_exp_part & ~f16_exp_mask) == 0);
+ TINT_ASSERT(Semantic, (f16_mantissa_part & ~f16_mantissa_mask) == 0);
+
+ return f16_sign_part | f16_exp_part | f16_mantissa_part;
+ }
+
+ if ((min_f32_biased_exp_for_f16_subnormal_number <= f32_biased_exponent) &&
+ (f32_biased_exponent <= max_f32_biased_exp_for_f16_subnormal_number)) {
+ // Subnormal f16
+ // The resulting exp bits are always 0, and the mantissa bits should be handled specially.
+ uint16_t f16_exp_part = 0;
+ // The resulting subnormal f16 will have only 1 valid mantissa bit if the unbiased exponent
+ // of value is of the minimum, i.e. -24; and have all 10 mantissa bits valid if the unbiased
+ // exponent of value is of the maximum, i.e. -15.
+ uint32_t f16_valid_mantissa_bits =
+ f32_biased_exponent - min_f32_biased_exp_for_f16_subnormal_number + 1;
+ // The resulting f16 mantissa part comes from right-shifting the f32 mantissa bits with
+ // leading 1 added.
+ uint16_t f16_mantissa_part =
+ static_cast<uint16_t>((f32_mantissa | (f32_mantissa_mask + 1)) >>
+ (f32_mantissa_bis_number + 1 - f16_valid_mantissa_bits));
+
+ TINT_ASSERT(Semantic, (1 <= f16_valid_mantissa_bits) &&
+ (f16_valid_mantissa_bits <= f16_mantissa_bis_number));
+ TINT_ASSERT(Semantic, (f16_mantissa_part & ~((1u << f16_valid_mantissa_bits) - 1)) == 0);
+ TINT_ASSERT(Semantic, (f16_mantissa_part != 0));
+
+ return f16_sign_part | f16_exp_part | f16_mantissa_part;
+ }
+
+ // Neither zero, subnormal f16 or normal f16, shall never hit.
+ tint::diag::List diag;
+ TINT_UNREACHABLE(Semantic, diag);
+ return f16_nan;
+}
+
} // namespace tint
diff --git a/chromium/third_party/dawn/src/tint/number.h b/chromium/third_party/dawn/src/tint/number.h
index b4c5ca41779..a36ccfbab01 100644
--- a/chromium/third_party/dawn/src/tint/number.h
+++ b/chromium/third_party/dawn/src/tint/number.h
@@ -16,11 +16,11 @@
#define SRC_TINT_NUMBER_H_
#include <stdint.h>
+#include <cmath>
#include <functional>
#include <limits>
+#include <optional>
#include <ostream>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <optional> // NOLINT(build/include_order))
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/result.h"
@@ -68,24 +68,49 @@ constexpr bool IsInteger = std::is_integral_v<T>;
template <typename T>
constexpr bool IsNumeric = IsInteger<T> || IsFloatingPoint<T>;
+/// Resolves to the underlying type for a Number.
+template <typename T>
+using UnwrapNumber = typename detail::NumberUnwrapper<T>::type;
+
+/// NumberBase is a CRTP base class for Number<T>
+template <typename NumberT>
+struct NumberBase {
+ /// @returns value of type `Number<T>` with the highest value for that type.
+ static NumberT Highest() { return NumberT(NumberT::kHighestValue); }
+ /// @returns value of type `Number<T>` with the lowest value for that type.
+ static NumberT Lowest() { return NumberT(NumberT::kLowestValue); }
+ /// @returns value of type `Number<T>` with the smallest value for that type.
+ static NumberT Smallest() { return NumberT(NumberT::kSmallestValue); }
+ /// @returns value of type `Number<T>` that represents NaN for that type.
+ static NumberT NaN() {
+ return NumberT(std::numeric_limits<UnwrapNumber<NumberT>>::quiet_NaN());
+ }
+ /// @returns value of type `Number<T>` that represents infinity for that type.
+ static NumberT Inf() { return NumberT(std::numeric_limits<UnwrapNumber<NumberT>>::infinity()); }
+};
+
/// Number wraps a integer or floating point number, enforcing explicit casting.
template <typename T>
-struct Number {
+struct Number : NumberBase<Number<T>> {
static_assert(IsNumeric<T>, "Number<T> constructed with non-numeric type");
/// type is the underlying type of the Number
using type = T;
/// Highest finite representable value of this type.
- static constexpr type kHighest = std::numeric_limits<type>::max();
+ static constexpr type kHighestValue = std::numeric_limits<type>::max();
/// Lowest finite representable value of this type.
- static constexpr type kLowest = std::numeric_limits<type>::lowest();
+ static constexpr type kLowestValue = std::numeric_limits<type>::lowest();
/// Smallest positive normal value of this type.
- static constexpr type kSmallest =
+ static constexpr type kSmallestValue =
std::is_integral_v<type> ? 0 : std::numeric_limits<type>::min();
+ /// Smallest positive subnormal value of this type, 0 for integral type.
+ static constexpr type kSmallestSubnormalValue =
+ std::is_integral_v<type> ? 0 : std::numeric_limits<type>::denorm_min();
+
/// Constructor. The value is zero-initialized.
Number() = default;
@@ -119,10 +144,6 @@ struct Number {
type value = {};
};
-/// Resolves to the underlying type for a Number.
-template <typename T>
-using UnwrapNumber = typename detail::NumberUnwrapper<T>::type;
-
/// Writes the number to the ostream.
/// @param out the std::ostream to write to
/// @param num the Number
@@ -132,76 +153,26 @@ inline std::ostream& operator<<(std::ostream& out, Number<T> num) {
return out << num.value;
}
-/// Equality operator.
-/// @param a the LHS number
-/// @param b the RHS number
-/// @returns true if the numbers `a` and `b` are exactly equal.
-template <typename A, typename B>
-bool operator==(Number<A> a, Number<B> b) {
- using T = decltype(a.value + b.value);
- return std::equal_to<T>()(static_cast<T>(a.value), static_cast<T>(b.value));
-}
-
-/// Inequality operator.
-/// @param a the LHS number
-/// @param b the RHS number
-/// @returns true if the numbers `a` and `b` are exactly unequal.
-template <typename A, typename B>
-bool operator!=(Number<A> a, Number<B> b) {
- return !(a == b);
-}
-
-/// Equality operator.
-/// @param a the LHS number
-/// @param b the RHS number
-/// @returns true if the numbers `a` and `b` are exactly equal.
-template <typename A, typename B>
-std::enable_if_t<IsNumeric<B>, bool> operator==(Number<A> a, B b) {
- return a == Number<B>(b);
-}
-
-/// Inequality operator.
-/// @param a the LHS number
-/// @param b the RHS number
-/// @returns true if the numbers `a` and `b` are exactly unequal.
-template <typename A, typename B>
-std::enable_if_t<IsNumeric<B>, bool> operator!=(Number<A> a, B b) {
- return !(a == b);
-}
-
-/// Equality operator.
-/// @param a the LHS number
-/// @param b the RHS number
-/// @returns true if the numbers `a` and `b` are exactly equal.
-template <typename A, typename B>
-std::enable_if_t<IsNumeric<A>, bool> operator==(A a, Number<B> b) {
- return Number<A>(a) == b;
-}
-
-/// Inequality operator.
-/// @param a the LHS number
-/// @param b the RHS number
-/// @returns true if the numbers `a` and `b` are exactly unequal.
-template <typename A, typename B>
-std::enable_if_t<IsNumeric<A>, bool> operator!=(A a, Number<B> b) {
- return !(a == b);
-}
-
/// The partial specification of Number for f16 type, storing the f16 value as float,
/// and enforcing proper explicit casting.
template <>
-struct Number<detail::NumberKindF16> {
+struct Number<detail::NumberKindF16> : NumberBase<Number<detail::NumberKindF16>> {
/// C++ does not have a native float16 type, so we use a 32-bit float instead.
using type = float;
/// Highest finite representable value of this type.
- static constexpr type kHighest = 65504.0f; // 2¹⁵ × (1 + 1023/1024)
+ static constexpr type kHighestValue = 65504.0f; // 2¹⁵ × (1 + 1023/1024)
/// Lowest finite representable value of this type.
- static constexpr type kLowest = -65504.0f;
+ static constexpr type kLowestValue = -65504.0f;
/// Smallest positive normal value of this type.
- static constexpr type kSmallest = 0.00006103515625f; // 2⁻¹⁴
+ /// binary16 0_00001_0000000000, value is 2⁻¹⁴.
+ static constexpr type kSmallestValue = 0x1p-14f;
+
+ /// Smallest positive subnormal value of this type.
+ /// binary16 0_00000_0000000001, value is 2⁻¹⁴ * 2⁻¹⁰ = 2⁻²⁴.
+ static constexpr type kSmallestSubnormalValue = 0x1p-24f;
/// Constructor. The value is zero-initialized.
Number() = default;
@@ -232,6 +203,13 @@ struct Number<detail::NumberKindF16> {
return *this;
}
+ /// Get the binary16 bit pattern in type uint16_t of this value.
+ /// @returns the binary16 bit pattern, in type uint16_t, of the stored quantized f16 value. If
+ /// the value is NaN, the returned value will be 0x7e00u. If the value is positive infinity, the
+ /// returned value will be 0x7c00u. If the input value is negative infinity, the returned value
+ /// will be 0xfc00u.
+ uint16_t BitsRepresentation() const;
+
/// @param value the input float32 value
/// @returns the float32 value quantized to the smaller float16 value, through truncation of the
/// mantissa bits (no rounding). If the float32 value is too large (positive or negative) to be
@@ -274,17 +252,83 @@ std::ostream& operator<<(std::ostream& out, ConversionFailure failure);
/// @returns the resulting value of the conversion, or a failure reason.
template <typename TO, typename FROM>
utils::Result<TO, ConversionFailure> CheckedConvert(Number<FROM> num) {
- using T = decltype(UnwrapNumber<TO>() + num.value);
+ // Use the highest-precision integer or floating-point type to perform the comparisons.
+ using T = std::conditional_t<IsFloatingPoint<UnwrapNumber<TO>> || IsFloatingPoint<FROM>,
+ AFloat::type, AInt::type>;
const auto value = static_cast<T>(num.value);
- if (value > static_cast<T>(TO::kHighest)) {
+ if (value > static_cast<T>(TO::kHighestValue)) {
return ConversionFailure::kExceedsPositiveLimit;
}
- if (value < static_cast<T>(TO::kLowest)) {
+ if (value < static_cast<T>(TO::kLowestValue)) {
return ConversionFailure::kExceedsNegativeLimit;
}
return TO(value); // Success
}
+/// Equality operator.
+/// @param a the LHS number
+/// @param b the RHS number
+/// @returns true if the numbers `a` and `b` are exactly equal. Also considers sign bit.
+template <typename A, typename B>
+bool operator==(Number<A> a, Number<B> b) {
+ // Use the highest-precision integer or floating-point type to perform the comparisons.
+ using T =
+ std::conditional_t<IsFloatingPoint<A> || IsFloatingPoint<B>, AFloat::type, AInt::type>;
+ auto va = static_cast<T>(a.value);
+ auto vb = static_cast<T>(b.value);
+ if constexpr (IsFloatingPoint<T>) {
+ if (std::signbit(va) != std::signbit(vb)) {
+ return false;
+ }
+ }
+ return std::equal_to<T>()(va, vb);
+}
+
+/// Inequality operator.
+/// @param a the LHS number
+/// @param b the RHS number
+/// @returns true if the numbers `a` and `b` are exactly unequal. Also considers sign bit.
+template <typename A, typename B>
+bool operator!=(Number<A> a, Number<B> b) {
+ return !(a == b);
+}
+
+/// Equality operator.
+/// @param a the LHS number
+/// @param b the RHS number
+/// @returns true if the numbers `a` and `b` are exactly equal.
+template <typename A, typename B>
+std::enable_if_t<IsNumeric<B>, bool> operator==(Number<A> a, B b) {
+ return a == Number<B>(b);
+}
+
+/// Inequality operator.
+/// @param a the LHS number
+/// @param b the RHS number
+/// @returns true if the numbers `a` and `b` are exactly unequal.
+template <typename A, typename B>
+std::enable_if_t<IsNumeric<B>, bool> operator!=(Number<A> a, B b) {
+ return !(a == b);
+}
+
+/// Equality operator.
+/// @param a the LHS number
+/// @param b the RHS number
+/// @returns true if the numbers `a` and `b` are exactly equal.
+template <typename A, typename B>
+std::enable_if_t<IsNumeric<A>, bool> operator==(A a, Number<B> b) {
+ return Number<A>(a) == b;
+}
+
+/// Inequality operator.
+/// @param a the LHS number
+/// @param b the RHS number
+/// @returns true if the numbers `a` and `b` are exactly unequal.
+template <typename A, typename B>
+std::enable_if_t<IsNumeric<A>, bool> operator!=(A a, Number<B> b) {
+ return !(a == b);
+}
+
/// Define 'TINT_HAS_OVERFLOW_BUILTINS' if the compiler provide overflow checking builtins.
/// If the compiler does not support these builtins, then these are emulated with algorithms
/// described in:
@@ -306,11 +350,11 @@ inline std::optional<AInt> CheckedAdd(AInt a, AInt b) {
}
#else // TINT_HAS_OVERFLOW_BUILTINS
if (a.value >= 0) {
- if (AInt::kHighest - a.value < b.value) {
+ if (b.value > AInt::kHighestValue - a.value) {
return {};
}
} else {
- if (b.value < AInt::kLowest - a.value) {
+ if (b.value < AInt::kLowestValue - a.value) {
return {};
}
}
@@ -319,6 +363,46 @@ inline std::optional<AInt> CheckedAdd(AInt a, AInt b) {
return AInt(result);
}
+/// @returns a + b, or an empty optional if the resulting value overflowed the AFloat
+inline std::optional<AFloat> CheckedAdd(AFloat a, AFloat b) {
+ auto result = a.value + b.value;
+ if (!std::isfinite(result)) {
+ return {};
+ }
+ return AFloat{result};
+}
+
+/// @returns a - b, or an empty optional if the resulting value overflowed the AInt
+inline std::optional<AInt> CheckedSub(AInt a, AInt b) {
+ int64_t result;
+#ifdef TINT_HAS_OVERFLOW_BUILTINS
+ if (__builtin_sub_overflow(a.value, b.value, &result)) {
+ return {};
+ }
+#else // TINT_HAS_OVERFLOW_BUILTINS
+ if (b.value >= 0) {
+ if (a.value < AInt::kLowestValue + b.value) {
+ return {};
+ }
+ } else {
+ if (a.value > AInt::kHighestValue + b.value) {
+ return {};
+ }
+ }
+ result = a.value - b.value;
+#endif // TINT_HAS_OVERFLOW_BUILTINS
+ return AInt(result);
+}
+
+/// @returns a + b, or an empty optional if the resulting value overflowed the AFloat
+inline std::optional<AFloat> CheckedSub(AFloat a, AFloat b) {
+ auto result = a.value - b.value;
+ if (!std::isfinite(result)) {
+ return {};
+ }
+ return AFloat{result};
+}
+
/// @returns a * b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedMul(AInt a, AInt b) {
int64_t result;
@@ -329,21 +413,21 @@ inline std::optional<AInt> CheckedMul(AInt a, AInt b) {
#else // TINT_HAS_OVERFLOW_BUILTINS
if (a > 0) {
if (b > 0) {
- if (a > (AInt::kHighest / b)) {
+ if (a > (AInt::kHighestValue / b)) {
return {};
}
} else {
- if (b < (AInt::kLowest / a)) {
+ if (b < (AInt::kLowestValue / a)) {
return {};
}
}
} else {
if (b > 0) {
- if (a < (AInt::kLowest / b)) {
+ if (a < (AInt::kLowestValue / b)) {
return {};
}
} else {
- if ((a != 0) && (b < (AInt::kHighest / a))) {
+ if ((a != 0) && (b < (AInt::kHighestValue / a))) {
return {};
}
}
diff --git a/chromium/third_party/dawn/src/tint/number_test.cc b/chromium/third_party/dawn/src/tint/number_test.cc
index 34b4d396243..3182ad353bf 100644
--- a/chromium/third_party/dawn/src/tint/number_test.cc
+++ b/chromium/third_party/dawn/src/tint/number_test.cc
@@ -26,38 +26,19 @@ using namespace tint::number_suffixes; // NOLINT
namespace tint {
namespace {
-constexpr int64_t kHighestI32 = static_cast<int64_t>(std::numeric_limits<int32_t>::max());
-constexpr int64_t kHighestU32 = static_cast<int64_t>(std::numeric_limits<uint32_t>::max());
-constexpr int64_t kLowestI32 = static_cast<int64_t>(std::numeric_limits<int32_t>::min());
-constexpr int64_t kLowestU32 = static_cast<int64_t>(std::numeric_limits<uint32_t>::min());
-
-// Highest float32 value.
-constexpr double kHighestF32 = 0x1.fffffep+127;
-
// Next ULP up from kHighestF32 for a float64.
constexpr double kHighestF32NextULP = 0x1.fffffe0000001p+127;
-// Smallest positive normal float32 value.
-constexpr double kSmallestF32 = 0x1p-126;
-
// Highest subnormal value for a float32.
constexpr double kHighestF32Subnormal = 0x0.fffffep-126;
-// Highest float16 value.
-constexpr double kHighestF16 = 0x1.ffcp+15;
-
// Next ULP up from kHighestF16 for a float64.
constexpr double kHighestF16NextULP = 0x1.ffc0000000001p+15;
-// Smallest positive normal float16 value.
-constexpr double kSmallestF16 = 0x1p-14;
-
-// Highest subnormal value for a float32.
+// Highest subnormal value for a float16.
constexpr double kHighestF16Subnormal = 0x0.ffcp-14;
-constexpr double kLowestF32 = -kHighestF32;
constexpr double kLowestF32NextULP = -kHighestF32NextULP;
-constexpr double kLowestF16 = -kHighestF16;
constexpr double kLowestF16NextULP = -kHighestF16NextULP;
// MSVC (only in release builds) can grumble about some of the inlined numerical overflow /
@@ -65,6 +46,79 @@ constexpr double kLowestF16NextULP = -kHighestF16NextULP;
// warning.
TINT_BEGIN_DISABLE_WARNING(CONSTANT_OVERFLOW);
+TEST(NumberTest, Equality) {
+ EXPECT_TRUE(0_a == 0_a);
+ EXPECT_TRUE(10_a == 10_a);
+ EXPECT_TRUE(-10_a == -10_a);
+
+ EXPECT_TRUE(0_i == 0_i);
+ EXPECT_TRUE(10_i == 10_i);
+ EXPECT_TRUE(-10_i == -10_i);
+
+ EXPECT_TRUE(0_u == 0_u);
+ EXPECT_TRUE(10_u == 10_u);
+
+ EXPECT_TRUE(0._a == 0._a);
+ EXPECT_TRUE(-0._a == -0._a);
+ EXPECT_TRUE(10._a == 10._a);
+ EXPECT_TRUE(-10._a == -10._a);
+
+ EXPECT_TRUE(0_f == 0_f);
+ EXPECT_TRUE(-0_f == -0_f);
+ EXPECT_TRUE(10_f == 10_f);
+ EXPECT_TRUE(-10_f == -10_f);
+
+ EXPECT_TRUE(0_h == 0_h);
+ EXPECT_TRUE(-0_h == -0_h);
+ EXPECT_TRUE(10_h == 10_h);
+ EXPECT_TRUE(-10_h == -10_h);
+}
+
+TEST(NumberTest, Inequality) {
+ EXPECT_TRUE(0_a != 1_a);
+ EXPECT_TRUE(10_a != 11_a);
+ EXPECT_TRUE(11_a != 10_a);
+ EXPECT_TRUE(-10_a != -11_a);
+ EXPECT_TRUE(-11_a != -10_a);
+
+ EXPECT_TRUE(0_i != 1_i);
+ EXPECT_TRUE(1_i != 0_i);
+ EXPECT_TRUE(10_i != 11_i);
+ EXPECT_TRUE(11_i != 10_i);
+ EXPECT_TRUE(-10_i != -11_i);
+ EXPECT_TRUE(-11_i != -10_i);
+
+ EXPECT_TRUE(0_u != 1_u);
+ EXPECT_TRUE(1_u != 0_u);
+ EXPECT_TRUE(10_u != 11_u);
+ EXPECT_TRUE(11_u != 10_u);
+
+ EXPECT_TRUE(0._a != -0._a);
+ EXPECT_TRUE(-0._a != 0._a);
+ EXPECT_TRUE(10._a != 11._a);
+ EXPECT_TRUE(11._a != 10._a);
+ EXPECT_TRUE(-10._a != -11._a);
+ EXPECT_TRUE(-11._a != -10._a);
+
+ EXPECT_TRUE(0_f != -0_f);
+ EXPECT_TRUE(-0_f != 0_f);
+ EXPECT_TRUE(-0_f != -1_f);
+ EXPECT_TRUE(-1_f != -0_f);
+ EXPECT_TRUE(10_f != -10_f);
+ EXPECT_TRUE(-10_f != 10_f);
+ EXPECT_TRUE(10_f != 11_f);
+ EXPECT_TRUE(-10_f != -11_f);
+
+ EXPECT_TRUE(0_h != -0_h);
+ EXPECT_TRUE(-0_h != 0_h);
+ EXPECT_TRUE(-0_h != -1_h);
+ EXPECT_TRUE(-1_h != -0_h);
+ EXPECT_TRUE(10_h != -10_h);
+ EXPECT_TRUE(-10_h != 10_h);
+ EXPECT_TRUE(10_h != 11_h);
+ EXPECT_TRUE(-10_h != -11_h);
+}
+
TEST(NumberTest, CheckedConvertIdentity) {
EXPECT_EQ(CheckedConvert<AInt>(0_a), 0_a);
EXPECT_EQ(CheckedConvert<AFloat>(0_a), 0.0_a);
@@ -82,29 +136,38 @@ TEST(NumberTest, CheckedConvertIdentity) {
}
TEST(NumberTest, CheckedConvertLargestValue) {
- EXPECT_EQ(CheckedConvert<i32>(AInt(kHighestI32)), i32(kHighestI32));
- EXPECT_EQ(CheckedConvert<u32>(AInt(kHighestU32)), u32(kHighestU32));
- EXPECT_EQ(CheckedConvert<f32>(AFloat(kHighestF32)), f32(kHighestF32));
- EXPECT_EQ(CheckedConvert<f16>(AFloat(kHighestF16)), f16(kHighestF16));
+ EXPECT_EQ(CheckedConvert<i32>(AInt(i32::Highest())), i32::Highest());
+ EXPECT_EQ(CheckedConvert<u32>(AInt(u32::Highest())), u32::Highest());
+ EXPECT_EQ(CheckedConvert<u32>(i32::Highest()), u32(i32::Highest()));
+ EXPECT_EQ(CheckedConvert<f32>(AFloat(f32::Highest())), f32::Highest());
+ EXPECT_EQ(CheckedConvert<f16>(AFloat(f16::Highest())), f16::Highest());
}
TEST(NumberTest, CheckedConvertLowestValue) {
- EXPECT_EQ(CheckedConvert<i32>(AInt(kLowestI32)), i32(kLowestI32));
- EXPECT_EQ(CheckedConvert<u32>(AInt(kLowestU32)), u32(kLowestU32));
- EXPECT_EQ(CheckedConvert<f32>(AFloat(kLowestF32)), f32(kLowestF32));
- EXPECT_EQ(CheckedConvert<f16>(AFloat(kLowestF16)), f16(kLowestF16));
+ EXPECT_EQ(CheckedConvert<i32>(AInt(i32::Lowest())), i32::Lowest());
+ EXPECT_EQ(CheckedConvert<u32>(AInt(u32::Lowest())), u32::Lowest());
+ EXPECT_EQ(CheckedConvert<f32>(AFloat(f32::Lowest())), f32::Lowest());
+ EXPECT_EQ(CheckedConvert<f16>(AFloat(f16::Lowest())), f16::Lowest());
}
TEST(NumberTest, CheckedConvertSmallestValue) {
EXPECT_EQ(CheckedConvert<i32>(AInt(0)), i32(0));
EXPECT_EQ(CheckedConvert<u32>(AInt(0)), u32(0));
- EXPECT_EQ(CheckedConvert<f32>(AFloat(kSmallestF32)), f32(kSmallestF32));
- EXPECT_EQ(CheckedConvert<f16>(AFloat(kSmallestF16)), f16(kSmallestF16));
+ EXPECT_EQ(CheckedConvert<f32>(AFloat(f32::Smallest())), f32::Smallest());
+ EXPECT_EQ(CheckedConvert<f16>(AFloat(f16::Smallest())), f16::Smallest());
}
TEST(NumberTest, CheckedConvertExceedsPositiveLimit) {
- EXPECT_EQ(CheckedConvert<i32>(AInt(kHighestI32 + 1)), ConversionFailure::kExceedsPositiveLimit);
- EXPECT_EQ(CheckedConvert<u32>(AInt(kHighestU32 + 1)), ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<i32>(AInt(static_cast<int64_t>(i32::Highest()) + 1)),
+ ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<u32>(AInt(static_cast<uint64_t>(u32::Highest()) + 1)),
+ ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<i32>(u32::Highest()), ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<i32>(u32(0x80000000)), ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<u32>(f32::Highest()), ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<i32>(f32::Highest()), ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<u32>(AFloat::Highest()), ConversionFailure::kExceedsPositiveLimit);
+ EXPECT_EQ(CheckedConvert<i32>(AFloat::Highest()), ConversionFailure::kExceedsPositiveLimit);
EXPECT_EQ(CheckedConvert<f32>(AFloat(kHighestF32NextULP)),
ConversionFailure::kExceedsPositiveLimit);
EXPECT_EQ(CheckedConvert<f16>(AFloat(kHighestF16NextULP)),
@@ -112,8 +175,16 @@ TEST(NumberTest, CheckedConvertExceedsPositiveLimit) {
}
TEST(NumberTest, CheckedConvertExceedsNegativeLimit) {
- EXPECT_EQ(CheckedConvert<i32>(AInt(kLowestI32 - 1)), ConversionFailure::kExceedsNegativeLimit);
- EXPECT_EQ(CheckedConvert<u32>(AInt(kLowestU32 - 1)), ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<i32>(AInt(static_cast<int64_t>(i32::Lowest()) - 1)),
+ ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<u32>(AInt(static_cast<uint64_t>(u32::Lowest()) - 1)),
+ ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<u32>(i32(-1)), ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<u32>(i32::Lowest()), ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<u32>(f32::Lowest()), ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<i32>(f32::Lowest()), ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<u32>(AFloat::Lowest()), ConversionFailure::kExceedsNegativeLimit);
+ EXPECT_EQ(CheckedConvert<i32>(AFloat::Lowest()), ConversionFailure::kExceedsNegativeLimit);
EXPECT_EQ(CheckedConvert<f32>(AFloat(kLowestF32NextULP)),
ConversionFailure::kExceedsNegativeLimit);
EXPECT_EQ(CheckedConvert<f16>(AFloat(kLowestF16NextULP)),
@@ -127,40 +198,185 @@ TEST(NumberTest, CheckedConvertSubnormals) {
EXPECT_EQ(CheckedConvert<f16>(AFloat(-kHighestF16Subnormal)), f16(-kHighestF16Subnormal));
}
-TEST(NumberTest, QuantizeF16) {
- constexpr float nan = std::numeric_limits<float>::quiet_NaN();
- constexpr float inf = std::numeric_limits<float>::infinity();
-
- EXPECT_EQ(f16(0.0), 0.0f);
- EXPECT_EQ(f16(1.0), 1.0f);
- EXPECT_EQ(f16(0.00006106496), 0.000061035156f);
- EXPECT_EQ(f16(1.0004883), 1.0f);
- EXPECT_EQ(f16(-8196), -8192.f);
- EXPECT_EQ(f16(65504.003), inf);
- EXPECT_EQ(f16(-65504.003), -inf);
- EXPECT_EQ(f16(inf), inf);
- EXPECT_EQ(f16(-inf), -inf);
- EXPECT_TRUE(std::isnan(f16(nan)));
+// Test cases for f16 subnormal quantization and BitsRepresentation.
+// The ULP is based on float rather than double or f16, since F16::Quantize and
+// F16::BitsRepresentation take float as input.
+constexpr float lowestPositiveNormalF16 = 0x1p-14;
+constexpr float lowestPositiveNormalF16PlusULP = 0x1.000002p-14;
+constexpr float lowestPositiveNormalF16MinusULP = 0x1.fffffep-15;
+constexpr float highestPositiveSubnormalF16 = 0x0.ffcp-14;
+constexpr float highestPositiveSubnormalF16PlusULP = 0x1.ff8002p-15;
+constexpr float highestPositiveSubnormalF16MinusULP = 0x1.ff7ffep-15;
+constexpr float lowestPositiveSubnormalF16 = 0x1.p-24;
+constexpr float lowestPositiveSubnormalF16PlusULP = 0x1.000002p-24;
+constexpr float lowestPositiveSubnormalF16MinusULP = 0x1.fffffep-25;
+
+constexpr uint16_t lowestPositiveNormalF16Bits = 0x0400u;
+constexpr uint16_t highestPositiveSubnormalF16Bits = 0x03ffu;
+constexpr uint16_t lowestPositiveSubnormalF16Bits = 0x0001u;
+
+constexpr float highestNegativeNormalF16 = -lowestPositiveNormalF16;
+constexpr float highestNegativeNormalF16PlusULP = -lowestPositiveNormalF16MinusULP;
+constexpr float highestNegativeNormalF16MinusULP = -lowestPositiveNormalF16PlusULP;
+constexpr float lowestNegativeSubnormalF16 = -highestPositiveSubnormalF16;
+constexpr float lowestNegativeSubnormalF16PlusULP = -highestPositiveSubnormalF16MinusULP;
+constexpr float lowestNegativeSubnormalF16MinusULP = -highestPositiveSubnormalF16PlusULP;
+constexpr float highestNegativeSubnormalF16 = -lowestPositiveSubnormalF16;
+constexpr float highestNegativeSubnormalF16PlusULP = -lowestPositiveSubnormalF16MinusULP;
+constexpr float highestNegativeSubnormalF16MinusULP = -lowestPositiveSubnormalF16PlusULP;
+
+constexpr uint16_t highestNegativeNormalF16Bits = 0x8400u;
+constexpr uint16_t lowestNegativeSubnormalF16Bits = 0x83ffu;
+constexpr uint16_t highestNegativeSubnormalF16Bits = 0x8001u;
+
+constexpr float f32_nan = std::numeric_limits<float>::quiet_NaN();
+constexpr float f32_inf = std::numeric_limits<float>::infinity();
+
+struct F16TestCase {
+ float input_value;
+ float quantized_value;
+ uint16_t f16_bit_pattern;
+};
+
+using NumberF16Test = testing::TestWithParam<F16TestCase>;
+
+TEST_P(NumberF16Test, QuantizeF16) {
+ float input_value = GetParam().input_value;
+ float quantized_value = GetParam().quantized_value;
+
+ std::stringstream ss;
+ ss << "input value = " << input_value << ", expected quantized value = " << quantized_value;
+ SCOPED_TRACE(ss.str());
+
+ if (std::isnan(quantized_value)) {
+ EXPECT_TRUE(std::isnan(f16(input_value)));
+ } else {
+ EXPECT_EQ(f16(input_value), quantized_value);
+ }
}
-using BinaryCheckedCase = std::tuple<std::optional<AInt>, AInt, AInt>;
+TEST_P(NumberF16Test, BitsRepresentation) {
+ float input_value = GetParam().input_value;
+ uint16_t representation = GetParam().f16_bit_pattern;
+
+ std::stringstream ss;
+ ss << "input value = " << input_value
+ << ", expected binary16 bits representation = " << std::hex << std::showbase
+ << representation;
+ SCOPED_TRACE(ss.str());
+ EXPECT_EQ(f16(input_value).BitsRepresentation(), representation);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ NumberF16Test,
+ NumberF16Test,
+ testing::ValuesIn(std::vector<F16TestCase>{
+ // NaN, Inf
+ {f32_inf, f32_inf, 0x7c00u},
+ {-f32_inf, -f32_inf, 0xfc00u},
+ {f32_nan, f32_nan, 0x7e00u},
+ {-f32_nan, -f32_nan, 0x7e00u},
+ // +/- zero
+ {+0.0f, 0.0f, 0x0000u},
+ {-0.0f, -0.0f, 0x8000u},
+ // Value in normal f16 range
+ {1.0f, 1.0f, 0x3c00u},
+ {-1.0f, -1.0f, 0xbc00u},
+ // 0.00006106496 quantized to 0.000061035156 = 0x1p-14
+ {0.00006106496f, 0.000061035156f, 0x0400u},
+ {-0.00006106496f, -0.000061035156f, 0x8400u},
+ // 1.0004883 quantized to 1.0 = 0x1p0
+ {1.0004883f, 1.0f, 0x3c00u},
+ {-1.0004883f, -1.0f, 0xbc00u},
+ // 8196.0 quantized to 8192.0 = 0x1p13
+ {8196.0f, 8192.f, 0x7000u},
+ {-8196.0f, -8192.f, 0xf000u},
+ // Value in subnormal f16 range
+ {0x0.034p-14f, 0x0.034p-14f, 0x000du},
+ {-0x0.034p-14f, -0x0.034p-14f, 0x800du},
+ {0x0.068p-14f, 0x0.068p-14f, 0x001au},
+ {-0x0.068p-14f, -0x0.068p-14f, 0x801au},
+ // 0x0.06b7p-14 quantized to 0x0.068p-14
+ {0x0.06b7p-14f, 0x0.068p-14f, 0x001au},
+ {-0x0.06b7p-14f, -0x0.068p-14, 0x801au},
+ // Value out of f16 range
+ {65504.003f, f32_inf, 0x7c00u},
+ {-65504.003f, -f32_inf, 0xfc00u},
+ {0x1.234p56f, f32_inf, 0x7c00u},
+ {-0x4.321p65f, -f32_inf, 0xfc00u},
+
+ // Test for subnormal quantization.
+ // Value larger than or equal to lowest positive normal f16 will be quantized to normal f16.
+ {lowestPositiveNormalF16PlusULP, lowestPositiveNormalF16, lowestPositiveNormalF16Bits},
+ {lowestPositiveNormalF16, lowestPositiveNormalF16, lowestPositiveNormalF16Bits},
+ // Positive value smaller than lowest positive normal f16 but not smaller than lowest
+ // positive
+ // subnormal f16 will be quantized to subnormal f16 or zero.
+ {lowestPositiveNormalF16MinusULP, highestPositiveSubnormalF16,
+ highestPositiveSubnormalF16Bits},
+ {highestPositiveSubnormalF16PlusULP, highestPositiveSubnormalF16,
+ highestPositiveSubnormalF16Bits},
+ {highestPositiveSubnormalF16, highestPositiveSubnormalF16, highestPositiveSubnormalF16Bits},
+ {highestPositiveSubnormalF16MinusULP, 0x0.ff8p-14, 0x03feu},
+ {lowestPositiveSubnormalF16PlusULP, lowestPositiveSubnormalF16,
+ lowestPositiveSubnormalF16Bits},
+ {lowestPositiveSubnormalF16, lowestPositiveSubnormalF16, lowestPositiveSubnormalF16Bits},
+ // Positive value smaller than lowest positive subnormal f16 will be quantized to zero.
+ {lowestPositiveSubnormalF16MinusULP, 0.0, 0x0000u},
+ // Test the mantissa discarding, the least significant mantissa bit is 0x1p-24 =
+ // 0x0.004p-14.
+ {0x0.064p-14f, 0x0.064p-14, 0x0019u},
+ {0x0.067fecp-14f, 0x0.064p-14, 0x0019u},
+ {0x0.063ffep-14f, 0x0.060p-14, 0x0018u},
+ {0x0.008p-14f, 0x0.008p-14, 0x0002u},
+ {0x0.00bffep-14f, 0x0.008p-14, 0x0002u},
+ {0x0.007ffep-14f, 0x0.004p-14, 0x0001u},
+
+ // Vice versa for negative cases.
+ {highestNegativeNormalF16MinusULP, highestNegativeNormalF16, highestNegativeNormalF16Bits},
+ {highestNegativeNormalF16, highestNegativeNormalF16, highestNegativeNormalF16Bits},
+ {highestNegativeNormalF16PlusULP, lowestNegativeSubnormalF16,
+ lowestNegativeSubnormalF16Bits},
+ {lowestNegativeSubnormalF16MinusULP, lowestNegativeSubnormalF16,
+ lowestNegativeSubnormalF16Bits},
+ {lowestNegativeSubnormalF16, lowestNegativeSubnormalF16, lowestNegativeSubnormalF16Bits},
+ {lowestNegativeSubnormalF16PlusULP, -0x0.ff8p-14, 0x83feu},
+ {highestNegativeSubnormalF16MinusULP, highestNegativeSubnormalF16,
+ highestNegativeSubnormalF16Bits},
+ {highestNegativeSubnormalF16, highestNegativeSubnormalF16, highestNegativeSubnormalF16Bits},
+ {highestNegativeSubnormalF16PlusULP, -0.0, 0x8000u},
+ // Test the mantissa discarding.
+ {-0x0.064p-14f, -0x0.064p-14, 0x8019u},
+ {-0x0.067fecp-14f, -0x0.064p-14, 0x8019u},
+ {-0x0.063ffep-14f, -0x0.060p-14, 0x8018u},
+ {-0x0.008p-14f, -0x0.008p-14, 0x8002u},
+ {-0x0.00bffep-14f, -0x0.008p-14, 0x8002u},
+ {-0x0.007ffep-14f, -0x0.004p-14, 0x8001u},
+ /////////////////////////////////////
+ }));
+
+#ifdef OVERFLOW
#undef OVERFLOW // corecrt_math.h :(
+#endif
#define OVERFLOW \
{}
-using CheckedAddTest = testing::TestWithParam<BinaryCheckedCase>;
-TEST_P(CheckedAddTest, Test) {
+using BinaryCheckedCase_AInt = std::tuple<std::optional<AInt>, AInt, AInt>;
+using BinaryCheckedCase_AFloat = std::tuple<std::optional<AFloat>, AFloat, AFloat>;
+
+using CheckedAddTest_AInt = testing::TestWithParam<BinaryCheckedCase_AInt>;
+TEST_P(CheckedAddTest_AInt, Test) {
auto expect = std::get<0>(GetParam());
auto a = std::get<1>(GetParam());
auto b = std::get<2>(GetParam());
- EXPECT_EQ(CheckedAdd(a, b), expect) << std::hex << "0x" << a << " * 0x" << b;
- EXPECT_EQ(CheckedAdd(b, a), expect) << std::hex << "0x" << a << " * 0x" << b;
+ EXPECT_EQ(CheckedAdd(a, b), expect) << std::hex << "0x" << a << " + 0x" << b;
+ EXPECT_EQ(CheckedAdd(b, a), expect) << std::hex << "0x" << a << " + 0x" << b;
}
INSTANTIATE_TEST_SUITE_P(
- CheckedAddTest,
- CheckedAddTest,
- testing::ValuesIn(std::vector<BinaryCheckedCase>{
+ CheckedAddTest_AInt,
+ CheckedAddTest_AInt,
+ testing::ValuesIn(std::vector<BinaryCheckedCase_AInt>{
{AInt(0), AInt(0), AInt(0)},
{AInt(1), AInt(1), AInt(0)},
{AInt(2), AInt(1), AInt(1)},
@@ -169,24 +385,114 @@ INSTANTIATE_TEST_SUITE_P(
{AInt(-1), AInt(-2), AInt(1)},
{AInt(0x300), AInt(0x100), AInt(0x200)},
{AInt(0x100), AInt(-0x100), AInt(0x200)},
- {AInt(AInt::kHighest), AInt(1), AInt(AInt::kHighest - 1)},
- {AInt(AInt::kLowest), AInt(-1), AInt(AInt::kLowest + 1)},
- {AInt(AInt::kHighest), AInt(0x7fffffff00000000ll), AInt(0x00000000ffffffffll)},
- {AInt(AInt::kHighest), AInt(AInt::kHighest), AInt(0)},
- {AInt(AInt::kLowest), AInt(AInt::kLowest), AInt(0)},
- {OVERFLOW, AInt(1), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(-1), AInt(AInt::kLowest)},
- {OVERFLOW, AInt(2), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(-2), AInt(AInt::kLowest)},
- {OVERFLOW, AInt(10000), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(-10000), AInt(AInt::kLowest)},
- {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(AInt::kLowest), AInt(AInt::kLowest)},
+ {AInt::Highest(), AInt(1), AInt(AInt::kHighestValue - 1)},
+ {AInt::Lowest(), AInt(-1), AInt(AInt::kLowestValue + 1)},
+ {AInt::Highest(), AInt(0x7fffffff00000000ll), AInt(0x00000000ffffffffll)},
+ {AInt::Highest(), AInt::Highest(), AInt(0)},
+ {AInt::Lowest(), AInt::Lowest(), AInt(0)},
+ {OVERFLOW, AInt(1), AInt::Highest()},
+ {OVERFLOW, AInt(-1), AInt::Lowest()},
+ {OVERFLOW, AInt(2), AInt::Highest()},
+ {OVERFLOW, AInt(-2), AInt::Lowest()},
+ {OVERFLOW, AInt(10000), AInt::Highest()},
+ {OVERFLOW, AInt(-10000), AInt::Lowest()},
+ {OVERFLOW, AInt::Highest(), AInt::Highest()},
+ {OVERFLOW, AInt::Lowest(), AInt::Lowest()},
+ ////////////////////////////////////////////////////////////////////////
+ }));
+
+using CheckedAddTest_AFloat = testing::TestWithParam<BinaryCheckedCase_AFloat>;
+TEST_P(CheckedAddTest_AFloat, Test) {
+ auto expect = std::get<0>(GetParam());
+ auto a = std::get<1>(GetParam());
+ auto b = std::get<2>(GetParam());
+ EXPECT_EQ(CheckedAdd(a, b), expect) << std::hex << "0x" << a << " + 0x" << b;
+ EXPECT_EQ(CheckedAdd(b, a), expect) << std::hex << "0x" << a << " + 0x" << b;
+}
+INSTANTIATE_TEST_SUITE_P(
+ CheckedAddTest_AFloat,
+ CheckedAddTest_AFloat,
+ testing::ValuesIn(std::vector<BinaryCheckedCase_AFloat>{
+ {AFloat(0), AFloat(0), AFloat(0)},
+ {AFloat(1), AFloat(1), AFloat(0)},
+ {AFloat(2), AFloat(1), AFloat(1)},
+ {AFloat(0), AFloat(-1), AFloat(1)},
+ {AFloat(3), AFloat(2), AFloat(1)},
+ {AFloat(-1), AFloat(-2), AFloat(1)},
+ {AFloat(0x300), AFloat(0x100), AFloat(0x200)},
+ {AFloat(0x100), AFloat(-0x100), AFloat(0x200)},
+ {AFloat::Highest(), AFloat(1), AFloat(AFloat::kHighestValue - 1)},
+ {AFloat::Lowest(), AFloat(-1), AFloat(AFloat::kLowestValue + 1)},
+ {AFloat::Highest(), AFloat::Highest(), AFloat(0)},
+ {AFloat::Lowest(), AFloat::Lowest(), AFloat(0)},
+ {OVERFLOW, AFloat::Highest(), AFloat::Highest()},
+ {OVERFLOW, AFloat::Lowest(), AFloat::Lowest()},
+ ////////////////////////////////////////////////////////////////////////
+ }));
+
+using CheckedSubTest_AInt = testing::TestWithParam<BinaryCheckedCase_AInt>;
+TEST_P(CheckedSubTest_AInt, Test) {
+ auto expect = std::get<0>(GetParam());
+ auto a = std::get<1>(GetParam());
+ auto b = std::get<2>(GetParam());
+ EXPECT_EQ(CheckedSub(a, b), expect) << std::hex << "0x" << a << " - 0x" << b;
+}
+INSTANTIATE_TEST_SUITE_P(
+ CheckedSubTest_AInt,
+ CheckedSubTest_AInt,
+ testing::ValuesIn(std::vector<BinaryCheckedCase_AInt>{
+ {AInt(0), AInt(0), AInt(0)},
+ {AInt(1), AInt(1), AInt(0)},
+ {AInt(0), AInt(1), AInt(1)},
+ {AInt(-2), AInt(-1), AInt(1)},
+ {AInt(1), AInt(2), AInt(1)},
+ {AInt(-3), AInt(-2), AInt(1)},
+ {AInt(0x100), AInt(0x300), AInt(0x200)},
+ {AInt(-0x300), AInt(-0x100), AInt(0x200)},
+ {AInt::Highest(), AInt(AInt::kHighestValue - 1), AInt(-1)},
+ {AInt::Lowest(), AInt(AInt::kLowestValue + 1), AInt(1)},
+ {AInt(0x00000000ffffffffll), AInt::Highest(), AInt(0x7fffffff00000000ll)},
+ {AInt::Highest(), AInt::Highest(), AInt(0)},
+ {AInt::Lowest(), AInt::Lowest(), AInt(0)},
+ {OVERFLOW, AInt::Lowest(), AInt(1)},
+ {OVERFLOW, AInt::Highest(), AInt(-1)},
+ {OVERFLOW, AInt::Lowest(), AInt(2)},
+ {OVERFLOW, AInt::Highest(), AInt(-2)},
+ {OVERFLOW, AInt::Lowest(), AInt(10000)},
+ {OVERFLOW, AInt::Highest(), AInt(-10000)},
+ {OVERFLOW, AInt::Lowest(), AInt::Highest()},
+ ////////////////////////////////////////////////////////////////////////
+ }));
+
+using CheckedSubTest_AFloat = testing::TestWithParam<BinaryCheckedCase_AFloat>;
+TEST_P(CheckedSubTest_AFloat, Test) {
+ auto expect = std::get<0>(GetParam());
+ auto a = std::get<1>(GetParam());
+ auto b = std::get<2>(GetParam());
+ EXPECT_EQ(CheckedSub(a, b), expect) << std::hex << "0x" << a << " - 0x" << b;
+}
+INSTANTIATE_TEST_SUITE_P(
+ CheckedSubTest_AFloat,
+ CheckedSubTest_AFloat,
+ testing::ValuesIn(std::vector<BinaryCheckedCase_AFloat>{
+ {AFloat(0), AFloat(0), AFloat(0)},
+ {AFloat(1), AFloat(1), AFloat(0)},
+ {AFloat(0), AFloat(1), AFloat(1)},
+ {AFloat(-2), AFloat(-1), AFloat(1)},
+ {AFloat(1), AFloat(2), AFloat(1)},
+ {AFloat(-3), AFloat(-2), AFloat(1)},
+ {AFloat(0x100), AFloat(0x300), AFloat(0x200)},
+ {AFloat(-0x300), AFloat(-0x100), AFloat(0x200)},
+ {AFloat::Highest(), AFloat(AFloat::kHighestValue - 1), AFloat(-1)},
+ {AFloat::Lowest(), AFloat(AFloat::kLowestValue + 1), AFloat(1)},
+ {AFloat::Highest(), AFloat::Highest(), AFloat(0)},
+ {AFloat::Lowest(), AFloat::Lowest(), AFloat(0)},
+ {OVERFLOW, AFloat::Lowest(), AFloat::Highest()},
////////////////////////////////////////////////////////////////////////
}));
-using CheckedMulTest = testing::TestWithParam<BinaryCheckedCase>;
-TEST_P(CheckedMulTest, Test) {
+using CheckedMulTest_AInt = testing::TestWithParam<BinaryCheckedCase_AInt>;
+TEST_P(CheckedMulTest_AInt, Test) {
auto expect = std::get<0>(GetParam());
auto a = std::get<1>(GetParam());
auto b = std::get<2>(GetParam());
@@ -194,9 +500,9 @@ TEST_P(CheckedMulTest, Test) {
EXPECT_EQ(CheckedMul(b, a), expect) << std::hex << "0x" << a << " * 0x" << b;
}
INSTANTIATE_TEST_SUITE_P(
- CheckedMulTest,
- CheckedMulTest,
- testing::ValuesIn(std::vector<BinaryCheckedCase>{
+ CheckedMulTest_AInt,
+ CheckedMulTest_AInt,
+ testing::ValuesIn(std::vector<BinaryCheckedCase_AInt>{
{AInt(0), AInt(0), AInt(0)},
{AInt(0), AInt(1), AInt(0)},
{AInt(1), AInt(1), AInt(1)},
@@ -220,21 +526,21 @@ INSTANTIATE_TEST_SUITE_P(
{AInt(-0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(-4)},
{AInt(-0x8000000000000000ll), AInt(0x1000000000000000ll), AInt(-8)},
{AInt(-0x8000000000000000ll), AInt(-0x1000000000000000ll), AInt(8)},
- {AInt(0), AInt(AInt::kHighest), AInt(0)},
- {AInt(0), AInt(AInt::kLowest), AInt(0)},
+ {AInt(0), AInt::Highest(), AInt(0)},
+ {AInt(0), AInt::Lowest(), AInt(0)},
{OVERFLOW, AInt(0x1000000000000000ll), AInt(8)},
{OVERFLOW, AInt(-0x1000000000000000ll), AInt(-8)},
{OVERFLOW, AInt(0x800000000000000ll), AInt(0x10)},
{OVERFLOW, AInt(0x80000000ll), AInt(0x100000000ll)},
- {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kLowest)},
+ {OVERFLOW, AInt::Highest(), AInt::Highest()},
+ {OVERFLOW, AInt::Highest(), AInt::Lowest()},
////////////////////////////////////////////////////////////////////////
}));
using TernaryCheckedCase = std::tuple<std::optional<AInt>, AInt, AInt, AInt>;
-using CheckedMaddTest = testing::TestWithParam<TernaryCheckedCase>;
-TEST_P(CheckedMaddTest, Test) {
+using CheckedMaddTest_AInt = testing::TestWithParam<TernaryCheckedCase>;
+TEST_P(CheckedMaddTest_AInt, Test) {
auto expect = std::get<0>(GetParam());
auto a = std::get<1>(GetParam());
auto b = std::get<2>(GetParam());
@@ -245,8 +551,8 @@ TEST_P(CheckedMaddTest, Test) {
<< std::hex << "0x" << a << " * 0x" << b << " + 0x" << c;
}
INSTANTIATE_TEST_SUITE_P(
- CheckedMaddTest,
- CheckedMaddTest,
+ CheckedMaddTest_AInt,
+ CheckedMaddTest_AInt,
testing::ValuesIn(std::vector<TernaryCheckedCase>{
{AInt(0), AInt(0), AInt(0), AInt(0)},
{AInt(0), AInt(1), AInt(0), AInt(0)},
@@ -257,8 +563,8 @@ INSTANTIATE_TEST_SUITE_P(
{AInt(-1), AInt(-1), AInt(1), AInt(0)},
{AInt(2), AInt(2), AInt(1), AInt(0)},
{AInt(-2), AInt(-2), AInt(1), AInt(0)},
- {AInt(0), AInt(AInt::kHighest), AInt(0), AInt(0)},
- {AInt(0), AInt(AInt::kLowest), AInt(0), AInt(0)},
+ {AInt(0), AInt::Highest(), AInt(0), AInt(0)},
+ {AInt(0), AInt::Lowest(), AInt(0), AInt(0)},
{AInt(3), AInt(1), AInt(2), AInt(1)},
{AInt(0x300), AInt(1), AInt(0x100), AInt(0x200)},
{AInt(0x100), AInt(1), AInt(-0x100), AInt(0x200)},
@@ -279,27 +585,27 @@ INSTANTIATE_TEST_SUITE_P(
{AInt(-0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(-4), AInt(0)},
{AInt(-0x8000000000000000ll), AInt(0x1000000000000000ll), AInt(-8), AInt(0)},
{AInt(-0x8000000000000000ll), AInt(-0x1000000000000000ll), AInt(8), AInt(0)},
- {AInt(AInt::kHighest), AInt(1), AInt(1), AInt(AInt::kHighest - 1)},
- {AInt(AInt::kLowest), AInt(1), AInt(-1), AInt(AInt::kLowest + 1)},
- {AInt(AInt::kHighest), AInt(1), AInt(0x7fffffff00000000ll), AInt(0x00000000ffffffffll)},
- {AInt(AInt::kHighest), AInt(1), AInt(AInt::kHighest), AInt(0)},
- {AInt(AInt::kLowest), AInt(1), AInt(AInt::kLowest), AInt(0)},
+ {AInt::Highest(), AInt(1), AInt(1), AInt(AInt::kHighestValue - 1)},
+ {AInt::Lowest(), AInt(1), AInt(-1), AInt(AInt::kLowestValue + 1)},
+ {AInt::Highest(), AInt(1), AInt(0x7fffffff00000000ll), AInt(0x00000000ffffffffll)},
+ {AInt::Highest(), AInt(1), AInt::Highest(), AInt(0)},
+ {AInt::Lowest(), AInt(1), AInt::Lowest(), AInt(0)},
{OVERFLOW, AInt(0x1000000000000000ll), AInt(8), AInt(0)},
{OVERFLOW, AInt(-0x1000000000000000ll), AInt(-8), AInt(0)},
{OVERFLOW, AInt(0x800000000000000ll), AInt(0x10), AInt(0)},
{OVERFLOW, AInt(0x80000000ll), AInt(0x100000000ll), AInt(0)},
- {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kHighest), AInt(0)},
- {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kLowest), AInt(0)},
- {OVERFLOW, AInt(1), AInt(1), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(1), AInt(-1), AInt(AInt::kLowest)},
- {OVERFLOW, AInt(1), AInt(2), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(1), AInt(-2), AInt(AInt::kLowest)},
- {OVERFLOW, AInt(1), AInt(10000), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(1), AInt(-10000), AInt(AInt::kLowest)},
- {OVERFLOW, AInt(1), AInt(AInt::kHighest), AInt(AInt::kHighest)},
- {OVERFLOW, AInt(1), AInt(AInt::kLowest), AInt(AInt::kLowest)},
- {OVERFLOW, AInt(1), AInt(AInt::kHighest), AInt(1)},
- {OVERFLOW, AInt(1), AInt(AInt::kLowest), AInt(-1)},
+ {OVERFLOW, AInt::Highest(), AInt::Highest(), AInt(0)},
+ {OVERFLOW, AInt::Highest(), AInt::Lowest(), AInt(0)},
+ {OVERFLOW, AInt(1), AInt(1), AInt::Highest()},
+ {OVERFLOW, AInt(1), AInt(-1), AInt::Lowest()},
+ {OVERFLOW, AInt(1), AInt(2), AInt::Highest()},
+ {OVERFLOW, AInt(1), AInt(-2), AInt::Lowest()},
+ {OVERFLOW, AInt(1), AInt(10000), AInt::Highest()},
+ {OVERFLOW, AInt(1), AInt(-10000), AInt::Lowest()},
+ {OVERFLOW, AInt(1), AInt::Highest(), AInt::Highest()},
+ {OVERFLOW, AInt(1), AInt::Lowest(), AInt::Lowest()},
+ {OVERFLOW, AInt(1), AInt::Highest(), AInt(1)},
+ {OVERFLOW, AInt(1), AInt::Lowest(), AInt(-1)},
}));
TINT_END_DISABLE_WARNING(CONSTANT_OVERFLOW);
diff --git a/chromium/third_party/dawn/src/tint/program.cc b/chromium/third_party/dawn/src/tint/program.cc
index 6722a09b0ee..6109c206646 100644
--- a/chromium/third_party/dawn/src/tint/program.cc
+++ b/chromium/third_party/dawn/src/tint/program.cc
@@ -35,9 +35,11 @@ Program::Program() = default;
Program::Program(Program&& program)
: id_(std::move(program.id_)),
+ highest_node_id_(std::move(program.highest_node_id_)),
types_(std::move(program.types_)),
ast_nodes_(std::move(program.ast_nodes_)),
sem_nodes_(std::move(program.sem_nodes_)),
+ constant_nodes_(std::move(program.constant_nodes_)),
ast_(std::move(program.ast_)),
sem_(std::move(program.sem_)),
symbols_(std::move(program.symbols_)),
@@ -49,6 +51,7 @@ Program::Program(Program&& program)
Program::Program(ProgramBuilder&& builder) {
id_ = builder.ID();
+ highest_node_id_ = builder.LastAllocatedNodeID();
is_valid_ = builder.IsValid();
if (builder.ResolveOnBuild() && builder.IsValid()) {
@@ -62,6 +65,7 @@ Program::Program(ProgramBuilder&& builder) {
types_ = std::move(builder.Types());
ast_nodes_ = std::move(builder.ASTNodes());
sem_nodes_ = std::move(builder.SemNodes());
+ constant_nodes_ = std::move(builder.ConstantNodes());
ast_ = &builder.AST(); // ast::Module is actually a heap allocation.
sem_ = std::move(builder.Sem());
symbols_ = std::move(builder.Symbols());
@@ -83,9 +87,11 @@ Program& Program::operator=(Program&& program) {
program.moved_ = true;
moved_ = false;
id_ = std::move(program.id_);
+ highest_node_id_ = std::move(program.highest_node_id_);
types_ = std::move(program.types_);
ast_nodes_ = std::move(program.ast_nodes_);
sem_nodes_ = std::move(program.sem_nodes_);
+ constant_nodes_ = std::move(program.constant_nodes_);
ast_ = std::move(program.ast_);
sem_ = std::move(program.sem_);
symbols_ = std::move(program.symbols_);
diff --git a/chromium/third_party/dawn/src/tint/program.h b/chromium/third_party/dawn/src/tint/program.h
index 3230e7e786c..ea884701eff 100644
--- a/chromium/third_party/dawn/src/tint/program.h
+++ b/chromium/third_party/dawn/src/tint/program.h
@@ -20,6 +20,7 @@
#include "src/tint/ast/function.h"
#include "src/tint/program_id.h"
+#include "src/tint/sem/constant.h"
#include "src/tint/sem/info.h"
#include "src/tint/sem/type_manager.h"
#include "src/tint/symbol_table.h"
@@ -43,6 +44,9 @@ class Program {
/// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
+ /// ConstantAllocator is an alias to BlockAllocator<sem::Constant>
+ using ConstantAllocator = utils::BlockAllocator<sem::Constant>;
+
/// Constructor
Program();
@@ -65,6 +69,9 @@ class Program {
/// @returns the unique identifier for this program
ProgramID ID() const { return id_; }
+ /// @returns the last allocated (numerically highest) AST node identifier.
+ ast::NodeID HighestASTNodeID() const { return highest_node_id_; }
+
/// @returns a reference to the program's types
const sem::Manager& Types() const {
AssertNotMoved();
@@ -157,9 +164,11 @@ class Program {
void AssertNotMoved() const;
ProgramID id_;
+ ast::NodeID highest_node_id_;
sem::Manager types_;
ASTNodeAllocator ast_nodes_;
SemNodeAllocator sem_nodes_;
+ ConstantAllocator constant_nodes_;
ast::Module* ast_ = nullptr;
sem::Info sem_;
SymbolTable symbols_{id_};
diff --git a/chromium/third_party/dawn/src/tint/program_builder.cc b/chromium/third_party/dawn/src/tint/program_builder.cc
index cd05fd41b2d..1507cd3629d 100644
--- a/chromium/third_party/dawn/src/tint/program_builder.cc
+++ b/chromium/third_party/dawn/src/tint/program_builder.cc
@@ -29,14 +29,16 @@ namespace tint {
ProgramBuilder::VarOptionals::~VarOptionals() = default;
ProgramBuilder::ProgramBuilder()
- : id_(ProgramID::New()), ast_(ast_nodes_.Create<ast::Module>(id_, Source{})) {}
+ : id_(ProgramID::New()),
+ ast_(ast_nodes_.Create<ast::Module>(id_, AllocateNodeID(), Source{})) {}
ProgramBuilder::ProgramBuilder(ProgramBuilder&& rhs)
: id_(std::move(rhs.id_)),
+ last_ast_node_id_(std::move(rhs.last_ast_node_id_)),
types_(std::move(rhs.types_)),
ast_nodes_(std::move(rhs.ast_nodes_)),
sem_nodes_(std::move(rhs.sem_nodes_)),
- ast_(rhs.ast_),
+ ast_(std::move(rhs.ast_)),
sem_(std::move(rhs.sem_)),
symbols_(std::move(rhs.symbols_)),
diagnostics_(std::move(rhs.diagnostics_)) {
@@ -49,10 +51,11 @@ ProgramBuilder& ProgramBuilder::operator=(ProgramBuilder&& rhs) {
rhs.MarkAsMoved();
AssertNotMoved();
id_ = std::move(rhs.id_);
+ last_ast_node_id_ = std::move(rhs.last_ast_node_id_);
types_ = std::move(rhs.types_);
ast_nodes_ = std::move(rhs.ast_nodes_);
sem_nodes_ = std::move(rhs.sem_nodes_);
- ast_ = rhs.ast_;
+ ast_ = std::move(rhs.ast_);
sem_ = std::move(rhs.sem_);
symbols_ = std::move(rhs.symbols_);
diagnostics_ = std::move(rhs.diagnostics_);
@@ -63,6 +66,7 @@ ProgramBuilder& ProgramBuilder::operator=(ProgramBuilder&& rhs) {
ProgramBuilder ProgramBuilder::Wrap(const Program* program) {
ProgramBuilder builder;
builder.id_ = program->ID();
+ builder.last_ast_node_id_ = program->HighestASTNodeID();
builder.types_ = sem::Manager::Wrap(program->Types());
builder.ast_ =
builder.create<ast::Module>(program->AST().source, program->AST().GlobalDeclarations());
@@ -125,10 +129,12 @@ const ast::Statement* ProgramBuilder::WrapInStatement(const ast::Statement* stmt
return stmt;
}
-const ast::Function* ProgramBuilder::WrapInFunction(const ast::StatementList stmts) {
- return Func(
- "test_function", {}, ty.void_(), std::move(stmts),
- {create<ast::StageAttribute>(ast::PipelineStage::kCompute), WorkgroupSize(1_i, 1_i, 1_i)});
+const ast::Function* ProgramBuilder::WrapInFunction(utils::VectorRef<const ast::Statement*> stmts) {
+ return Func("test_function", {}, ty.void_(), std::move(stmts),
+ utils::Vector{
+ create<ast::StageAttribute>(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i, 1_i, 1_i),
+ });
}
} // namespace tint
diff --git a/chromium/third_party/dawn/src/tint/program_builder.h b/chromium/third_party/dawn/src/tint/program_builder.h
index 5f47efb0165..25766e671f6 100644
--- a/chromium/third_party/dawn/src/tint/program_builder.h
+++ b/chromium/third_party/dawn/src/tint/program_builder.h
@@ -19,6 +19,8 @@
#include <unordered_set>
#include <utility>
+#include "tint/override_id.h"
+
#include "src/tint/ast/alias.h"
#include "src/tint/ast/array.h"
#include "src/tint/ast/assignment_statement.h"
@@ -33,6 +35,7 @@
#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/case_statement.h"
#include "src/tint/ast/compound_assignment_statement.h"
+#include "src/tint/ast/const.h"
#include "src/tint/ast/continue_statement.h"
#include "src/tint/ast/depth_multisampled_texture.h"
#include "src/tint/ast/depth_texture.h"
@@ -53,17 +56,21 @@
#include "src/tint/ast/index_accessor_expression.h"
#include "src/tint/ast/interpolate_attribute.h"
#include "src/tint/ast/invariant_attribute.h"
+#include "src/tint/ast/let.h"
#include "src/tint/ast/loop_statement.h"
#include "src/tint/ast/matrix.h"
#include "src/tint/ast/member_accessor_expression.h"
#include "src/tint/ast/module.h"
#include "src/tint/ast/multisampled_texture.h"
+#include "src/tint/ast/override.h"
+#include "src/tint/ast/parameter.h"
#include "src/tint/ast/phony_expression.h"
#include "src/tint/ast/pointer.h"
#include "src/tint/ast/return_statement.h"
#include "src/tint/ast/sampled_texture.h"
#include "src/tint/ast/sampler.h"
#include "src/tint/ast/stage_attribute.h"
+#include "src/tint/ast/static_assert.h"
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/stride_attribute.h"
#include "src/tint/ast/struct_member_align_attribute.h"
@@ -73,15 +80,18 @@
#include "src/tint/ast/type_name.h"
#include "src/tint/ast/u32.h"
#include "src/tint/ast/unary_op_expression.h"
+#include "src/tint/ast/var.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/vector.h"
#include "src/tint/ast/void.h"
+#include "src/tint/ast/while_statement.h"
#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/number.h"
#include "src/tint/program.h"
#include "src/tint/program_id.h"
#include "src/tint/sem/array.h"
#include "src/tint/sem/bool.h"
+#include "src/tint/sem/constant.h"
#include "src/tint/sem/depth_texture.h"
#include "src/tint/sem/external_texture.h"
#include "src/tint/sem/f16.h"
@@ -111,6 +121,30 @@ class VariableDeclStatement;
namespace tint {
+namespace detail {
+
+/// IsVectorLike<T>::value is true if T is a utils::Vector or utils::VectorRef.
+template <typename T>
+struct IsVectorLike {
+ /// Non-specialized form of IsVectorLike defaults to false
+ static constexpr bool value = false;
+};
+
+/// IsVectorLike specialization for utils::Vector
+template <typename T, size_t N>
+struct IsVectorLike<utils::Vector<T, N>> {
+ /// True for the IsVectorLike specialization of utils::Vector
+ static constexpr bool value = true;
+};
+
+/// IsVectorLike specialization for utils::VectorRef
+template <typename T>
+struct IsVectorLike<utils::VectorRef<T>> {
+ /// True for the IsVectorLike specialization of utils::VectorRef
+ static constexpr bool value = true;
+};
+} // namespace detail
+
/// ProgramBuilder is a mutable builder for a Program.
/// To construct a Program, populate the builder and then `std::move` it to a
/// Program.
@@ -122,8 +156,14 @@ class ProgramBuilder {
using DisableIfSource =
traits::EnableIfIsNotType<traits::Decay<traits::NthTypeOf<0, TYPES..., void>>, Source>;
+ /// A helper used to disable overloads if the first type in `TYPES` is a utils::Vector,
+ /// utils::VectorRef or utils::VectorRef.
+ template <typename... TYPES>
+ using DisableIfVectorLike = traits::EnableIf<
+ !detail::IsVectorLike<traits::Decay<traits::NthTypeOf<0, TYPES..., void>>>::value>;
+
/// VarOptionals is a helper for accepting a number of optional, extra
- /// arguments for Var() and Global().
+ /// arguments for Var() and GlobalVar().
struct VarOptionals {
template <typename... ARGS>
explicit VarOptionals(ARGS&&... args) {
@@ -134,13 +174,13 @@ class ProgramBuilder {
ast::StorageClass storage = ast::StorageClass::kNone;
ast::Access access = ast::Access::kUndefined;
const ast::Expression* constructor = nullptr;
- ast::AttributeList attributes = {};
+ utils::Vector<const ast::Attribute*, 4> attributes;
private:
void Set(ast::StorageClass sc) { storage = sc; }
void Set(ast::Access ac) { access = ac; }
void Set(const ast::Expression* c) { constructor = c; }
- void Set(const ast::AttributeList& l) { attributes = l; }
+ void Set(utils::VectorRef<const ast::Attribute*> l) { attributes = std::move(l); }
template <typename FIRST, typename... ARGS>
void Apply(FIRST&& first, ARGS&&... args) {
@@ -157,6 +197,9 @@ class ProgramBuilder {
/// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
+ /// ConstantAllocator is an alias to BlockAllocator<sem::Constant>
+ using ConstantAllocator = utils::BlockAllocator<sem::Constant>;
+
/// Constructor
ProgramBuilder();
@@ -223,6 +266,12 @@ class ProgramBuilder {
return sem_nodes_;
}
+ /// @returns a reference to the program's semantic constant storage
+ ConstantAllocator& ConstantNodes() {
+ AssertNotMoved();
+ return constant_nodes_;
+ }
+
/// @returns a reference to the program's AST root Module
ast::Module& AST() {
AssertNotMoved();
@@ -283,6 +332,16 @@ class ProgramBuilder {
/// information
bool IsValid() const;
+ /// @returns the last allocated (numerically highest) AST node identifier.
+ ast::NodeID LastAllocatedNodeID() const { return last_ast_node_id_; }
+
+ /// @returns the next sequentially unique node identifier.
+ ast::NodeID AllocateNodeID() {
+ auto out = ast::NodeID{last_ast_node_id_.value + 1};
+ last_ast_node_id_ = out;
+ return out;
+ }
+
/// Creates a new ast::Node owned by the ProgramBuilder. When the
/// ProgramBuilder is destructed, the ast::Node will also be destructed.
/// @param source the Source of the node
@@ -291,7 +350,7 @@ class ProgramBuilder {
template <typename T, typename... ARGS>
traits::EnableIfIsType<T, ast::Node>* create(const Source& source, ARGS&&... args) {
AssertNotMoved();
- return ast_nodes_.Create<T>(id_, source, std::forward<ARGS>(args)...);
+ return ast_nodes_.Create<T>(id_, AllocateNodeID(), source, std::forward<ARGS>(args)...);
}
/// Creates a new ast::Node owned by the ProgramBuilder, injecting the current
@@ -303,7 +362,7 @@ class ProgramBuilder {
template <typename T>
traits::EnableIfIsType<T, ast::Node>* create() {
AssertNotMoved();
- return ast_nodes_.Create<T>(id_, source_);
+ return ast_nodes_.Create<T>(id_, AllocateNodeID(), source_);
}
/// Creates a new ast::Node owned by the ProgramBuilder, injecting the current
@@ -321,14 +380,13 @@ class ProgramBuilder {
T>*
create(ARG0&& arg0, ARGS&&... args) {
AssertNotMoved();
- return ast_nodes_.Create<T>(id_, source_, std::forward<ARG0>(arg0),
+ return ast_nodes_.Create<T>(id_, AllocateNodeID(), source_, std::forward<ARG0>(arg0),
std::forward<ARGS>(args)...);
}
/// Creates a new sem::Node owned by the ProgramBuilder.
- /// When the ProgramBuilder is destructed, the sem::Node will also be
- /// destructed.
- /// @param args the arguments to pass to the type constructor
+ /// When the ProgramBuilder is destructed, the sem::Node will also be destructed.
+ /// @param args the arguments to pass to the constructor
/// @returns the node pointer
template <typename T, typename... ARGS>
traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> &&
@@ -339,6 +397,16 @@ class ProgramBuilder {
return sem_nodes_.Create<T>(std::forward<ARGS>(args)...);
}
+ /// Creates a new sem::Constant owned by the ProgramBuilder.
+ /// When the ProgramBuilder is destructed, the sem::Node will also be destructed.
+ /// @param args the arguments to pass to the constructor
+ /// @returns the node pointer
+ template <typename T, typename... ARGS>
+ traits::EnableIf<traits::IsTypeOrDerived<T, sem::Constant>, T>* create(ARGS&&... args) {
+ AssertNotMoved();
+ return constant_nodes_.Create<T>(std::forward<ARGS>(args)...);
+ }
+
/// Creates a new sem::Type owned by the ProgramBuilder.
/// When the ProgramBuilder is destructed, owned ProgramBuilder and the
/// returned`Type` will also be destructed.
@@ -452,14 +520,35 @@ class ProgramBuilder {
/// @return the tint AST type for a 2-element vector of `type`.
const ast::Vector* vec2(const ast::Type* type) const { return vec(type, 2u); }
+ /// @param source the vector source
+ /// @param type vector subtype
+ /// @return the tint AST type for a 2-element vector of `type`.
+ const ast::Vector* vec2(const Source& source, const ast::Type* type) const {
+ return vec(source, type, 2u);
+ }
+
/// @param type vector subtype
/// @return the tint AST type for a 3-element vector of `type`.
const ast::Vector* vec3(const ast::Type* type) const { return vec(type, 3u); }
+ /// @param source the vector source
+ /// @param type vector subtype
+ /// @return the tint AST type for a 3-element vector of `type`.
+ const ast::Vector* vec3(const Source& source, const ast::Type* type) const {
+ return vec(source, type, 3u);
+ }
+
/// @param type vector subtype
/// @return the tint AST type for a 4-element vector of `type`.
const ast::Vector* vec4(const ast::Type* type) const { return vec(type, 4u); }
+ /// @param source the vector source
+ /// @param type vector subtype
+ /// @return the tint AST type for a 4-element vector of `type`.
+ const ast::Vector* vec4(const Source& source, const ast::Type* type) const {
+ return vec(source, type, 4u);
+ }
+
/// @param n vector width in elements
/// @return the tint AST type for a `n`-element vector of `type`.
template <typename T>
@@ -473,18 +562,39 @@ class ProgramBuilder {
return vec2(Of<T>());
}
+ /// @param source the Source of the node
+ /// @return the tint AST type for a 2-element vector of the C type `T`.
+ template <typename T>
+ const ast::Vector* vec2(const Source& source) const {
+ return vec2(source, Of<T>());
+ }
+
/// @return the tint AST type for a 3-element vector of the C type `T`.
template <typename T>
const ast::Vector* vec3() const {
return vec3(Of<T>());
}
+ /// @param source the Source of the node
+ /// @return the tint AST type for a 3-element vector of the C type `T`.
+ template <typename T>
+ const ast::Vector* vec3(const Source& source) const {
+ return vec3(source, Of<T>());
+ }
+
/// @return the tint AST type for a 4-element vector of the C type `T`.
template <typename T>
const ast::Vector* vec4() const {
return vec4(Of<T>());
}
+ /// @param source the Source of the node
+ /// @return the tint AST type for a 4-element vector of the C type `T`.
+ template <typename T>
+ const ast::Vector* vec4(const Source& source) const {
+ return vec4(source, Of<T>());
+ }
+
/// @param type matrix subtype
/// @param columns number of columns for the matrix
/// @param rows number of rows for the matrix
@@ -608,11 +718,12 @@ class ProgramBuilder {
/// @param attrs the optional attributes for the array
/// @return the tint AST type for a array of size `n` of type `T`
template <typename EXPR = ast::Expression*>
- const ast::Array* array(const ast::Type* subtype,
- EXPR&& n = nullptr,
- ast::AttributeList attrs = {}) const {
+ const ast::Array* array(
+ const ast::Type* subtype,
+ EXPR&& n = nullptr,
+ utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
return builder->create<ast::Array>(subtype, builder->Expr(std::forward<EXPR>(n)),
- attrs);
+ std::move(attrs));
}
/// @param source the Source of the node
@@ -621,12 +732,13 @@ class ProgramBuilder {
/// @param attrs the optional attributes for the array
/// @return the tint AST type for a array of size `n` of type `T`
template <typename EXPR = ast::Expression*>
- const ast::Array* array(const Source& source,
- const ast::Type* subtype,
- EXPR&& n = nullptr,
- ast::AttributeList attrs = {}) const {
- return builder->create<ast::Array>(source, subtype,
- builder->Expr(std::forward<EXPR>(n)), attrs);
+ const ast::Array* array(
+ const Source& source,
+ const ast::Type* subtype,
+ EXPR&& n = nullptr,
+ utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
+ return builder->create<ast::Array>(
+ source, subtype, builder->Expr(std::forward<EXPR>(n)), std::move(attrs));
}
/// @param subtype the array element type
@@ -635,9 +747,9 @@ class ProgramBuilder {
/// @return the tint AST type for a array of size `n` of type `T`
template <typename EXPR>
const ast::Array* array(const ast::Type* subtype, EXPR&& n, uint32_t stride) const {
- ast::AttributeList attrs;
+ utils::Vector<const ast::Attribute*, 2> attrs;
if (stride) {
- attrs.emplace_back(builder->create<ast::StrideAttribute>(stride));
+ attrs.Push(builder->create<ast::StrideAttribute>(stride));
}
return array(subtype, std::forward<EXPR>(n), std::move(attrs));
}
@@ -652,9 +764,9 @@ class ProgramBuilder {
const ast::Type* subtype,
EXPR&& n,
uint32_t stride) const {
- ast::AttributeList attrs;
+ utils::Vector<const ast::Attribute*, 2> attrs;
if (stride) {
- attrs.emplace_back(builder->create<ast::StrideAttribute>(stride));
+ attrs.Push(builder->create<ast::StrideAttribute>(stride));
}
return array(source, subtype, std::forward<EXPR>(n), std::move(attrs));
}
@@ -755,6 +867,17 @@ class ProgramBuilder {
}
/// @param source the Source of the node
+ /// @param storage_class the storage class of the pointer
+ /// @param access the optional access control of the pointer
+ /// @return the pointer to type `T` with the given ast::StorageClass.
+ template <typename T>
+ const ast::Pointer* pointer(const Source& source,
+ ast::StorageClass storage_class,
+ ast::Access access = ast::Access::kUndefined) const {
+ return pointer(source, Of<T>(), storage_class, access);
+ }
+
+ /// @param source the Source of the node
/// @param type the type of the atomic
/// @return the atomic to `type`
const ast::Atomic* atomic(const Source& source, const ast::Type* type) const {
@@ -1092,9 +1215,9 @@ class ProgramBuilder {
/// `list`.
/// @param list the list to append too
/// @param arg the arg to create
- template <typename ARG>
- void Append(ast::ExpressionList& list, ARG&& arg) {
- list.emplace_back(Expr(std::forward<ARG>(arg)));
+ template <size_t N, typename ARG>
+ void Append(utils::Vector<const ast::Expression*, N>& list, ARG&& arg) {
+ list.Push(Expr(std::forward<ARG>(arg)));
}
/// Converts `arg0` and `args` to `ast::Expression`s using `Expr()`,
@@ -1102,29 +1225,38 @@ class ProgramBuilder {
/// @param list the list to append too
/// @param arg0 the first argument
/// @param args the rest of the arguments
- template <typename ARG0, typename... ARGS>
- void Append(ast::ExpressionList& list, ARG0&& arg0, ARGS&&... args) {
+ template <size_t N, typename ARG0, typename... ARGS>
+ void Append(utils::Vector<const ast::Expression*, N>& list, ARG0&& arg0, ARGS&&... args) {
Append(list, std::forward<ARG0>(arg0));
Append(list, std::forward<ARGS>(args)...);
}
- /// @return an empty list of expressions
- ast::ExpressionList ExprList() { return {}; }
+ /// @return utils::EmptyType
+ utils::EmptyType ExprList() { return utils::Empty; }
/// @param args the list of expressions
/// @return the list of expressions converted to `ast::Expression`s using
/// `Expr()`,
- template <typename... ARGS>
- ast::ExpressionList ExprList(ARGS&&... args) {
- ast::ExpressionList list;
- list.reserve(sizeof...(args));
+ template <typename... ARGS, typename = DisableIfVectorLike<ARGS...>>
+ auto ExprList(ARGS&&... args) {
+ utils::Vector<const ast::Expression*, sizeof...(ARGS)> list;
Append(list, std::forward<ARGS>(args)...);
return list;
}
/// @param list the list of expressions
/// @return `list`
- ast::ExpressionList ExprList(ast::ExpressionList list) { return list; }
+ template <typename T, size_t N>
+ utils::Vector<T, N> ExprList(utils::Vector<T, N>&& list) {
+ return std::move(list);
+ }
+
+ /// @param list the list of expressions
+ /// @return `list`
+ utils::VectorRef<const ast::Expression*> ExprList(
+ utils::VectorRef<const ast::Expression*> list) {
+ return list;
+ }
/// @param args the arguments for the type constructor
/// @return an `ast::CallExpression` of type `ty`, with the values
@@ -1197,99 +1329,207 @@ class ProgramBuilder {
/// @param args the arguments for the vector constructor
/// @return an `ast::CallExpression` of a 2-element vector of type
/// `T`, constructed with the values `args`.
- template <typename T, typename... ARGS>
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* vec2(ARGS&&... args) {
return Construct(ty.vec2<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the vector source
/// @param args the arguments for the vector constructor
- /// @return an `ast::CallExpression` of a 3-element vector of type
+ /// @return an `ast::CallExpression` of a 2-element vector of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* vec2(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.vec2<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the vector constructor
+ /// @return an `ast::CallExpression` of a 3-element vector of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* vec3(ARGS&&... args) {
return Construct(ty.vec3<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the vector source
/// @param args the arguments for the vector constructor
- /// @return an `ast::CallExpression` of a 4-element vector of type
+ /// @return an `ast::CallExpression` of a 3-element vector of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* vec3(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.vec3<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the vector constructor
+ /// @return an `ast::CallExpression` of a 4-element vector of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* vec4(ARGS&&... args) {
return Construct(ty.vec4<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the vector source
+ /// @param args the arguments for the vector constructor
+ /// @return an `ast::CallExpression` of a 4-element vector of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS>
+ const ast::CallExpression* vec4(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.vec4<T>(), std::forward<ARGS>(args)...);
+ }
+
/// @param args the arguments for the matrix constructor
/// @return an `ast::CallExpression` of a 2x2 matrix of type
/// `T`, constructed with the values `args`.
- template <typename T, typename... ARGS>
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat2x2(ARGS&&... args) {
return Construct(ty.mat2x2<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 2x3 matrix of type
+ /// @return an `ast::CallExpression` of a 2x2 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat2x2(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat2x2<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 2x3 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat2x3(ARGS&&... args) {
return Construct(ty.mat2x3<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 2x4 matrix of type
+ /// @return an `ast::CallExpression` of a 2x3 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat2x3(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat2x3<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 2x4 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat2x4(ARGS&&... args) {
return Construct(ty.mat2x4<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 3x2 matrix of type
+ /// @return an `ast::CallExpression` of a 2x4 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat2x4(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat2x4<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 3x2 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat3x2(ARGS&&... args) {
return Construct(ty.mat3x2<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 3x3 matrix of type
+ /// @return an `ast::CallExpression` of a 3x2 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat3x2(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat3x2<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 3x3 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat3x3(ARGS&&... args) {
return Construct(ty.mat3x3<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 3x4 matrix of type
+ /// @return an `ast::CallExpression` of a 3x3 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat3x3(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat3x3<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 3x4 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat3x4(ARGS&&... args) {
return Construct(ty.mat3x4<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 4x2 matrix of type
+ /// @return an `ast::CallExpression` of a 3x4 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat3x4(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat3x4<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 4x2 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat4x2(ARGS&&... args) {
return Construct(ty.mat4x2<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 4x3 matrix of type
+ /// @return an `ast::CallExpression` of a 4x2 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat4x2(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat4x2<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 4x3 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat4x3(ARGS&&... args) {
return Construct(ty.mat4x3<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
/// @param args the arguments for the matrix constructor
- /// @return an `ast::CallExpression` of a 4x4 matrix of type
+ /// @return an `ast::CallExpression` of a 4x3 matrix of type
/// `T`, constructed with the values `args`.
template <typename T, typename... ARGS>
+ const ast::CallExpression* mat4x3(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat4x3<T>(), std::forward<ARGS>(args)...);
+ }
+
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 4x4 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS, typename _ = DisableIfSource<ARGS...>>
const ast::CallExpression* mat4x4(ARGS&&... args) {
return Construct(ty.mat4x4<T>(), std::forward<ARGS>(args)...);
}
+ /// @param source the matrix source
+ /// @param args the arguments for the matrix constructor
+ /// @return an `ast::CallExpression` of a 4x4 matrix of type
+ /// `T`, constructed with the values `args`.
+ template <typename T, typename... ARGS>
+ const ast::CallExpression* mat4x4(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.mat4x4<T>(), std::forward<ARGS>(args)...);
+ }
+
/// @param args the arguments for the array constructor
/// @return an `ast::CallExpression` of an array with element type
/// `T` and size `N`, constructed with the values `args`.
@@ -1298,6 +1538,15 @@ class ProgramBuilder {
return Construct(ty.array<T, N>(), std::forward<ARGS>(args)...);
}
+ /// @param source the array source
+ /// @param args the arguments for the array constructor
+ /// @return an `ast::CallExpression` of an array with element type
+ /// `T` and size `N`, constructed with the values `args`.
+ template <typename T, int N, typename... ARGS>
+ const ast::CallExpression* array(const Source& source, ARGS&&... args) {
+ return Construct(source, ty.array<T, N>(), std::forward<ARGS>(args)...);
+ }
+
/// @param subtype the array element type
/// @param n the array size. nullptr represents a runtime-array.
/// @param args the arguments for the array constructor
@@ -1308,6 +1557,21 @@ class ProgramBuilder {
return Construct(ty.array(subtype, std::forward<EXPR>(n)), std::forward<ARGS>(args)...);
}
+ /// @param source the array source
+ /// @param subtype the array element type
+ /// @param n the array size. nullptr represents a runtime-array.
+ /// @param args the arguments for the array constructor
+ /// @return an `ast::CallExpression` of an array with element type
+ /// `subtype`, constructed with the values `args`.
+ template <typename EXPR, typename... ARGS>
+ const ast::CallExpression* array(const Source& source,
+ const ast::Type* subtype,
+ EXPR&& n,
+ ARGS&&... args) {
+ return Construct(source, ty.array(subtype, std::forward<EXPR>(n)),
+ std::forward<ARGS>(args)...);
+ }
+
/// Adds the extension to the list of enable directives at the top of the module.
/// @param ext the extension to enable
/// @return an `ast::Enable` enabling the given extension.
@@ -1327,14 +1591,13 @@ class ProgramBuilder {
/// * ast::AttributeList - specifies the variable's attributes
/// Note that repeated arguments of the same type will use the last argument's
/// value.
- /// @returns a `ast::Variable` with the given name, type and additional
+ /// @returns a `ast::Var` with the given name, type and additional
/// options
template <typename NAME, typename... OPTIONAL>
- const ast::Variable* Var(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) {
+ const ast::Var* Var(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) {
VarOptionals opts(std::forward<OPTIONAL>(optional)...);
- return create<ast::Variable>(Sym(std::forward<NAME>(name)), opts.storage, opts.access, type,
- false /* is_const */, false /* is_overridable */,
- opts.constructor, std::move(opts.attributes));
+ return create<ast::Var>(Sym(std::forward<NAME>(name)), type, opts.storage, opts.access,
+ opts.constructor, std::move(opts.attributes));
}
/// @param source the variable source
@@ -1348,32 +1611,57 @@ class ProgramBuilder {
/// * ast::AttributeList - specifies the variable's attributes
/// Note that repeated arguments of the same type will use the last argument's
/// value.
- /// @returns a `ast::Variable` with the given name, storage and type
+ /// @returns a `ast::Var` with the given name, storage and type
template <typename NAME, typename... OPTIONAL>
- const ast::Variable* Var(const Source& source,
- NAME&& name,
- const ast::Type* type,
- OPTIONAL&&... optional) {
+ const ast::Var* Var(const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ OPTIONAL&&... optional) {
VarOptionals opts(std::forward<OPTIONAL>(optional)...);
- return create<ast::Variable>(source, Sym(std::forward<NAME>(name)), opts.storage,
- opts.access, type, false /* is_const */,
- false /* is_overridable */, opts.constructor,
- std::move(opts.attributes));
+ return create<ast::Var>(source, Sym(std::forward<NAME>(name)), type, opts.storage,
+ opts.access, opts.constructor, std::move(opts.attributes));
+ }
+
+ /// @param name the variable name
+ /// @param type the variable type
+ /// @param constructor constructor expression
+ /// @param attributes optional variable attributes
+ /// @returns an `ast::Const` with the given name and type
+ template <typename NAME>
+ const ast::Const* Const(NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::Const>(Sym(std::forward<NAME>(name)), type, constructor, attributes);
+ }
+
+ /// @param source the variable source
+ /// @param name the variable name
+ /// @param type the variable type
+ /// @param constructor constructor expression
+ /// @param attributes optional variable attributes
+ /// @returns an `ast::Const` with the given name and type
+ template <typename NAME>
+ const ast::Const* Const(const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::Const>(source, Sym(std::forward<NAME>(name)), type, constructor,
+ attributes);
}
/// @param name the variable name
/// @param type the variable type
/// @param constructor constructor expression
/// @param attributes optional variable attributes
- /// @returns an immutable `ast::Variable` with the given name and type
+ /// @returns an `ast::Let` with the given name and type
template <typename NAME>
- const ast::Variable* Let(NAME&& name,
- const ast::Type* type,
- const ast::Expression* constructor,
- ast::AttributeList attributes = {}) {
- return create<ast::Variable>(Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
- ast::Access::kUndefined, type, true /* is_const */,
- false /* is_overridable */, constructor, attributes);
+ const ast::Let* Let(NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::Let>(Sym(std::forward<NAME>(name)), type, constructor, attributes);
}
/// @param source the variable source
@@ -1381,46 +1669,39 @@ class ProgramBuilder {
/// @param type the variable type
/// @param constructor constructor expression
/// @param attributes optional variable attributes
- /// @returns an immutable `ast::Variable` with the given name and type
+ /// @returns an `ast::Let` with the given name and type
template <typename NAME>
- const ast::Variable* Let(const Source& source,
- NAME&& name,
- const ast::Type* type,
- const ast::Expression* constructor,
- ast::AttributeList attributes = {}) {
- return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
- ast::StorageClass::kNone, ast::Access::kUndefined, type,
- true /* is_const */, false /* is_overridable */, constructor,
- attributes);
+ const ast::Let* Let(const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::Let>(source, Sym(std::forward<NAME>(name)), type, constructor,
+ attributes);
}
/// @param name the parameter name
/// @param type the parameter type
/// @param attributes optional parameter attributes
- /// @returns an immutable `ast::Variable` with the given name and type
+ /// @returns an `ast::Parameter` with the given name and type
template <typename NAME>
- const ast::Variable* Param(NAME&& name,
- const ast::Type* type,
- ast::AttributeList attributes = {}) {
- return create<ast::Variable>(Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
- ast::Access::kUndefined, type, true /* is_const */,
- false /* is_overridable */, nullptr, attributes);
+ const ast::Parameter* Param(NAME&& name,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::Parameter>(Sym(std::forward<NAME>(name)), type, attributes);
}
/// @param source the parameter source
/// @param name the parameter name
/// @param type the parameter type
/// @param attributes optional parameter attributes
- /// @returns an immutable `ast::Variable` with the given name and type
+ /// @returns an `ast::Parameter` with the given name and type
template <typename NAME>
- const ast::Variable* Param(const Source& source,
- NAME&& name,
- const ast::Type* type,
- ast::AttributeList attributes = {}) {
- return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
- ast::StorageClass::kNone, ast::Access::kUndefined, type,
- true /* is_const */, false /* is_overridable */, nullptr,
- attributes);
+ const ast::Parameter* Param(const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::Parameter>(source, Sym(std::forward<NAME>(name)), type, attributes);
}
/// @param name the variable name
@@ -1433,10 +1714,10 @@ class ProgramBuilder {
/// * ast::AttributeList - specifies the variable's attributes
/// Note that repeated arguments of the same type will use the last argument's
/// value.
- /// @returns a new `ast::Variable`, which is automatically registered as a
- /// global variable with the ast::Module.
+ /// @returns a new `ast::Var`, which is automatically registered as a global variable with the
+ /// ast::Module.
template <typename NAME, typename... OPTIONAL, typename = DisableIfSource<NAME>>
- const ast::Variable* Global(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) {
+ const ast::Var* GlobalVar(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) {
auto* var = Var(std::forward<NAME>(name), type, std::forward<OPTIONAL>(optional)...);
AST().AddGlobalVariable(var);
return var;
@@ -1453,13 +1734,13 @@ class ProgramBuilder {
/// * ast::AttributeList - specifies the variable's attributes
/// Note that repeated arguments of the same type will use the last argument's
/// value.
- /// @returns a new `ast::Variable`, which is automatically registered as a
- /// global variable with the ast::Module.
+ /// @returns a new `ast::Var`, which is automatically registered as a global variable with the
+ /// ast::Module.
template <typename NAME, typename... OPTIONAL>
- const ast::Variable* Global(const Source& source,
- NAME&& name,
- const ast::Type* type,
- OPTIONAL&&... optional) {
+ const ast::Var* GlobalVar(const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ OPTIONAL&&... optional) {
auto* var =
Var(source, std::forward<NAME>(name), type, std::forward<OPTIONAL>(optional)...);
AST().AddGlobalVariable(var);
@@ -1470,15 +1751,15 @@ class ProgramBuilder {
/// @param type the variable type
/// @param constructor constructor expression
/// @param attributes optional variable attributes
- /// @returns a const `ast::Variable` constructed by calling Var() with the
- /// arguments of `args`, which is automatically registered as a global
- /// variable with the ast::Module.
+ /// @returns an `ast::Const` constructed by calling Const() with the arguments of `args`, which
+ /// is automatically registered as a global variable with the ast::Module.
template <typename NAME>
- const ast::Variable* GlobalConst(NAME&& name,
- const ast::Type* type,
- const ast::Expression* constructor,
- ast::AttributeList attributes = {}) {
- auto* var = Let(std::forward<NAME>(name), type, constructor, std::move(attributes));
+ const ast::Const* GlobalConst(
+ NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ auto* var = Const(std::forward<NAME>(name), type, constructor, std::move(attributes));
AST().AddGlobalVariable(var);
return var;
}
@@ -1488,16 +1769,18 @@ class ProgramBuilder {
/// @param type the variable type
/// @param constructor constructor expression
/// @param attributes optional variable attributes
- /// @returns a const `ast::Variable` constructed by calling Var() with the
+ /// @returns a const `ast::Const` constructed by calling Var() with the
/// arguments of `args`, which is automatically registered as a global
/// variable with the ast::Module.
template <typename NAME>
- const ast::Variable* GlobalConst(const Source& source,
- NAME&& name,
- const ast::Type* type,
- const ast::Expression* constructor,
- ast::AttributeList attributes = {}) {
- auto* var = Let(source, std::forward<NAME>(name), type, constructor, std::move(attributes));
+ const ast::Const* GlobalConst(
+ const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ auto* var =
+ Const(source, std::forward<NAME>(name), type, constructor, std::move(attributes));
AST().AddGlobalVariable(var);
return var;
}
@@ -1506,17 +1789,16 @@ class ProgramBuilder {
/// @param type the variable type
/// @param constructor optional constructor expression
/// @param attributes optional variable attributes
- /// @returns an overridable const `ast::Variable` which is automatically
- /// registered as a global variable with the ast::Module.
+ /// @returns an `ast::Override` which is automatically registered as a global variable with the
+ /// ast::Module.
template <typename NAME>
- const ast::Variable* Override(NAME&& name,
- const ast::Type* type,
- const ast::Expression* constructor,
- ast::AttributeList attributes = {}) {
- auto* var =
- create<ast::Variable>(source_, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
- ast::Access::kUndefined, type, true /* is_const */,
- true /* is_overridable */, constructor, std::move(attributes));
+ const ast::Override* Override(
+ NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ auto* var = create<ast::Override>(source_, Sym(std::forward<NAME>(name)), type, constructor,
+ std::move(attributes));
AST().AddGlobalVariable(var);
return var;
}
@@ -1526,24 +1808,58 @@ class ProgramBuilder {
/// @param type the variable type
/// @param constructor constructor expression
/// @param attributes optional variable attributes
- /// @returns a const `ast::Variable` constructed by calling Var() with the
- /// arguments of `args`, which is automatically registered as a global
- /// variable with the ast::Module.
+ /// @returns an `ast::Override` constructed with the arguments of `args`, which is automatically
+ /// registered as a global variable with the ast::Module.
template <typename NAME>
- const ast::Variable* Override(const Source& source,
- NAME&& name,
- const ast::Type* type,
- const ast::Expression* constructor,
- ast::AttributeList attributes = {}) {
- auto* var =
- create<ast::Variable>(source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
- ast::Access::kUndefined, type, true /* is_const */,
- true /* is_overridable */, constructor, std::move(attributes));
+ const ast::Override* Override(
+ const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ const ast::Expression* constructor,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ auto* var = create<ast::Override>(source, Sym(std::forward<NAME>(name)), type, constructor,
+ std::move(attributes));
AST().AddGlobalVariable(var);
return var;
}
/// @param source the source information
+ /// @param condition the assertion condition
+ /// @returns a new `ast::StaticAssert`, which is automatically registered as a global statement
+ /// with the ast::Module.
+ template <typename EXPR>
+ const ast::StaticAssert* GlobalStaticAssert(const Source& source, EXPR&& condition) {
+ auto* sa = StaticAssert(source, std::forward<EXPR>(condition));
+ AST().AddStaticAssert(sa);
+ return sa;
+ }
+
+ /// @param condition the assertion condition
+ /// @returns a new `ast::StaticAssert`, which is automatically registered as a global statement
+ /// with the ast::Module.
+ template <typename EXPR, typename = DisableIfSource<EXPR>>
+ const ast::StaticAssert* GlobalStaticAssert(EXPR&& condition) {
+ auto* sa = StaticAssert(std::forward<EXPR>(condition));
+ AST().AddStaticAssert(sa);
+ return sa;
+ }
+
+ /// @param source the source information
+ /// @param condition the assertion condition
+ /// @returns a new `ast::StaticAssert` with the given assertion condition
+ template <typename EXPR>
+ const ast::StaticAssert* StaticAssert(const Source& source, EXPR&& condition) {
+ return create<ast::StaticAssert>(source, Expr(std::forward<EXPR>(condition)));
+ }
+
+ /// @param condition the assertion condition
+ /// @returns a new `ast::StaticAssert` with the given assertion condition
+ template <typename EXPR, typename = DisableIfSource<EXPR>>
+ const ast::StaticAssert* StaticAssert(EXPR&& condition) {
+ return create<ast::StaticAssert>(Expr(std::forward<EXPR>(condition)));
+ }
+
+ /// @param source the source information
/// @param expr the expression to take the address of
/// @return an ast::UnaryOpExpression that takes the address of `expr`
template <typename EXPR>
@@ -1662,6 +1978,17 @@ class ProgramBuilder {
Expr(std::forward<RHS>(rhs)));
}
+ /// @param source the source information
+ /// @param lhs the left hand argument to the addition operation
+ /// @param rhs the right hand argument to the addition operation
+ /// @returns a `ast::BinaryExpression` summing the arguments `lhs` and `rhs`
+ template <typename LHS, typename RHS>
+ const ast::BinaryExpression* Add(const Source& source, LHS&& lhs, RHS&& rhs) {
+ return create<ast::BinaryExpression>(source, ast::BinaryOp::kAdd,
+ Expr(std::forward<LHS>(lhs)),
+ Expr(std::forward<RHS>(rhs)));
+ }
+
/// @param lhs the left hand argument to the and operation
/// @param rhs the right hand argument to the and operation
/// @returns a `ast::BinaryExpression` bitwise anding `lhs` and `rhs`
@@ -1924,7 +2251,7 @@ class ProgramBuilder {
/// @param group the group index
/// @param binding the binding index
/// @returns a attribute list with both the group and binding attributes
- ast::AttributeList GroupAndBinding(uint32_t group, uint32_t binding) {
+ utils::Vector<const ast::Attribute*, 2> GroupAndBinding(uint32_t group, uint32_t binding) {
return {Group(group), Binding(binding)};
}
@@ -1939,16 +2266,18 @@ class ProgramBuilder {
/// attributes
/// @returns the function pointer
template <typename NAME>
- const ast::Function* Func(const Source& source,
- NAME&& name,
- ast::VariableList params,
- const ast::Type* type,
- ast::StatementList body,
- ast::AttributeList attributes = {},
- ast::AttributeList return_type_attributes = {}) {
- auto* func = create<ast::Function>(source, Sym(std::forward<NAME>(name)), params, type,
- create<ast::BlockStatement>(body), attributes,
- return_type_attributes);
+ const ast::Function* Func(
+ const Source& source,
+ NAME&& name,
+ utils::VectorRef<const ast::Parameter*> params,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Statement*> body,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty,
+ utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty) {
+ auto* func =
+ create<ast::Function>(source, Sym(std::forward<NAME>(name)), std::move(params), type,
+ create<ast::BlockStatement>(std::move(body)),
+ std::move(attributes), std::move(return_type_attributes));
AST().AddFunction(func);
return func;
}
@@ -1963,15 +2292,17 @@ class ProgramBuilder {
/// attributes
/// @returns the function pointer
template <typename NAME>
- const ast::Function* Func(NAME&& name,
- ast::VariableList params,
- const ast::Type* type,
- ast::StatementList body,
- ast::AttributeList attributes = {},
- ast::AttributeList return_type_attributes = {}) {
- auto* func = create<ast::Function>(Sym(std::forward<NAME>(name)), params, type,
- create<ast::BlockStatement>(body), attributes,
- return_type_attributes);
+ const ast::Function* Func(
+ NAME&& name,
+ utils::VectorRef<const ast::Parameter*> params,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Statement*> body,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty,
+ utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty) {
+ auto* func =
+ create<ast::Function>(Sym(std::forward<NAME>(name)), std::move(params), type,
+ create<ast::BlockStatement>(std::move(body)),
+ std::move(attributes), std::move(return_type_attributes));
AST().AddFunction(func);
return func;
}
@@ -2066,9 +2397,11 @@ class ProgramBuilder {
/// @param members the struct members
/// @returns the struct type
template <typename NAME>
- const ast::Struct* Structure(const Source& source, NAME&& name, ast::StructMemberList members) {
+ const ast::Struct* Structure(const Source& source,
+ NAME&& name,
+ utils::VectorRef<const ast::StructMember*> members) {
auto sym = Sym(std::forward<NAME>(name));
- auto* type = create<ast::Struct>(source, sym, std::move(members), ast::AttributeList{});
+ auto* type = create<ast::Struct>(source, sym, std::move(members), utils::Empty);
AST().AddTypeDecl(type);
return type;
}
@@ -2078,9 +2411,9 @@ class ProgramBuilder {
/// @param members the struct members
/// @returns the struct type
template <typename NAME>
- const ast::Struct* Structure(NAME&& name, ast::StructMemberList members) {
+ const ast::Struct* Structure(NAME&& name, utils::VectorRef<const ast::StructMember*> members) {
auto sym = Sym(std::forward<NAME>(name));
- auto* type = create<ast::Struct>(sym, std::move(members), ast::AttributeList{});
+ auto* type = create<ast::Struct>(sym, std::move(members), utils::Empty);
AST().AddTypeDecl(type);
return type;
}
@@ -2092,10 +2425,11 @@ class ProgramBuilder {
/// @param attributes the optional struct member attributes
/// @returns the struct member pointer
template <typename NAME>
- const ast::StructMember* Member(const Source& source,
- NAME&& name,
- const ast::Type* type,
- ast::AttributeList attributes = {}) {
+ const ast::StructMember* Member(
+ const Source& source,
+ NAME&& name,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)), type,
std::move(attributes));
}
@@ -2106,22 +2440,23 @@ class ProgramBuilder {
/// @param attributes the optional struct member attributes
/// @returns the struct member pointer
template <typename NAME>
- const ast::StructMember* Member(NAME&& name,
- const ast::Type* type,
- ast::AttributeList attributes = {}) {
+ const ast::StructMember* Member(
+ NAME&& name,
+ const ast::Type* type,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type,
std::move(attributes));
}
/// Creates a ast::StructMember with the given byte offset
- /// @param offset the offset to use in the StructMemberOffsetattribute
+ /// @param offset the offset to use in the StructMemberOffsetAttribute
/// @param name the struct member name
/// @param type the struct member type
/// @returns the struct member pointer
template <typename NAME>
const ast::StructMember* Member(uint32_t offset, NAME&& name, const ast::Type* type) {
return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type,
- ast::AttributeList{
+ utils::Vector<const ast::Attribute*, 1>{
create<ast::StructMemberOffsetAttribute>(offset),
});
}
@@ -2133,7 +2468,9 @@ class ProgramBuilder {
template <typename... Statements>
const ast::BlockStatement* Block(const Source& source, Statements&&... statements) {
return create<ast::BlockStatement>(
- source, ast::StatementList{std::forward<Statements>(statements)...});
+ source, utils::Vector<const ast::Statement*, sizeof...(statements)>{
+ std::forward<Statements>(statements)...,
+ });
}
/// Creates a ast::BlockStatement with input statements
@@ -2142,7 +2479,9 @@ class ProgramBuilder {
template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>>
const ast::BlockStatement* Block(STATEMENTS&&... statements) {
return create<ast::BlockStatement>(
- ast::StatementList{std::forward<STATEMENTS>(statements)...});
+ utils::Vector<const ast::Statement*, sizeof...(statements)>{
+ std::forward<STATEMENTS>(statements)...,
+ });
}
/// A wrapper type for the Else statement used to create If statements.
@@ -2339,6 +2678,27 @@ class ProgramBuilder {
return create<ast::ForLoopStatement>(init, Expr(std::forward<COND>(cond)), cont, body);
}
+ /// Creates a ast::WhileStatement with input body and condition.
+ /// @param source the source information
+ /// @param cond the loop condition
+ /// @param body the loop body
+ /// @returns the while statement pointer
+ template <typename COND>
+ const ast::WhileStatement* While(const Source& source,
+ COND&& cond,
+ const ast::BlockStatement* body) {
+ return create<ast::WhileStatement>(source, Expr(std::forward<COND>(cond)), body);
+ }
+
+ /// Creates a ast::WhileStatement with given condition and body.
+ /// @param cond the condition
+ /// @param body the loop body
+ /// @returns the while loop statement pointer
+ template <typename COND>
+ const ast::WhileStatement* While(COND&& cond, const ast::BlockStatement* body) {
+ return create<ast::WhileStatement>(Expr(std::forward<COND>(cond)), body);
+ }
+
/// Creates a ast::VariableDeclStatement for the input variable
/// @param source the source information
/// @param var the variable to wrap in a decl statement
@@ -2363,8 +2723,10 @@ class ProgramBuilder {
const ast::SwitchStatement* Switch(const Source& source,
ExpressionInit&& condition,
Cases&&... cases) {
- return create<ast::SwitchStatement>(source, Expr(std::forward<ExpressionInit>(condition)),
- ast::CaseStatementList{std::forward<Cases>(cases)...});
+ return create<ast::SwitchStatement>(
+ source, Expr(std::forward<ExpressionInit>(condition)),
+ utils::Vector<const ast::CaseStatement*, sizeof...(cases)>{
+ std::forward<Cases>(cases)...});
}
/// Creates a ast::SwitchStatement with input expression and cases
@@ -2375,8 +2737,10 @@ class ProgramBuilder {
typename... Cases,
typename = DisableIfSource<ExpressionInit>>
const ast::SwitchStatement* Switch(ExpressionInit&& condition, Cases&&... cases) {
- return create<ast::SwitchStatement>(Expr(std::forward<ExpressionInit>(condition)),
- ast::CaseStatementList{std::forward<Cases>(cases)...});
+ return create<ast::SwitchStatement>(
+ Expr(std::forward<ExpressionInit>(condition)),
+ utils::Vector<const ast::CaseStatement*, sizeof...(cases)>{
+ std::forward<Cases>(cases)...});
}
/// Creates a ast::CaseStatement with input list of selectors, and body
@@ -2385,7 +2749,7 @@ class ProgramBuilder {
/// @param body the case body
/// @returns the case statement pointer
const ast::CaseStatement* Case(const Source& source,
- ast::CaseSelectorList selectors,
+ utils::VectorRef<const ast::IntLiteralExpression*> selectors,
const ast::BlockStatement* body = nullptr) {
return create<ast::CaseStatement>(source, std::move(selectors), body ? body : Block());
}
@@ -2394,7 +2758,7 @@ class ProgramBuilder {
/// @param selectors list of selectors
/// @param body the case body
/// @returns the case statement pointer
- const ast::CaseStatement* Case(ast::CaseSelectorList selectors,
+ const ast::CaseStatement* Case(utils::VectorRef<const ast::IntLiteralExpression*> selectors,
const ast::BlockStatement* body = nullptr) {
return create<ast::CaseStatement>(std::move(selectors), body ? body : Block());
}
@@ -2405,7 +2769,7 @@ class ProgramBuilder {
/// @returns the case statement pointer
const ast::CaseStatement* Case(const ast::IntLiteralExpression* selector,
const ast::BlockStatement* body = nullptr) {
- return Case(ast::CaseSelectorList{selector}, body);
+ return Case(utils::Vector{selector}, body);
}
/// Convenience function that creates a 'default' ast::CaseStatement
@@ -2414,14 +2778,14 @@ class ProgramBuilder {
/// @returns the case statement pointer
const ast::CaseStatement* DefaultCase(const Source& source,
const ast::BlockStatement* body = nullptr) {
- return Case(source, ast::CaseSelectorList{}, body);
+ return Case(source, utils::Empty, body);
}
/// Convenience function that creates a 'default' ast::CaseStatement
/// @param body the case body
/// @returns the case statement pointer
const ast::CaseStatement* DefaultCase(const ast::BlockStatement* body = nullptr) {
- return Case(ast::CaseSelectorList{}, body);
+ return Case(utils::Empty, body);
}
/// Creates an ast::FallthroughStatement
@@ -2439,14 +2803,14 @@ class ProgramBuilder {
/// @param source the source information
/// @param builtin the builtin value
/// @returns the builtin attribute pointer
- const ast::BuiltinAttribute* Builtin(const Source& source, ast::Builtin builtin) {
+ const ast::BuiltinAttribute* Builtin(const Source& source, ast::BuiltinValue builtin) {
return create<ast::BuiltinAttribute>(source, builtin);
}
/// Creates an ast::BuiltinAttribute
/// @param builtin the builtin value
/// @returns the builtin attribute pointer
- const ast::BuiltinAttribute* Builtin(ast::Builtin builtin) {
+ const ast::BuiltinAttribute* Builtin(ast::BuiltinValue builtin) {
return create<ast::BuiltinAttribute>(source_, builtin);
}
@@ -2513,11 +2877,24 @@ class ProgramBuilder {
/// @param source the source information
/// @param id the id value
/// @returns the override attribute pointer
+ const ast::IdAttribute* Id(const Source& source, OverrideId id) {
+ return create<ast::IdAttribute>(source, id.value);
+ }
+
+ /// Creates an ast::IdAttribute with an override identifier
+ /// @param id the optional id value
+ /// @returns the override attribute pointer
+ const ast::IdAttribute* Id(OverrideId id) { return Id(source_, id); }
+
+ /// Creates an ast::IdAttribute
+ /// @param source the source information
+ /// @param id the id value
+ /// @returns the override attribute pointer
const ast::IdAttribute* Id(const Source& source, uint32_t id) {
return create<ast::IdAttribute>(source, id);
}
- /// Creates an ast::IdAttribute with a constant ID
+ /// Creates an ast::IdAttribute with an override identifier
/// @param id the optional id value
/// @returns the override attribute pointer
const ast::IdAttribute* Id(uint32_t id) { return Id(source_, id); }
@@ -2596,7 +2973,8 @@ class ProgramBuilder {
/// @param validation the validation to disable
/// @returns the disable validation attribute pointer
const ast::DisableValidationAttribute* Disable(ast::DisabledValidation validation) {
- return ASTNodes().Create<ast::DisableValidationAttribute>(ID(), validation);
+ return ASTNodes().Create<ast::DisableValidationAttribute>(ID(), AllocateNodeID(),
+ validation);
}
/// Sets the current builder source to `src`
@@ -2688,13 +3066,15 @@ class ProgramBuilder {
/// @returns the function
template <typename... ARGS>
const ast::Function* WrapInFunction(ARGS&&... args) {
- ast::StatementList stmts{WrapInStatement(std::forward<ARGS>(args))...};
- return WrapInFunction(std::move(stmts));
+ utils::Vector stmts{
+ WrapInStatement(std::forward<ARGS>(args))...,
+ };
+ return WrapInFunction(utils::VectorRef<const ast::Statement*>{std::move(stmts)});
}
/// @param stmts a list of ast::Statement that will be wrapped by a function,
/// so that each statement is reachable by the Resolver.
/// @returns the function
- const ast::Function* WrapInFunction(ast::StatementList stmts);
+ const ast::Function* WrapInFunction(utils::VectorRef<const ast::Statement*> stmts);
/// The builder types
TypesBuilder const ty{this};
@@ -2705,9 +3085,11 @@ class ProgramBuilder {
private:
ProgramID id_;
+ ast::NodeID last_ast_node_id_ = ast::NodeID{static_cast<decltype(ast::NodeID::value)>(0) - 1};
sem::Manager types_;
ASTNodeAllocator ast_nodes_;
SemNodeAllocator sem_nodes_;
+ ConstantAllocator constant_nodes_;
ast::Module* ast_;
sem::Info sem_;
SymbolTable symbols_{id_};
diff --git a/chromium/third_party/dawn/src/tint/program_builder_test.cc b/chromium/third_party/dawn/src/tint/program_builder_test.cc
index dd7e7a8c37a..24e7344a98e 100644
--- a/chromium/third_party/dawn/src/tint/program_builder_test.cc
+++ b/chromium/third_party/dawn/src/tint/program_builder_test.cc
@@ -38,14 +38,14 @@ TEST_F(ProgramBuilderTest, WrapDoesntAffectInner) {
return builder;
}());
- ASSERT_EQ(inner.AST().Functions().size(), 1u);
+ ASSERT_EQ(inner.AST().Functions().Length(), 1u);
ASSERT_TRUE(inner.Symbols().Get("a").IsValid());
ASSERT_FALSE(inner.Symbols().Get("b").IsValid());
ProgramBuilder outer = ProgramBuilder::Wrap(&inner);
- ASSERT_EQ(inner.AST().Functions().size(), 1u);
- ASSERT_EQ(outer.AST().Functions().size(), 1u);
+ ASSERT_EQ(inner.AST().Functions().Length(), 1u);
+ ASSERT_EQ(outer.AST().Functions().Length(), 1u);
EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));
@@ -57,8 +57,8 @@ TEST_F(ProgramBuilderTest, WrapDoesntAffectInner) {
auto* ty = outer.ty.f32();
outer.Func("b", {}, ty, {}, {});
- ASSERT_EQ(inner.AST().Functions().size(), 1u);
- ASSERT_EQ(outer.AST().Functions().size(), 2u);
+ ASSERT_EQ(inner.AST().Functions().Length(), 1u);
+ ASSERT_EQ(outer.AST().Functions().Length(), 2u);
EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
EXPECT_EQ(outer.AST().Functions()[1]->symbol, outer.Symbols().Get("b"));
EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));
diff --git a/chromium/third_party/dawn/src/tint/program_test.cc b/chromium/third_party/dawn/src/tint/program_test.cc
index 3bdf11ac92e..39d7c07c149 100644
--- a/chromium/third_party/dawn/src/tint/program_test.cc
+++ b/chromium/third_party/dawn/src/tint/program_test.cc
@@ -28,7 +28,7 @@ TEST_F(ProgramTest, Unbuilt) {
TEST_F(ProgramTest, Creation) {
Program program(std::move(*this));
- EXPECT_EQ(program.AST().Functions().size(), 0u);
+ EXPECT_EQ(program.AST().Functions().Length(), 0u);
}
TEST_F(ProgramTest, EmptyIsValid) {
@@ -46,7 +46,7 @@ TEST_F(ProgramTest, IDsAreUnique) {
}
TEST_F(ProgramTest, Assert_GlobalVariable) {
- Global("var", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
Program program(std::move(*this));
EXPECT_TRUE(program.IsValid());
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/construct.h b/chromium/third_party/dawn/src/tint/reader/spirv/construct.h
index de4e477a294..cd0804a480e 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/construct.h
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/construct.h
@@ -18,7 +18,8 @@
#include <memory>
#include <sstream>
#include <string>
-#include <vector>
+
+#include "src/tint/utils/vector.h"
namespace tint::reader::spirv {
@@ -146,7 +147,7 @@ struct Construct {
};
/// ConstructList is a list of Construct unique pointers.
-using ConstructList = std::vector<std::unique_ptr<Construct>>;
+using ConstructList = utils::Vector<std::unique_ptr<Construct>, 8>;
/// Converts a construct kind to a string.
/// @param kind the construct kind to convert
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.cc b/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.cc
index 2677494a121..9e3604afe5f 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.cc
@@ -22,8 +22,8 @@ EntryPointInfo::EntryPointInfo(std::string the_name,
ast::PipelineStage the_stage,
bool the_owns_inner_implementation,
std::string the_inner_name,
- std::vector<uint32_t>&& the_inputs,
- std::vector<uint32_t>&& the_outputs,
+ utils::VectorRef<uint32_t> the_inputs,
+ utils::VectorRef<uint32_t> the_outputs,
GridSize the_wg_size)
: name(the_name),
stage(the_stage),
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.h b/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.h
index bc13759f008..90077421d1e 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.h
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/entry_point_info.h
@@ -16,9 +16,9 @@
#define SRC_TINT_READER_SPIRV_ENTRY_POINT_INFO_H_
#include <string>
-#include <vector>
#include "src/tint/ast/pipeline_stage.h"
+#include "src/tint/utils/vector.h"
namespace tint::reader::spirv {
@@ -48,8 +48,8 @@ struct EntryPointInfo {
ast::PipelineStage the_stage,
bool the_owns_inner_implementation,
std::string the_inner_name,
- std::vector<uint32_t>&& the_inputs,
- std::vector<uint32_t>&& the_outputs,
+ utils::VectorRef<uint32_t> the_inputs,
+ utils::VectorRef<uint32_t> the_outputs,
GridSize the_wg_size);
/// Copy constructor
/// @param other the other entry point info to be built from
@@ -75,9 +75,9 @@ struct EntryPointInfo {
/// The name of the inner implementation function of the entry point.
std::string inner_name;
/// IDs of pipeline input variables, sorted and without duplicates.
- std::vector<uint32_t> inputs;
+ utils::Vector<uint32_t, 8> inputs;
/// IDs of pipeline output variables, sorted and without duplicates.
- std::vector<uint32_t> outputs;
+ utils::Vector<uint32_t, 8> outputs;
/// If this is a compute shader, this is the workgroup size in the x, y,
/// and z dimensions set via LocalSize, or via the composite value
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.cc b/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.cc
index 1d58eee8dcd..879167032f8 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.cc
@@ -39,9 +39,9 @@ ast::PipelineStage EnumConverter::ToPipelineStage(SpvExecutionModel model) {
ast::StorageClass EnumConverter::ToStorageClass(const SpvStorageClass sc) {
switch (sc) {
case SpvStorageClassInput:
- return ast::StorageClass::kInput;
+ return ast::StorageClass::kIn;
case SpvStorageClassOutput:
- return ast::StorageClass::kOutput;
+ return ast::StorageClass::kOut;
case SpvStorageClassUniform:
return ast::StorageClass::kUniform;
case SpvStorageClassWorkgroup:
@@ -62,38 +62,38 @@ ast::StorageClass EnumConverter::ToStorageClass(const SpvStorageClass sc) {
return ast::StorageClass::kInvalid;
}
-ast::Builtin EnumConverter::ToBuiltin(SpvBuiltIn b) {
+ast::BuiltinValue EnumConverter::ToBuiltin(SpvBuiltIn b) {
switch (b) {
case SpvBuiltInPosition:
- return ast::Builtin::kPosition;
+ return ast::BuiltinValue::kPosition;
case SpvBuiltInVertexIndex:
- return ast::Builtin::kVertexIndex;
+ return ast::BuiltinValue::kVertexIndex;
case SpvBuiltInInstanceIndex:
- return ast::Builtin::kInstanceIndex;
+ return ast::BuiltinValue::kInstanceIndex;
case SpvBuiltInFrontFacing:
- return ast::Builtin::kFrontFacing;
+ return ast::BuiltinValue::kFrontFacing;
case SpvBuiltInFragCoord:
- return ast::Builtin::kPosition;
+ return ast::BuiltinValue::kPosition;
case SpvBuiltInFragDepth:
- return ast::Builtin::kFragDepth;
+ return ast::BuiltinValue::kFragDepth;
case SpvBuiltInLocalInvocationId:
- return ast::Builtin::kLocalInvocationId;
+ return ast::BuiltinValue::kLocalInvocationId;
case SpvBuiltInLocalInvocationIndex:
- return ast::Builtin::kLocalInvocationIndex;
+ return ast::BuiltinValue::kLocalInvocationIndex;
case SpvBuiltInGlobalInvocationId:
- return ast::Builtin::kGlobalInvocationId;
+ return ast::BuiltinValue::kGlobalInvocationId;
case SpvBuiltInWorkgroupId:
- return ast::Builtin::kWorkgroupId;
+ return ast::BuiltinValue::kWorkgroupId;
case SpvBuiltInSampleId:
- return ast::Builtin::kSampleIndex;
+ return ast::BuiltinValue::kSampleIndex;
case SpvBuiltInSampleMask:
- return ast::Builtin::kSampleMask;
+ return ast::BuiltinValue::kSampleMask;
default:
break;
}
Fail() << "unknown SPIR-V builtin: " << uint32_t(b);
- return ast::Builtin::kNone;
+ return ast::BuiltinValue::kInvalid;
}
ast::TextureDimension EnumConverter::ToDim(SpvDim dim, bool arrayed) {
@@ -129,7 +129,7 @@ ast::TextureDimension EnumConverter::ToDim(SpvDim dim, bool arrayed) {
ast::TexelFormat EnumConverter::ToTexelFormat(SpvImageFormat fmt) {
switch (fmt) {
case SpvImageFormatUnknown:
- return ast::TexelFormat::kNone;
+ return ast::TexelFormat::kInvalid;
// 8 bit channels
case SpvImageFormatRgba8:
@@ -172,7 +172,7 @@ ast::TexelFormat EnumConverter::ToTexelFormat(SpvImageFormat fmt) {
break;
}
Fail() << "invalid image format: " << int(fmt);
- return ast::TexelFormat::kNone;
+ return ast::TexelFormat::kInvalid;
}
} // namespace tint::reader::spirv
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.h b/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.h
index ac86f718961..fc3ad83abf8 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.h
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter.h
@@ -16,7 +16,7 @@
#define SRC_TINT_READER_SPIRV_ENUM_CONVERTER_H_
#include "spirv/unified1/spirv.h"
-#include "src/tint/ast/builtin.h"
+#include "src/tint/ast/builtin_value.h"
#include "src/tint/ast/pipeline_stage.h"
#include "src/tint/ast/storage_class.h"
#include "src/tint/reader/spirv/fail_stream.h"
@@ -49,7 +49,7 @@ class EnumConverter {
/// On failure, logs an error and returns kNone
/// @param b the SPIR-V builtin
/// @returns a Tint AST builtin
- ast::Builtin ToBuiltin(SpvBuiltIn b);
+ ast::BuiltinValue ToBuiltin(SpvBuiltIn b);
/// Converts a possibly arrayed SPIR-V Dim to a Tint texture dimension.
/// On failure, logs an error and returns kNone
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter_test.cc
index 791d7e352c4..95a6264967e 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/enum_converter_test.cc
@@ -125,8 +125,8 @@ INSTANTIATE_TEST_SUITE_P(
EnumConverterGood,
SpvStorageClassTest,
testing::Values(
- StorageClassCase{SpvStorageClassInput, true, ast::StorageClass::kInput},
- StorageClassCase{SpvStorageClassOutput, true, ast::StorageClass::kOutput},
+ StorageClassCase{SpvStorageClassInput, true, ast::StorageClass::kIn},
+ StorageClassCase{SpvStorageClassOutput, true, ast::StorageClass::kOut},
StorageClassCase{SpvStorageClassUniform, true, ast::StorageClass::kUniform},
StorageClassCase{SpvStorageClassWorkgroup, true, ast::StorageClass::kWorkgroup},
StorageClassCase{SpvStorageClassUniformConstant, true, ast::StorageClass::kNone},
@@ -144,7 +144,7 @@ INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
struct BuiltinCase {
SpvBuiltIn builtin;
bool expect_success;
- ast::Builtin expected;
+ ast::BuiltinValue expected;
};
inline std::ostream& operator<<(std::ostream& out, BuiltinCase bc) {
out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin)
@@ -184,30 +184,30 @@ INSTANTIATE_TEST_SUITE_P(
EnumConverterGood_Input,
SpvBuiltinTest,
testing::Values(
- BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
- BuiltinCase{SpvBuiltInInstanceIndex, true, ast::Builtin::kInstanceIndex},
- BuiltinCase{SpvBuiltInFrontFacing, true, ast::Builtin::kFrontFacing},
- BuiltinCase{SpvBuiltInFragCoord, true, ast::Builtin::kPosition},
- BuiltinCase{SpvBuiltInLocalInvocationId, true, ast::Builtin::kLocalInvocationId},
- BuiltinCase{SpvBuiltInLocalInvocationIndex, true, ast::Builtin::kLocalInvocationIndex},
- BuiltinCase{SpvBuiltInGlobalInvocationId, true, ast::Builtin::kGlobalInvocationId},
- BuiltinCase{SpvBuiltInWorkgroupId, true, ast::Builtin::kWorkgroupId},
- BuiltinCase{SpvBuiltInSampleId, true, ast::Builtin::kSampleIndex},
- BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
+ BuiltinCase{SpvBuiltInPosition, true, ast::BuiltinValue::kPosition},
+ BuiltinCase{SpvBuiltInInstanceIndex, true, ast::BuiltinValue::kInstanceIndex},
+ BuiltinCase{SpvBuiltInFrontFacing, true, ast::BuiltinValue::kFrontFacing},
+ BuiltinCase{SpvBuiltInFragCoord, true, ast::BuiltinValue::kPosition},
+ BuiltinCase{SpvBuiltInLocalInvocationId, true, ast::BuiltinValue::kLocalInvocationId},
+ BuiltinCase{SpvBuiltInLocalInvocationIndex, true, ast::BuiltinValue::kLocalInvocationIndex},
+ BuiltinCase{SpvBuiltInGlobalInvocationId, true, ast::BuiltinValue::kGlobalInvocationId},
+ BuiltinCase{SpvBuiltInWorkgroupId, true, ast::BuiltinValue::kWorkgroupId},
+ BuiltinCase{SpvBuiltInSampleId, true, ast::BuiltinValue::kSampleIndex},
+ BuiltinCase{SpvBuiltInSampleMask, true, ast::BuiltinValue::kSampleMask}));
INSTANTIATE_TEST_SUITE_P(
EnumConverterGood_Output,
SpvBuiltinTest,
- testing::Values(BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
- BuiltinCase{SpvBuiltInFragDepth, true, ast::Builtin::kFragDepth},
- BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
+ testing::Values(BuiltinCase{SpvBuiltInPosition, true, ast::BuiltinValue::kPosition},
+ BuiltinCase{SpvBuiltInFragDepth, true, ast::BuiltinValue::kFragDepth},
+ BuiltinCase{SpvBuiltInSampleMask, true, ast::BuiltinValue::kSampleMask}));
INSTANTIATE_TEST_SUITE_P(
EnumConverterBad,
SpvBuiltinTest,
- testing::Values(BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
- BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
- BuiltinCase{SpvBuiltInNumWorkgroups, false, ast::Builtin::kNone}));
+ testing::Values(BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::BuiltinValue::kInvalid},
+ BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::BuiltinValue::kInvalid},
+ BuiltinCase{SpvBuiltInNumWorkgroups, false, ast::BuiltinValue::kInvalid}));
// Dim
@@ -326,7 +326,7 @@ INSTANTIATE_TEST_SUITE_P(
SpvImageFormatTest,
testing::Values(
// Unknown. This is used for sampled images.
- TexelFormatCase{SpvImageFormatUnknown, true, ast::TexelFormat::kNone},
+ TexelFormatCase{SpvImageFormatUnknown, true, ast::TexelFormat::kInvalid},
// 8 bit channels
TexelFormatCase{SpvImageFormatRgba8, true, ast::TexelFormat::kRgba8Unorm},
TexelFormatCase{SpvImageFormatRgba8Snorm, true, ast::TexelFormat::kRgba8Snorm},
@@ -355,23 +355,23 @@ INSTANTIATE_TEST_SUITE_P(
SpvImageFormatTest,
testing::Values(
// Scanning in order from the SPIR-V spec.
- TexelFormatCase{SpvImageFormatRg16f, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatR11fG11fB10f, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatR16f, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRgb10A2, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg16, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg8, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatR16, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatR8, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRgba16Snorm, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg16Snorm, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg8Snorm, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg16i, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg8i, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatR8i, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRgb10a2ui, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg16ui, false, ast::TexelFormat::kNone},
- TexelFormatCase{SpvImageFormatRg8ui, false, ast::TexelFormat::kNone}));
+ TexelFormatCase{SpvImageFormatRg16f, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatR11fG11fB10f, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatR16f, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRgb10A2, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg16, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg8, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatR16, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatR8, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRgba16Snorm, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg16Snorm, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg8Snorm, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg16i, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg8i, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatR8i, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRgb10a2ui, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg16ui, false, ast::TexelFormat::kInvalid},
+ TexelFormatCase{SpvImageFormatRg8ui, false, ast::TexelFormat::kInvalid}));
} // namespace
} // namespace tint::reader::spirv
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/function.cc b/chromium/third_party/dawn/src/tint/reader/spirv/function.cc
index d88773e2ed4..a57984b8204 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/function.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/function.cc
@@ -20,8 +20,8 @@
#include "src/tint/ast/assignment_statement.h"
#include "src/tint/ast/bitcast_expression.h"
#include "src/tint/ast/break_statement.h"
-#include "src/tint/ast/builtin.h"
#include "src/tint/ast/builtin_attribute.h"
+#include "src/tint/ast/builtin_value.h"
#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/continue_statement.h"
#include "src/tint/ast/discard_statement.h"
@@ -36,6 +36,7 @@
#include "src/tint/sem/builtin_type.h"
#include "src/tint/sem/depth_texture.h"
#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/transform/spirv_atomic.h"
// Terms:
// CFG: the control flow graph of the function, where basic blocks are the
@@ -501,6 +502,38 @@ bool IsSampledImageAccess(SpvOp opcode) {
}
// @param opcode a SPIR-V opcode
+// @returns true if the given instruction is an atomic operation.
+bool IsAtomicOp(SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpAtomicLoad:
+ case SpvOpAtomicStore:
+ case SpvOpAtomicExchange:
+ case SpvOpAtomicCompareExchange:
+ case SpvOpAtomicCompareExchangeWeak:
+ case SpvOpAtomicIIncrement:
+ case SpvOpAtomicIDecrement:
+ case SpvOpAtomicIAdd:
+ case SpvOpAtomicISub:
+ case SpvOpAtomicSMin:
+ case SpvOpAtomicUMin:
+ case SpvOpAtomicSMax:
+ case SpvOpAtomicUMax:
+ case SpvOpAtomicAnd:
+ case SpvOpAtomicOr:
+ case SpvOpAtomicXor:
+ case SpvOpAtomicFlagTestAndSet:
+ case SpvOpAtomicFlagClear:
+ case SpvOpAtomicFMinEXT:
+ case SpvOpAtomicFMaxEXT:
+ case SpvOpAtomicFAddEXT:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+// @param opcode a SPIR-V opcode
// @returns true if the given instruction is an image sampling, gather,
// or gather-compare operation.
bool IsImageSamplingOrGatherOrDrefGather(SpvOp opcode) {
@@ -589,7 +622,7 @@ class StructuredTraverser {
// - a continue target always follows the associated loop construct, if any
// @returns the IDs of blocks in reverse structured post order
std::vector<uint32_t> ReverseStructuredPostOrder() {
- visit_order_.clear();
+ visit_order_.Clear();
visited_.clear();
VisitBackward(function_.entry()->id());
@@ -627,20 +660,20 @@ class StructuredTraverser {
VisitBackward(terminator->GetSingleWordInOperand(0));
} else if (opcode == SpvOpSwitch) {
// TODO(dneto): Consider visiting the labels in literal-value order.
- std::vector<uint32_t> successors;
+ utils::Vector<uint32_t, 32> successors;
bb->ForEachSuccessorLabel(
- [&successors](const uint32_t succ_id) { successors.push_back(succ_id); });
+ [&successors](const uint32_t succ_id) { successors.Push(succ_id); });
for (auto succ_id : successors) {
VisitBackward(succ_id);
}
}
- visit_order_.push_back(id);
+ visit_order_.Push(id);
}
const spvtools::opt::Function& function_;
std::unordered_map<uint32_t, const spvtools::opt::BasicBlock*> id_to_block_;
- std::vector<uint32_t> visit_order_;
+ utils::Vector<uint32_t, 32> visit_order_;
std::unordered_set<uint32_t> visited_;
};
@@ -659,13 +692,14 @@ struct SwitchStatementBuilder final : public Castable<SwitchStatementBuilder, St
auto reversed_cases = cases;
std::reverse(reversed_cases.begin(), reversed_cases.end());
- return builder->create<ast::SwitchStatement>(Source{}, condition, reversed_cases);
+ return builder->create<ast::SwitchStatement>(Source{}, condition,
+ std::move(reversed_cases));
}
/// Switch statement condition
const ast::Expression* const condition;
/// Switch statement cases
- ast::CaseStatementList cases;
+ utils::Vector<ast::CaseStatement*, 4> cases;
};
/// A StatementBuilder for ast::IfStatement
@@ -711,9 +745,9 @@ struct LoopStatementBuilder final : public Castable<LoopStatementBuilder, Statem
/// @param decos a list of parsed decorations
/// @returns true if the decorations include a SampleMask builtin
-bool HasBuiltinSampleMask(const ast::AttributeList& decos) {
+bool HasBuiltinSampleMask(utils::VectorRef<const ast::Attribute*> decos) {
if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(decos)) {
- return builtin->builtin == ast::Builtin::kSampleMask;
+ return builtin->builtin == ast::BuiltinValue::kSampleMask;
}
return false;
}
@@ -725,9 +759,13 @@ BlockInfo::BlockInfo(const spvtools::opt::BasicBlock& bb) : basic_block(&bb), id
BlockInfo::~BlockInfo() = default;
DefInfo::DefInfo(const spvtools::opt::Instruction& def_inst,
+ bool the_locally_defined,
uint32_t the_block_pos,
size_t the_index)
- : inst(def_inst), block_pos(the_block_pos), index(the_index) {}
+ : inst(def_inst),
+ locally_defined(the_locally_defined),
+ block_pos(the_block_pos),
+ index(the_index) {}
DefInfo::~DefInfo() = default;
@@ -771,7 +809,7 @@ FunctionEmitter::FunctionEmitter(FunctionEmitter&& other)
sample_mask_in_id(other.sample_mask_out_id),
sample_mask_out_id(other.sample_mask_in_id),
ep_info_(other.ep_info_) {
- other.statements_stack_.clear();
+ other.statements_stack_.Clear();
PushNewStatementBlock(nullptr, 0, nullptr);
}
@@ -789,7 +827,7 @@ FunctionEmitter::StatementBlock::~StatementBlock() = default;
void FunctionEmitter::StatementBlock::Finalize(ProgramBuilder* pb) {
TINT_ASSERT(Reader, !finalized_ /* Finalize() must only be called once */);
- for (size_t i = 0; i < statements_.size(); i++) {
+ for (size_t i = 0; i < statements_.Length(); i++) {
if (auto* sb = statements_[i]->As<StatementBuilder>()) {
statements_[i] = sb->Build(pb);
}
@@ -804,64 +842,64 @@ void FunctionEmitter::StatementBlock::Finalize(ProgramBuilder* pb) {
void FunctionEmitter::StatementBlock::Add(const ast::Statement* statement) {
TINT_ASSERT(Reader, !finalized_ /* Add() must not be called after Finalize() */);
- statements_.emplace_back(statement);
+ statements_.Push(statement);
}
void FunctionEmitter::PushNewStatementBlock(const Construct* construct,
uint32_t end_id,
CompletionAction action) {
- statements_stack_.emplace_back(StatementBlock{construct, end_id, action});
+ statements_stack_.Push(StatementBlock{construct, end_id, action});
}
void FunctionEmitter::PushGuard(const std::string& guard_name, uint32_t end_id) {
- TINT_ASSERT(Reader, !statements_stack_.empty());
+ TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
TINT_ASSERT(Reader, !guard_name.empty());
// Guard control flow by the guard variable. Introduce a new
// if-selection with a then-clause ending at the same block
// as the statement block at the top of the stack.
- const auto& top = statements_stack_.back();
+ const auto& top = statements_stack_.Back();
auto* cond =
create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(guard_name));
auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
- PushNewStatementBlock(top.GetConstruct(), end_id, [=](const ast::StatementList& stmts) {
+ PushNewStatementBlock(top.GetConstruct(), end_id, [=](const StatementList& stmts) {
builder->body = create<ast::BlockStatement>(Source{}, stmts);
});
}
void FunctionEmitter::PushTrueGuard(uint32_t end_id) {
- TINT_ASSERT(Reader, !statements_stack_.empty());
- const auto& top = statements_stack_.back();
+ TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+ const auto& top = statements_stack_.Back();
auto* cond = MakeTrue(Source{});
auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
- PushNewStatementBlock(top.GetConstruct(), end_id, [=](const ast::StatementList& stmts) {
+ PushNewStatementBlock(top.GetConstruct(), end_id, [=](const StatementList& stmts) {
builder->body = create<ast::BlockStatement>(Source{}, stmts);
});
}
-const ast::StatementList FunctionEmitter::ast_body() {
- TINT_ASSERT(Reader, !statements_stack_.empty());
+FunctionEmitter::StatementList FunctionEmitter::ast_body() {
+ TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
auto& entry = statements_stack_[0];
entry.Finalize(&builder_);
return entry.GetStatements();
}
const ast::Statement* FunctionEmitter::AddStatement(const ast::Statement* statement) {
- TINT_ASSERT(Reader, !statements_stack_.empty());
+ TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
if (statement != nullptr) {
- statements_stack_.back().Add(statement);
+ statements_stack_.Back().Add(statement);
}
return statement;
}
const ast::Statement* FunctionEmitter::LastStatement() {
- TINT_ASSERT(Reader, !statements_stack_.empty());
- auto& statement_list = statements_stack_.back().GetStatements();
- TINT_ASSERT(Reader, !statement_list.empty());
- return statement_list.back();
+ TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+ auto& statement_list = statements_stack_.Back().GetStatements();
+ TINT_ASSERT(Reader, !statement_list.IsEmpty());
+ return statement_list.Back();
}
bool FunctionEmitter::Emit() {
@@ -900,10 +938,9 @@ bool FunctionEmitter::Emit() {
return false;
}
- builder_.AST().AddFunction(
- create<ast::Function>(decl.source, builder_.Symbols().Register(decl.name),
- std::move(decl.params), decl.return_type->Build(builder_), body,
- std::move(decl.attributes), ast::AttributeList{}));
+ builder_.AST().AddFunction(create<ast::Function>(
+ decl.source, builder_.Symbols().Register(decl.name), std::move(decl.params),
+ decl.return_type->Build(builder_), body, std::move(decl.attributes), utils::Empty));
}
if (ep_info_ && !ep_info_->inner_name.empty()) {
@@ -914,17 +951,17 @@ bool FunctionEmitter::Emit() {
}
const ast::BlockStatement* FunctionEmitter::MakeFunctionBody() {
- TINT_ASSERT(Reader, statements_stack_.size() == 1);
+ TINT_ASSERT(Reader, statements_stack_.Length() == 1);
if (!EmitBody()) {
return nullptr;
}
// Set the body of the AST function node.
- if (statements_stack_.size() != 1) {
+ if (statements_stack_.Length() != 1) {
Fail() << "internal error: statement-list stack should have 1 "
"element but has "
- << statements_stack_.size();
+ << statements_stack_.Length();
return nullptr;
}
@@ -933,7 +970,7 @@ const ast::BlockStatement* FunctionEmitter::MakeFunctionBody() {
auto* body = create<ast::BlockStatement>(Source{}, statements);
// Maintain the invariant by repopulating the one and only element.
- statements_stack_.clear();
+ statements_stack_.Clear();
PushNewStatementBlock(constructs_[0].get(), 0, nullptr);
return body;
@@ -941,12 +978,12 @@ const ast::BlockStatement* FunctionEmitter::MakeFunctionBody() {
bool FunctionEmitter::EmitPipelineInput(std::string var_name,
const Type* var_type,
- ast::AttributeList* attrs,
- std::vector<int> index_prefix,
+ AttributeList* attrs,
+ utils::Vector<int, 8> index_prefix,
const Type* tip_type,
const Type* forced_param_type,
- ast::VariableList* params,
- ast::StatementList* statements) {
+ ParameterList* params,
+ StatementList* statements) {
// TODO(dneto): Handle structs where the locations are annotated on members.
tip_type = tip_type->UnwrapAlias();
if (auto* ref_type = tip_type->As<Reference>()) {
@@ -957,11 +994,11 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
return Switch(
tip_type,
[&](const Matrix* matrix_type) -> bool {
- index_prefix.push_back(0);
+ index_prefix.Push(0);
const auto num_columns = static_cast<int>(matrix_type->columns);
const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
for (int col = 0; col < num_columns; col++) {
- index_prefix.back() = col;
+ index_prefix.Back() = col;
if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix, vec_ty,
forced_param_type, params, statements)) {
return false;
@@ -973,10 +1010,10 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
if (array_type->size == 0) {
return Fail() << "runtime-size array not allowed on pipeline IO";
}
- index_prefix.push_back(0);
+ index_prefix.Push(0);
const Type* elem_ty = array_type->type;
for (int i = 0; i < static_cast<int>(array_type->size); i++) {
- index_prefix.back() = i;
+ index_prefix.Back() = i;
if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix, elem_ty,
forced_param_type, params, statements)) {
return false;
@@ -986,12 +1023,14 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
},
[&](const Struct* struct_type) -> bool {
const auto& members = struct_type->members;
- index_prefix.push_back(0);
- for (int i = 0; i < static_cast<int>(members.size()); ++i) {
- index_prefix.back() = i;
- ast::AttributeList member_attrs(*attrs);
+ index_prefix.Push(0);
+ for (size_t i = 0; i < members.size(); ++i) {
+ index_prefix.Back() = static_cast<int>(i);
+ AttributeList member_attrs(*attrs);
if (!parser_impl_.ConvertPipelineDecorations(
- struct_type, parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
+ struct_type,
+ parser_impl_.GetMemberPipelineDecorations(*struct_type,
+ static_cast<int>(i)),
&member_attrs)) {
return false;
}
@@ -1000,7 +1039,8 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
return false;
}
// Copy the location as updated by nested expansion of the member.
- parser_impl_.SetLocation(attrs, GetLocation(member_attrs));
+ parser_impl_.SetLocation(attrs,
+ ast::GetAttribute<ast::LocationAttribute>(member_attrs));
}
return success();
},
@@ -1017,7 +1057,7 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
// disallowed but currently the SPIR-V reader will make duplicates when
// the entire AST is cloned at the top level of the SPIR-V reader flow.
// Consider rewriting this to avoid this node-sharing.
- params->push_back(builder_.Param(param_name, param_type->Build(builder_), *attrs));
+ params->Push(builder_.Param(param_name, param_type->Build(builder_), *attrs));
// Add a body statement to copy the parameter to the corresponding
// private variable.
@@ -1041,7 +1081,7 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
store_dest = builder_.MemberAccessor(
store_dest,
builder_.Expr(parser_impl_.GetMemberName(*struct_type, index)));
- current_type = struct_type->members[index];
+ current_type = struct_type->members[static_cast<size_t>(index)];
});
}
@@ -1052,7 +1092,7 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
create<ast::BitcastExpression>(tip_type->Build(builder_), param_value);
}
- statements->push_back(builder_.Assign(store_dest, param_value));
+ statements->Push(builder_.Assign(store_dest, param_value));
// Increment the location attribute, in case more parameters will
// follow.
@@ -1062,7 +1102,7 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
});
}
-void FunctionEmitter::IncrementLocation(ast::AttributeList* attributes) {
+void FunctionEmitter::IncrementLocation(AttributeList* attributes) {
for (auto*& attr : *attributes) {
if (auto* loc_attr = attr->As<ast::LocationAttribute>()) {
// Replace this location attribute with a new one with one higher index.
@@ -1073,23 +1113,14 @@ void FunctionEmitter::IncrementLocation(ast::AttributeList* attributes) {
}
}
-const ast::Attribute* FunctionEmitter::GetLocation(const ast::AttributeList& attributes) {
- for (auto* const& attr : attributes) {
- if (attr->Is<ast::LocationAttribute>()) {
- return attr;
- }
- }
- return nullptr;
-}
-
bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
const Type* var_type,
- ast::AttributeList* decos,
- std::vector<int> index_prefix,
+ AttributeList* decos,
+ utils::Vector<int, 8> index_prefix,
const Type* tip_type,
const Type* forced_member_type,
- ast::StructMemberList* return_members,
- ast::ExpressionList* return_exprs) {
+ StructMemberList* return_members,
+ ExpressionList* return_exprs) {
tip_type = tip_type->UnwrapAlias();
if (auto* ref_type = tip_type->As<Reference>()) {
tip_type = ref_type->type;
@@ -1099,12 +1130,12 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
return Switch(
tip_type,
[&](const Matrix* matrix_type) {
- index_prefix.push_back(0);
+ index_prefix.Push(0);
const auto num_columns = static_cast<int>(matrix_type->columns);
const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
for (int col = 0; col < num_columns; col++) {
- index_prefix.back() = col;
- if (!EmitPipelineOutput(var_name, var_type, decos, index_prefix, vec_ty,
+ index_prefix.Back() = col;
+ if (!EmitPipelineOutput(var_name, var_type, std::move(decos), index_prefix, vec_ty,
forced_member_type, return_members, return_exprs)) {
return false;
}
@@ -1115,11 +1146,11 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
if (array_type->size == 0) {
return Fail() << "runtime-size array not allowed on pipeline IO";
}
- index_prefix.push_back(0);
+ index_prefix.Push(0);
const Type* elem_ty = array_type->type;
for (int i = 0; i < static_cast<int>(array_type->size); i++) {
- index_prefix.back() = i;
- if (!EmitPipelineOutput(var_name, var_type, decos, index_prefix, elem_ty,
+ index_prefix.Back() = i;
+ if (!EmitPipelineOutput(var_name, var_type, std::move(decos), index_prefix, elem_ty,
forced_member_type, return_members, return_exprs)) {
return false;
}
@@ -1128,21 +1159,23 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
},
[&](const Struct* struct_type) -> bool {
const auto& members = struct_type->members;
- index_prefix.push_back(0);
+ index_prefix.Push(0);
for (int i = 0; i < static_cast<int>(members.size()); ++i) {
- index_prefix.back() = i;
- ast::AttributeList member_attrs(*decos);
+ index_prefix.Back() = i;
+ AttributeList member_attrs(*decos);
if (!parser_impl_.ConvertPipelineDecorations(
struct_type, parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
&member_attrs)) {
return false;
}
- if (!EmitPipelineOutput(var_name, var_type, &member_attrs, index_prefix, members[i],
- forced_member_type, return_members, return_exprs)) {
+ if (!EmitPipelineOutput(var_name, var_type, &member_attrs, index_prefix,
+ members[static_cast<size_t>(i)], forced_member_type,
+ return_members, return_exprs)) {
return false;
}
// Copy the location as updated by nested expansion of the member.
- parser_impl_.SetLocation(decos, GetLocation(member_attrs));
+ parser_impl_.SetLocation(decos,
+ ast::GetAttribute<ast::LocationAttribute>(member_attrs));
}
return success();
},
@@ -1160,7 +1193,7 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
// disallowed but currently the SPIR-V reader will make duplicates when
// the entire AST is cloned at the top level of the SPIR-V reader flow.
// Consider rewriting this to avoid this node-sharing.
- return_members->push_back(
+ return_members->Push(
builder_.Member(member_name, member_type->Build(builder_), *decos));
// Create an expression to evaluate the part of the variable indexed by
@@ -1186,7 +1219,7 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
load_source = builder_.MemberAccessor(
load_source,
builder_.Expr(parser_impl_.GetMemberName(*struct_type, index)));
- current_type = struct_type->members[index];
+ current_type = struct_type->members[static_cast<size_t>(index)];
});
}
@@ -1196,7 +1229,7 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
load_source = create<ast::BitcastExpression>(forced_member_type->Build(builder_),
load_source);
}
- return_exprs->push_back(load_source);
+ return_exprs->Push(load_source);
// Increment the location attribute, in case more parameters will
// follow.
@@ -1210,7 +1243,7 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
Source source;
// The statements in the body.
- ast::StatementList stmts;
+ utils::Vector<const ast::Statement*, 8> stmts;
FunctionDeclaration decl;
decl.source = source;
@@ -1226,7 +1259,7 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
TINT_ASSERT(Reader, var->opcode() == SpvOpVariable);
auto* store_type = GetVariableStoreType(*var);
auto* forced_param_type = store_type;
- ast::AttributeList param_decos;
+ AttributeList param_decos;
if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_param_type, &param_decos,
true)) {
// This occurs, and is not an error, for the PointSize builtin.
@@ -1249,12 +1282,12 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
auto* sample_mask_array_type = store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
TINT_ASSERT(Reader, sample_mask_array_type);
ok = EmitPipelineInput(var_name, store_type, &param_decos, {0},
- sample_mask_array_type->type, forced_param_type, &(decl.params),
+ sample_mask_array_type->type, forced_param_type, &decl.params,
&stmts);
} else {
// The normal path.
ok = EmitPipelineInput(var_name, store_type, &param_decos, {}, store_type,
- forced_param_type, &(decl.params), &stmts);
+ forced_param_type, &decl.params, &stmts);
}
if (!ok) {
return false;
@@ -1262,15 +1295,15 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
}
// Call the inner function. It has no parameters.
- stmts.push_back(create<ast::CallStatement>(
+ stmts.Push(create<ast::CallStatement>(
source,
create<ast::CallExpression>(source,
create<ast::IdentifierExpression>(
source, builder_.Symbols().Register(ep_info_->inner_name)),
- ast::ExpressionList{})));
+ utils::Empty)));
// Pipeline outputs are mapped to the return value.
- if (ep_info_->outputs.empty()) {
+ if (ep_info_->outputs.IsEmpty()) {
// There is nothing to return.
return_type = ty_.Void()->Build(builder_);
} else {
@@ -1281,8 +1314,8 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
const auto return_struct_sym = builder_.Symbols().Register(return_struct_name);
// Define the structure.
- std::vector<const ast::StructMember*> return_members;
- ast::ExpressionList return_exprs;
+ StructMemberList return_members;
+ ExpressionList return_exprs;
const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
@@ -1291,13 +1324,13 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
// The SPIR-V gl_PerVertex variable has already been remapped to
// a gl_Position variable. Substitute the type.
const Type* param_type = ty_.Vector(ty_.F32(), 4);
- ast::AttributeList out_decos{
- create<ast::BuiltinAttribute>(source, ast::Builtin::kPosition)};
+ AttributeList out_decos{
+ create<ast::BuiltinAttribute>(source, ast::BuiltinValue::kPosition)};
const auto var_name = namer_.GetName(var_id);
- return_members.push_back(
+ return_members.Push(
builder_.Member(var_name, param_type->Build(builder_), out_decos));
- return_exprs.push_back(builder_.Expr(var_name));
+ return_exprs.Push(builder_.Expr(var_name));
} else {
const auto* var = def_use_mgr_->GetDef(var_id);
@@ -1305,7 +1338,7 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
TINT_ASSERT(Reader, var->opcode() == SpvOpVariable);
const Type* store_type = GetVariableStoreType(*var);
const Type* forced_member_type = store_type;
- ast::AttributeList out_decos;
+ AttributeList out_decos;
if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_member_type,
&out_decos, true)) {
// This occurs, and is not an error, for the PointSize builtin.
@@ -1338,26 +1371,26 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
}
}
- if (return_members.empty()) {
+ if (return_members.IsEmpty()) {
// This can occur if only the PointSize member is accessed, because we
// never emit it.
return_type = ty_.Void()->Build(builder_);
} else {
// Create and register the result type.
- auto* str = create<ast::Struct>(Source{}, return_struct_sym, return_members,
- ast::AttributeList{});
+ auto* str =
+ create<ast::Struct>(Source{}, return_struct_sym, return_members, AttributeList{});
parser_impl_.AddTypeDecl(return_struct_sym, str);
return_type = builder_.ty.Of(str);
// Add the return-value statement.
- stmts.push_back(create<ast::ReturnStatement>(
+ stmts.Push(create<ast::ReturnStatement>(
source, builder_.Construct(source, return_type, std::move(return_exprs))));
}
}
auto* body = create<ast::BlockStatement>(source, stmts);
- ast::AttributeList fn_attrs;
- fn_attrs.emplace_back(create<ast::StageAttribute>(source, ep_info_->stage));
+ AttributeList fn_attrs;
+ fn_attrs.Push(create<ast::StageAttribute>(source, ep_info_->stage));
if (ep_info_->stage == ast::PipelineStage::kCompute) {
auto& size = ep_info_->workgroup_size;
@@ -1365,13 +1398,13 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
const ast::Expression* x = builder_.Expr(i32(size.x));
const ast::Expression* y = size.y ? builder_.Expr(i32(size.y)) : nullptr;
const ast::Expression* z = size.z ? builder_.Expr(i32(size.z)) : nullptr;
- fn_attrs.emplace_back(create<ast::WorkgroupAttribute>(Source{}, x, y, z));
+ fn_attrs.Push(create<ast::WorkgroupAttribute>(Source{}, x, y, z));
}
}
builder_.AST().AddFunction(create<ast::Function>(
source, builder_.Symbols().Register(ep_info_->name), std::move(decl.params), return_type,
- body, std::move(fn_attrs), ast::AttributeList{}));
+ body, std::move(fn_attrs), AttributeList{}));
return true;
}
@@ -1395,15 +1428,13 @@ bool FunctionEmitter::ParseFunctionDeclaration(FunctionDeclaration* decl) {
<< function_.result_id();
}
- ast::VariableList ast_params;
+ ParameterList ast_params;
function_.ForEachParam([this, &ast_params](const spvtools::opt::Instruction* param) {
auto* type = parser_impl_.ConvertType(param->type_id());
if (type != nullptr) {
- auto* ast_param =
- parser_impl_.MakeVariable(param->result_id(), ast::StorageClass::kNone, type, true,
- false, nullptr, ast::AttributeList{});
+ auto* ast_param = parser_impl_.MakeParameter(param->result_id(), type, AttributeList{});
// Parameters are treated as const declarations.
- ast_params.emplace_back(ast_param);
+ ast_params.Push(ast_param);
// The value is accessible by name.
identifier_types_.emplace(param->result_id(), type);
} else {
@@ -1417,7 +1448,7 @@ bool FunctionEmitter::ParseFunctionDeclaration(FunctionDeclaration* decl) {
decl->name = name;
decl->params = std::move(ast_params);
decl->return_type = ret_ty;
- decl->attributes.clear();
+ decl->attributes.Clear();
return success();
}
@@ -1726,11 +1757,11 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
// haven't reached the backedge block.
TINT_ASSERT(Reader, block_order_.size() > 0);
- constructs_.clear();
+ constructs_.Clear();
const auto entry_id = block_order_[0];
// The stack of enclosing constructs.
- std::vector<Construct*> enclosing;
+ utils::Vector<Construct*, 4> enclosing;
// Creates a control flow construct and pushes it onto the stack.
// Its parent is the top of the stack, or nullptr if the stack is empty.
@@ -1740,7 +1771,7 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
const auto begin_pos = GetBlockInfo(begin_id)->pos;
const auto end_pos =
end_id == 0 ? uint32_t(block_order_.size()) : GetBlockInfo(end_id)->pos;
- const auto* parent = enclosing.empty() ? nullptr : enclosing.back();
+ const auto* parent = enclosing.IsEmpty() ? nullptr : enclosing.Back();
auto scope_end_pos = end_pos;
// A loop construct is added right after its associated continue construct.
// In that case, adjust the parent up.
@@ -1750,11 +1781,10 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
scope_end_pos = parent->end_pos;
parent = parent->parent;
}
- constructs_.push_back(std::make_unique<Construct>(parent, static_cast<int>(depth), k,
- begin_id, end_id, begin_pos, end_pos,
- scope_end_pos));
- Construct* result = constructs_.back().get();
- enclosing.push_back(result);
+ constructs_.Push(std::make_unique<Construct>(parent, static_cast<int>(depth), k, begin_id,
+ end_id, begin_pos, end_pos, scope_end_pos));
+ Construct* result = constructs_.Back().get();
+ enclosing.Push(result);
return result;
};
@@ -1769,19 +1799,19 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
auto* block_info = GetBlockInfo(block_id);
TINT_ASSERT(Reader, block_info);
- if (enclosing.empty()) {
+ if (enclosing.IsEmpty()) {
return Fail() << "internal error: too many merge blocks before block " << block_id;
}
- const Construct* top = enclosing.back();
+ const Construct* top = enclosing.Back();
while (block_id == top->end_id) {
// We've reached a predeclared end of the construct. Pop it off the
// stack.
- enclosing.pop_back();
- if (enclosing.empty()) {
+ enclosing.Pop();
+ if (enclosing.IsEmpty()) {
return Fail() << "internal error: too many merge blocks before block " << block_id;
}
- top = enclosing.back();
+ top = enclosing.Back();
}
const auto merge = block_info->merge_for_header;
@@ -1789,7 +1819,7 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
// The current block is a header.
const auto header = block_id;
const auto* header_info = block_info;
- const auto depth = 1 + top->depth;
+ const auto depth = static_cast<size_t>(1 + top->depth);
const auto ct = header_info->continue_for_header;
if (ct != 0) {
// The current block is a loop header.
@@ -1812,10 +1842,10 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
// If the loop header branches to two different blocks inside the loop
// construct, then the loop body should be modeled as an if-selection
// construct
- std::vector<uint32_t> targets;
+ utils::Vector<uint32_t, 4> targets;
header_info->basic_block->ForEachSuccessorLabel(
- [&targets](const uint32_t target) { targets.push_back(target); });
- if ((targets.size() == 2u) && targets[0] != targets[1]) {
+ [&targets](const uint32_t target) { targets.Push(target); });
+ if ((targets.Length() == 2u) && targets[0] != targets[1]) {
const auto target0_pos = GetBlockInfo(targets[0])->pos;
const auto target1_pos = GetBlockInfo(targets[1])->pos;
if (top->ContainsPos(target0_pos) && top->ContainsPos(target1_pos)) {
@@ -1842,10 +1872,10 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
// At the end of the block list, we should only have the kFunction construct
// left.
- if (enclosing.size() != 1) {
+ if (enclosing.Length() != 1) {
return Fail() << "internal error: unbalanced structured constructs when "
"labeling structured constructs: ended with "
- << enclosing.size() - 1 << " unterminated constructs";
+ << enclosing.Length() - 1 << " unterminated constructs";
}
const auto* top = enclosing[0];
if (top->kind != Construct::kFunction || top->depth != 0) {
@@ -1906,8 +1936,8 @@ bool FunctionEmitter::FindSwitchCaseHeaders() {
default_block->default_is_merge = default_block->pos == construct->end_pos;
// Map a case target to the list of values selecting that case.
- std::unordered_map<uint32_t, std::vector<uint64_t>> block_to_values;
- std::vector<uint32_t> case_targets;
+ std::unordered_map<uint32_t, utils::Vector<uint64_t, 4>> block_to_values;
+ utils::Vector<uint32_t, 4> case_targets;
std::unordered_set<uint64_t> case_values;
// Process case targets.
@@ -1921,16 +1951,15 @@ bool FunctionEmitter::FindSwitchCaseHeaders() {
}
case_values.insert(value);
if (block_to_values.count(case_target_id) == 0) {
- case_targets.push_back(case_target_id);
+ case_targets.Push(case_target_id);
}
- block_to_values[case_target_id].push_back(value);
+ block_to_values[case_target_id].Push(value);
}
for (uint32_t case_target_id : case_targets) {
auto* case_block = GetBlockInfo(case_target_id);
- case_block->case_values =
- std::make_unique<std::vector<uint64_t>>(std::move(block_to_values[case_target_id]));
+ case_block->case_values = std::move(block_to_values[case_target_id]);
// A case target can't be a back-edge.
if (construct->begin_pos >= case_block->pos) {
@@ -2046,13 +2075,13 @@ bool FunctionEmitter::ClassifyCFGEdges() {
const auto& src_construct = *(src_info->construct);
// Compute the ordered list of unique successors.
- std::vector<uint32_t> successors;
+ utils::Vector<uint32_t, 4> successors;
{
std::unordered_set<uint32_t> visited;
src_info->basic_block->ForEachSuccessorLabel(
[&successors, &visited](const uint32_t succ) {
if (visited.count(succ) == 0) {
- successors.push_back(succ);
+ successors.Push(succ);
visited.insert(succ);
}
});
@@ -2066,10 +2095,10 @@ bool FunctionEmitter::ClassifyCFGEdges() {
// to have a merge instruction. We also track kIfBreak edges
// because when used with normal forward edges, we'll need
// to generate a flow guard variable.
- std::vector<uint32_t> normal_forward_edges;
- std::vector<uint32_t> if_break_edges;
+ utils::Vector<uint32_t, 4> normal_forward_edges;
+ utils::Vector<uint32_t, 4> if_break_edges;
- if (successors.empty() && src_construct.enclosing_continue) {
+ if (successors.IsEmpty() && src_construct.enclosing_continue) {
// Kill and return are not allowed in a continue construct.
return Fail() << "Invalid function exit at block " << src
<< " from continue construct starting at "
@@ -2184,10 +2213,10 @@ bool FunctionEmitter::ClassifyCFGEdges() {
if ((edge_kind == EdgeKind::kForward) ||
(edge_kind == EdgeKind::kCaseFallThrough)) {
- normal_forward_edges.push_back(dest);
+ normal_forward_edges.Push(dest);
}
if (edge_kind == EdgeKind::kIfBreak) {
- if_break_edges.push_back(dest);
+ if_break_edges.Push(dest);
}
if ((edge_kind == EdgeKind::kForward) ||
@@ -2249,13 +2278,13 @@ bool FunctionEmitter::ClassifyCFGEdges() {
if (num_backedges > 1) {
return Fail() << "Block " << src << " has too many backedges: " << num_backedges;
}
- if ((normal_forward_edges.size() > 1) && (src_info->merge_for_header == 0)) {
+ if ((normal_forward_edges.Length() > 1) && (src_info->merge_for_header == 0)) {
return Fail() << "Control flow diverges at block " << src << " (to "
<< normal_forward_edges[0] << ", " << normal_forward_edges[1]
<< ") but it is not a structured header (it has no merge "
"instruction)";
}
- if ((normal_forward_edges.size() + if_break_edges.size() > 1) &&
+ if ((normal_forward_edges.Length() + if_break_edges.Length() > 1) &&
(src_info->merge_for_header == 0)) {
// There is a branch to the merge of an if-selection combined
// with an other normal forward branch. Control within the
@@ -2464,9 +2493,8 @@ bool FunctionEmitter::EmitFunctionVariables() {
return false;
}
}
- auto* var =
- parser_impl_.MakeVariable(inst.result_id(), ast::StorageClass::kNone, var_store_type,
- false, false, constructor, ast::AttributeList{});
+ auto* var = parser_impl_.MakeVar(inst.result_id(), ast::StorageClass::kNone, var_store_type,
+ constructor, AttributeList{});
auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
AddStatement(var_decl_stmt);
auto* var_type = ty_.Reference(var_store_type, ast::StorageClass::kNone);
@@ -2589,7 +2617,7 @@ bool FunctionEmitter::EmitFunctionBodyStatements() {
// Upon entry, the statement stack has one entry representing the whole
// function.
- TINT_ASSERT(Reader, !constructs_.empty());
+ TINT_ASSERT(Reader, !constructs_.IsEmpty());
Construct* function_construct = constructs_[0].get();
TINT_ASSERT(Reader, function_construct != nullptr);
TINT_ASSERT(Reader, function_construct->kind == Construct::kFunction);
@@ -2597,7 +2625,7 @@ bool FunctionEmitter::EmitFunctionBodyStatements() {
// had not been computed at the time the entry was first created.
// TODO(dneto): refactor how the first construct is created vs.
// this statements stack entry is populated.
- TINT_ASSERT(Reader, statements_stack_.size() == 1);
+ TINT_ASSERT(Reader, statements_stack_.Length() == 1);
statements_stack_[0].SetConstruct(function_construct);
for (auto block_id : block_order()) {
@@ -2610,24 +2638,24 @@ bool FunctionEmitter::EmitFunctionBodyStatements() {
bool FunctionEmitter::EmitBasicBlock(const BlockInfo& block_info) {
// Close off previous constructs.
- while (!statements_stack_.empty() && (statements_stack_.back().GetEndId() == block_info.id)) {
- statements_stack_.back().Finalize(&builder_);
- statements_stack_.pop_back();
+ while (!statements_stack_.IsEmpty() && (statements_stack_.Back().GetEndId() == block_info.id)) {
+ statements_stack_.Back().Finalize(&builder_);
+ statements_stack_.Pop();
}
- if (statements_stack_.empty()) {
+ if (statements_stack_.IsEmpty()) {
return Fail() << "internal error: statements stack empty at block " << block_info.id;
}
// Enter new constructs.
- std::vector<const Construct*> entering_constructs; // inner most comes first
+ utils::Vector<const Construct*, 4> entering_constructs; // inner most comes first
{
auto* here = block_info.construct;
- auto* const top_construct = statements_stack_.back().GetConstruct();
+ auto* const top_construct = statements_stack_.Back().GetConstruct();
while (here != top_construct) {
// Only enter a construct at its header block.
if (here->begin_id == block_info.id) {
- entering_constructs.push_back(here);
+ entering_constructs.Push(here);
}
here = here->parent;
}
@@ -2683,10 +2711,10 @@ bool FunctionEmitter::EmitBasicBlock(const BlockInfo& block_info) {
// - We are entering 0 or 1 constructs, or
// - We are entering 2 constructs, with the outer one being a kContinue or
// kLoop, the inner one is not a continue.
- if (entering_constructs.size() > 2) {
+ if (entering_constructs.Length() > 2) {
return Fail() << "internal error: bad construct nesting found";
}
- if (entering_constructs.size() == 2) {
+ if (entering_constructs.Length() == 2) {
auto inner_kind = entering_constructs[0]->kind;
auto outer_kind = entering_constructs[1]->kind;
if (outer_kind != Construct::kContinue && outer_kind != Construct::kLoop) {
@@ -2858,9 +2886,9 @@ bool FunctionEmitter::EmitIfStart(const BlockInfo& block_info) {
// But make sure we do it in the right order.
auto push_else = [this, builder, else_end, construct, false_is_break, false_is_continue]() {
// Push the else clause onto the stack first.
- PushNewStatementBlock(construct, else_end, [=](const ast::StatementList& stmts) {
+ PushNewStatementBlock(construct, else_end, [=](const StatementList& stmts) {
// Only set the else-clause if there are statements to fill it.
- if (!stmts.empty()) {
+ if (!stmts.IsEmpty()) {
// The "else" consists of the statement list from the top of
// statements stack, without an "else if" condition.
builder->else_stmt = create<ast::BlockStatement>(Source{}, stmts);
@@ -2909,7 +2937,7 @@ bool FunctionEmitter::EmitIfStart(const BlockInfo& block_info) {
}
// Push the then clause onto the stack.
- PushNewStatementBlock(construct, then_end, [=](const ast::StatementList& stmts) {
+ PushNewStatementBlock(construct, then_end, [=](const StatementList& stmts) {
builder->body = create<ast::BlockStatement>(Source{}, stmts);
});
if (true_is_break) {
@@ -2946,17 +2974,17 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
// We will push statement-blocks onto the stack to gather the statements in
// the default clause and cases clauses. Determine the list of blocks
// that start each clause.
- std::vector<const BlockInfo*> clause_heads;
+ utils::Vector<const BlockInfo*, 4> clause_heads;
// Collect the case clauses, even if they are just the merge block.
// First the default clause.
const auto default_id = branch->GetSingleWordInOperand(1);
const auto* default_info = GetBlockInfo(default_id);
- clause_heads.push_back(default_info);
+ clause_heads.Push(default_info);
// Now the case clauses.
for (uint32_t iarg = 2; iarg + 1 < branch->NumInOperands(); iarg += 2) {
const auto case_target_id = branch->GetSingleWordInOperand(iarg + 1);
- clause_heads.push_back(GetBlockInfo(case_target_id));
+ clause_heads.Push(GetBlockInfo(case_target_id));
}
std::stable_sort(
@@ -2967,37 +2995,36 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
// Use read index r, and write index w.
// Invariant: w <= r;
size_t w = 0;
- for (size_t r = 0; r < clause_heads.size(); ++r) {
+ for (size_t r = 0; r < clause_heads.Length(); ++r) {
if (clause_heads[r] != clause_heads[w]) {
++w; // Advance the write cursor.
}
clause_heads[w] = clause_heads[r];
}
// We know it's not empty because it always has at least a default clause.
- TINT_ASSERT(Reader, !clause_heads.empty());
- clause_heads.resize(w + 1);
+ TINT_ASSERT(Reader, !clause_heads.IsEmpty());
+ clause_heads.Resize(w + 1);
}
// Push them on in reverse order.
- const auto last_clause_index = clause_heads.size() - 1;
+ const auto last_clause_index = clause_heads.Length() - 1;
for (size_t i = last_clause_index;; --i) {
// Create a list of integer literals for the selector values leading to
// this case clause.
- ast::CaseSelectorList selectors;
- const auto* values_ptr = clause_heads[i]->case_values.get();
- const bool has_selectors = (values_ptr && !values_ptr->empty());
+ utils::Vector<const ast::IntLiteralExpression*, 4> selectors;
+ const bool has_selectors = clause_heads[i]->case_values.has_value();
if (has_selectors) {
- std::vector<uint64_t> values(values_ptr->begin(), values_ptr->end());
+ auto values = clause_heads[i]->case_values.value();
std::stable_sort(values.begin(), values.end());
for (auto value : values) {
// The rest of this module can handle up to 64 bit switch values.
// The Tint AST handles 32-bit values.
const uint32_t value32 = uint32_t(value & 0xFFFFFFFF);
if (selector.type->IsUnsignedScalarOrVector()) {
- selectors.emplace_back(create<ast::IntLiteralExpression>(
+ selectors.Push(create<ast::IntLiteralExpression>(
Source{}, value32, ast::IntLiteralExpression::Suffix::kU));
} else {
- selectors.emplace_back(
+ selectors.Push(
create<ast::IntLiteralExpression>(Source{}, static_cast<int32_t>(value32),
ast::IntLiteralExpression::Suffix::kI));
}
@@ -3006,13 +3033,13 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
// Where does this clause end?
const auto end_id =
- (i + 1 < clause_heads.size()) ? clause_heads[i + 1]->id : construct->end_id;
+ (i + 1 < clause_heads.Length()) ? clause_heads[i + 1]->id : construct->end_id;
// Reserve the case clause slot in swch->cases, push the new statement block
// for the case, and fill the case clause once the block is generated.
- auto case_idx = swch->cases.size();
- swch->cases.emplace_back(nullptr);
- PushNewStatementBlock(construct, end_id, [=](const ast::StatementList& stmts) {
+ auto case_idx = swch->cases.Length();
+ swch->cases.Push(nullptr);
+ PushNewStatementBlock(construct, end_id, [=](const StatementList& stmts) {
auto* body = create<ast::BlockStatement>(Source{}, stmts);
swch->cases[case_idx] = create<ast::CaseStatement>(Source{}, selectors, body);
});
@@ -3021,11 +3048,11 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
construct->ContainsPos(default_info->pos)) {
// Generate a default clause with a just fallthrough.
auto* stmts = create<ast::BlockStatement>(
- Source{}, ast::StatementList{
+ Source{}, StatementList{
create<ast::FallthroughStatement>(Source{}),
});
- auto* case_stmt = create<ast::CaseStatement>(Source{}, ast::CaseSelectorList{}, stmts);
- swch->cases.emplace_back(case_stmt);
+ auto* case_stmt = create<ast::CaseStatement>(Source{}, utils::Empty, stmts);
+ swch->cases.Push(case_stmt);
}
if (i == 0) {
@@ -3038,7 +3065,7 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
bool FunctionEmitter::EmitLoopStart(const Construct* construct) {
auto* builder = AddStatementBuilder<LoopStatementBuilder>();
- PushNewStatementBlock(construct, construct->end_id, [=](const ast::StatementList& stmts) {
+ PushNewStatementBlock(construct, construct->end_id, [=](const StatementList& stmts) {
builder->body = create<ast::BlockStatement>(Source{}, stmts);
});
return success();
@@ -3053,7 +3080,7 @@ bool FunctionEmitter::EmitContinuingStart(const Construct* construct) {
return Fail() << "internal error: starting continue construct, "
"expected loop on top of stack";
}
- PushNewStatementBlock(construct, construct->end_id, [=](const ast::StatementList& stmts) {
+ PushNewStatementBlock(construct, construct->end_id, [=](const StatementList& stmts) {
loop->continuing = create<ast::BlockStatement>(Source{}, stmts);
});
@@ -3147,7 +3174,7 @@ bool FunctionEmitter::EmitNormalTerminator(const BlockInfo& block_info) {
AddStatement(MakeSimpleIf(cond, true_branch, false_branch));
if (!flow_guard.empty()) {
- PushGuard(flow_guard, statements_stack_.back().GetEndId());
+ PushGuard(flow_guard, statements_stack_.Back().GetEndId());
}
return true;
}
@@ -3247,15 +3274,15 @@ const ast::Statement* FunctionEmitter::MakeSimpleIf(const ast::Expression* condi
if ((then_stmt == nullptr) && (else_stmt == nullptr)) {
return nullptr;
}
- ast::StatementList if_stmts;
+ StatementList if_stmts;
if (then_stmt != nullptr) {
- if_stmts.emplace_back(then_stmt);
+ if_stmts.Push(then_stmt);
}
auto* if_block = create<ast::BlockStatement>(Source{}, if_stmts);
const ast::Statement* else_block = nullptr;
if (else_stmt) {
- else_block = create<ast::BlockStatement>(ast::StatementList{else_stmt});
+ else_block = create<ast::BlockStatement>(StatementList{else_stmt});
}
auto* if_stmt = create<ast::IfStatement>(Source{}, condition, if_block, else_block);
@@ -3309,7 +3336,7 @@ bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
return true;
}
// Returns the given list of local definition IDs, sorted by their index.
- auto sorted_by_index = [this](const std::vector<uint32_t>& ids) {
+ auto sorted_by_index = [this](auto& ids) {
auto sorted = ids;
std::stable_sort(sorted.begin(), sorted.end(),
[this](const uint32_t lhs, const uint32_t rhs) {
@@ -3324,8 +3351,8 @@ bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
TINT_ASSERT(Reader, def_inst);
auto* storage_type = RemapStorageClass(parser_impl_.ConvertType(def_inst->type_id()), id);
AddStatement(create<ast::VariableDeclStatement>(
- Source{}, parser_impl_.MakeVariable(id, ast::StorageClass::kNone, storage_type, false,
- false, nullptr, ast::AttributeList{})));
+ Source{}, parser_impl_.MakeVar(id, ast::StorageClass::kNone, storage_type, nullptr,
+ AttributeList{})));
auto* type = ty_.Reference(storage_type, ast::StorageClass::kNone);
identifier_types_.emplace(id, type);
}
@@ -3356,7 +3383,7 @@ bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
// Emit assignments to carry values to phi nodes in potential destinations.
// Do it in index order.
- if (!block_info.phi_assignments.empty()) {
+ if (!block_info.phi_assignments.IsEmpty()) {
auto sorted = block_info.phi_assignments;
std::stable_sort(
sorted.begin(), sorted.end(),
@@ -3392,13 +3419,11 @@ bool FunctionEmitter::EmitConstDefinition(const spvtools::opt::Instruction& inst
}
expr = AddressOfIfNeeded(expr, &inst);
- auto* ast_const =
- parser_impl_.MakeVariable(inst.result_id(), ast::StorageClass::kNone, expr.type, true,
- false, expr.expr, ast::AttributeList{});
- if (!ast_const) {
+ auto* let = parser_impl_.MakeLet(inst.result_id(), expr.type, expr.expr);
+ if (!let) {
return false;
}
- AddStatement(create<ast::VariableDeclStatement>(Source{}, ast_const));
+ AddStatement(create<ast::VariableDeclStatement>(Source{}, let));
identifier_types_.emplace(inst.result_id(), expr.type);
return success();
}
@@ -3487,6 +3512,10 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
return EmitImageAccess(inst);
}
+ if (IsAtomicOp(inst.opcode())) {
+ return EmitAtomicOp(inst);
+ }
+
switch (inst.opcode()) {
case SpvOpNop:
return true;
@@ -3773,8 +3802,8 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
const char* unary_builtin_name = GetUnaryBuiltInFunctionName(opcode);
if (unary_builtin_name != nullptr) {
- ast::ExpressionList params;
- params.emplace_back(MakeOperand(inst, 0).expr);
+ ExpressionList params;
+ params.Push(MakeOperand(inst, 0).expr);
return {ast_type, create<ast::CallExpression>(
Source{},
create<ast::IdentifierExpression>(
@@ -3852,9 +3881,9 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
}
if (opcode == SpvOpCompositeConstruct) {
- ast::ExpressionList operands;
+ ExpressionList operands;
for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
- operands.emplace_back(MakeOperand(inst, iarg).expr);
+ operands.Push(MakeOperand(inst, iarg).expr);
}
return {ast_type,
builder_.Construct(Source{}, ast_type->Build(builder_), std::move(operands))};
@@ -3922,7 +3951,7 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(const spvtools::opt::Inst
auto e1 = MakeOperand(inst, 2);
auto e2 = ToSignedIfUnsigned(MakeOperand(inst, 3));
- return {e1.type, builder_.Call(Source{}, "ldexp", ast::ExpressionList{e1.expr, e2.expr})};
+ return {e1.type, builder_.Call(Source{}, "ldexp", utils::Vector{e1.expr, e2.expr})};
}
auto* result_type = parser_impl_.ConvertType(inst.type_id());
@@ -3948,16 +3977,19 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(const spvtools::opt::Inst
TINT_ASSERT(Reader, normal.type->Is<F32>());
TINT_ASSERT(Reader, incident.type->Is<F32>());
TINT_ASSERT(Reader, nref.type->Is<F32>());
- return {ty_.F32(),
- builder_.Call(
- Source{}, "select",
- ast::ExpressionList{create<ast::UnaryOpExpression>(
- Source{}, ast::UnaryOp::kNegation, normal.expr),
- normal.expr,
- create<ast::BinaryExpression>(
- Source{}, ast::BinaryOp::kLessThan,
- builder_.Mul({}, incident.expr, nref.expr),
- builder_.Expr(0_f))})};
+ return {
+ ty_.F32(),
+ builder_.Call(
+ Source{}, "select",
+ utils::Vector{
+ create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kNegation,
+ normal.expr),
+ normal.expr,
+ create<ast::BinaryExpression>(
+ Source{}, ast::BinaryOp::kLessThan,
+ builder_.Mul({}, incident.expr, nref.expr), builder_.Expr(0_f)),
+ }),
+ };
}
case GLSLstd450Reflect: {
@@ -3988,13 +4020,17 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(const spvtools::opt::Inst
return {};
}
const Type* f32 = eta.type;
- return {f32, builder_.MemberAccessor(
- builder_.Call(
- Source{}, "refract",
- ast::ExpressionList{
- builder_.vec2<tint::f32>(incident.expr, 0_f),
- builder_.vec2<tint::f32>(normal.expr, 0_f), eta.expr}),
- "x")};
+ return {
+ f32,
+ builder_.MemberAccessor(
+ builder_.Call(Source{}, "refract",
+ utils::Vector{
+ builder_.vec2<tint::f32>(incident.expr, 0_f),
+ builder_.vec2<tint::f32>(normal.expr, 0_f),
+ eta.expr,
+ }),
+ "x"),
+ };
}
default:
break;
@@ -4008,7 +4044,7 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(const spvtools::opt::Inst
}
auto* func = create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
- ast::ExpressionList operands;
+ ExpressionList operands;
const Type* first_operand_type = nullptr;
// All parameters to GLSL.std.450 extended instructions are IDs.
for (uint32_t iarg = 2; iarg < inst.NumInOperands(); ++iarg) {
@@ -4016,7 +4052,7 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(const spvtools::opt::Inst
if (first_operand_type == nullptr) {
first_operand_type = operand.type;
}
- operands.emplace_back(operand.expr);
+ operands.Push(operand.expr);
}
auto* call = create<ast::CallExpression>(Source{}, func, std::move(operands));
TypedExpression call_expr{result_type, call};
@@ -4273,7 +4309,7 @@ TypedExpression FunctionEmitter::MakeCompositeExtract(const spvtools::opt::Instr
// This is structurally similar to creating an access chain, but
// the SPIR-V instruction has literal indices instead of IDs for indices.
- auto composite_index = 0;
+ auto composite_index = 0u;
auto first_index_position = 1;
TypedExpression current_expr(MakeOperand(inst, composite_index));
if (!current_expr) {
@@ -4317,13 +4353,14 @@ TypedExpression FunctionEmitter::MakeCompositeValueDecomposition(
// hierarchy, maintaining |current_type_id| as the SPIR-V ID of the type of
// the object pointed to after processing the previous indices.
const auto num_in_operands = inst.NumInOperands();
- for (uint32_t index = index_start; index < num_in_operands; ++index) {
+ for (uint32_t index = static_cast<uint32_t>(index_start); index < num_in_operands; ++index) {
const uint32_t index_val = inst.GetSingleWordInOperand(index);
const auto* current_type_inst = def_use_mgr_->GetDef(current_type_id);
if (!current_type_inst) {
Fail() << "composite type %" << current_type_id << " is invalid after following "
- << (index - index_start) << " indices: " << inst.PrettyPrint();
+ << (index - static_cast<uint32_t>(index_start))
+ << " indices: " << inst.PrettyPrint();
return {};
}
const char* operation_name = nullptr;
@@ -4442,7 +4479,7 @@ TypedExpression FunctionEmitter::MakeVectorShuffle(const spvtools::opt::Instruct
// Assume the literal indices are valid, and there is a valid number of them.
auto source = GetSourceForInst(inst);
const Vector* result_type = As<Vector>(parser_impl_.ConvertType(inst.type_id()));
- ast::ExpressionList values;
+ ExpressionList values;
for (uint32_t i = 2; i < inst.NumInOperands(); ++i) {
const auto index = inst.GetSingleWordInOperand(i);
if (index < vec0_len) {
@@ -4450,8 +4487,7 @@ TypedExpression FunctionEmitter::MakeVectorShuffle(const spvtools::opt::Instruct
if (!expr) {
return {};
}
- values.emplace_back(
- create<ast::MemberAccessorExpression>(source, expr.expr, Swizzle(index)));
+ values.Push(create<ast::MemberAccessorExpression>(source, expr.expr, Swizzle(index)));
} else if (index < vec0_len + vec1_len) {
const auto sub_index = index - vec0_len;
TINT_ASSERT(Reader, sub_index < kMaxVectorLen);
@@ -4459,18 +4495,19 @@ TypedExpression FunctionEmitter::MakeVectorShuffle(const spvtools::opt::Instruct
if (!expr) {
return {};
}
- values.emplace_back(
+ values.Push(
create<ast::MemberAccessorExpression>(source, expr.expr, Swizzle(sub_index)));
} else if (index == 0xFFFFFFFF) {
// By rule, this maps to OpUndef. Instead, make it zero.
- values.emplace_back(parser_impl_.MakeNullValue(result_type->type));
+ values.Push(parser_impl_.MakeNullValue(result_type->type));
} else {
Fail() << "invalid vectorshuffle ID %" << inst.result_id()
<< ": index too large: " << index;
return {};
}
}
- return {result_type, builder_.Construct(source, result_type->Build(builder_), values)};
+ return {result_type,
+ builder_.Construct(source, result_type->Build(builder_), std::move(values))};
}
bool FunctionEmitter::RegisterSpecialBuiltInVariables() {
@@ -4479,9 +4516,10 @@ bool FunctionEmitter::RegisterSpecialBuiltInVariables() {
const auto id = special_var.first;
const auto builtin = special_var.second;
const auto* var = def_use_mgr_->GetDef(id);
- def_info_[id] = std::make_unique<DefInfo>(*var, 0, index);
+ def_info_[id] = std::make_unique<DefInfo>(*var, false, 0, index);
++index;
auto& def = def_info_[id];
+ // Builtins are always defined outside the function.
switch (builtin) {
case SpvBuiltInPointSize:
def->skip = SkipReason::kPointSizeBuiltinPointer;
@@ -4526,7 +4564,7 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
if ((result_id == 0) || inst.opcode() == SpvOpLabel) {
continue;
}
- def_info_[result_id] = std::make_unique<DefInfo>(inst, block_pos, index);
+ def_info_[result_id] = std::make_unique<DefInfo>(inst, true, block_pos, index);
++index;
auto& info = def_info_[result_id];
@@ -4612,7 +4650,7 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
// but only if they are defined in this function as well.
auto require_named_const_def = [&](const spvtools::opt::Instruction& inst,
int in_operand_index) {
- const auto id = inst.GetSingleWordInOperand(in_operand_index);
+ const auto id = inst.GetSingleWordInOperand(static_cast<uint32_t>(in_operand_index));
auto* const operand_def = GetDefInfo(id);
if (operand_def) {
operand_def->requires_named_const_def = true;
@@ -4690,7 +4728,7 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
if (IsInBlockOrder(pred_block_info)) {
// Record the assignment that needs to occur at the end
// of the predecessor block.
- pred_block_info->phi_assignments.push_back({phi_id, value_id});
+ pred_block_info->phi_assignments.Push({phi_id, value_id});
first_pos = std::min(first_pos, pred_block_info->pos);
last_pos = std::max(last_pos, pred_block_info->pos);
}
@@ -4698,8 +4736,7 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
// Schedule the declaration of the state variable.
const auto* enclosing_construct = GetEnclosingScope(first_pos, last_pos);
- GetBlockInfo(enclosing_construct->begin_id)
- ->phis_needing_state_vars.push_back(phi_id);
+ GetBlockInfo(enclosing_construct->begin_id)->phis_needing_state_vars.Push(phi_id);
}
}
}
@@ -4722,6 +4759,13 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
// There is no need to adjust the location of the declaration.
continue;
}
+ if (!def_info->locally_defined) {
+ // Never hoist a variable declared at module scope.
+ // This occurs for builtin variables, which are mapped to module-scope
+ // private variables.
+ continue;
+ }
+
// The first use must be the at the SSA definition, because block order
// respects dominance.
const auto first_pos = def_info->block_pos;
@@ -4763,7 +4807,7 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
// TODO(dneto): Handle non-storable types, particularly pointers.
def_info->requires_hoisted_def = true;
auto* hoist_to_block = GetBlockInfo(enclosing_construct->begin_id);
- hoist_to_block->hoisted_ids.push_back(def_id);
+ hoist_to_block->hoisted_ids.Push(def_id);
}
}
}
@@ -4825,8 +4869,8 @@ TypedExpression FunctionEmitter::MakeNumericConversion(const spvtools::opt::Inst
return {};
}
- ast::ExpressionList params;
- params.push_back(arg_expr.expr);
+ ExpressionList params;
+ params.Push(arg_expr.expr);
TypedExpression result{
expr_type,
builder_.Construct(GetSourceForInst(inst), expr_type->Build(builder_), std::move(params))};
@@ -4844,7 +4888,7 @@ bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
auto name = namer_.Name(inst.GetSingleWordInOperand(0));
auto* function = create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
- ast::ExpressionList args;
+ ExpressionList args;
for (uint32_t iarg = 1; iarg < inst.NumInOperands(); ++iarg) {
auto expr = MakeOperand(inst, iarg);
if (!expr) {
@@ -4853,7 +4897,7 @@ bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
// Functions cannot use references as parameters, so we need to pass by
// pointer if the operand is of pointer type.
expr = AddressOfIfNeeded(expr, def_use_mgr_->GetDef(inst.GetSingleWordInOperand(iarg)));
- args.emplace_back(expr.expr);
+ args.Push(expr.expr);
}
if (failed()) {
return false;
@@ -4873,7 +4917,7 @@ bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
bool FunctionEmitter::EmitControlBarrier(const spvtools::opt::Instruction& inst) {
uint32_t operands[3];
- for (int i = 0; i < 3; i++) {
+ for (uint32_t i = 0; i < 3; i++) {
auto id = inst.GetSingleWordInOperand(i);
if (auto* constant = constant_mgr_->FindDeclaredConstant(id)) {
operands[i] = constant->GetU32();
@@ -4891,7 +4935,7 @@ bool FunctionEmitter::EmitControlBarrier(const spvtools::opt::Instruction& inst)
<< "expected Workgroup (2), got: " << execution;
}
if (semantics & SpvMemorySemanticsAcquireReleaseMask) {
- semantics &= ~SpvMemorySemanticsAcquireReleaseMask;
+ semantics &= ~static_cast<uint32_t>(SpvMemorySemanticsAcquireReleaseMask);
} else {
return Fail() << "control barrier semantics requires acquire and release";
}
@@ -4900,14 +4944,14 @@ bool FunctionEmitter::EmitControlBarrier(const spvtools::opt::Instruction& inst)
return Fail() << "workgroupBarrier requires workgroup memory scope";
}
AddStatement(create<ast::CallStatement>(builder_.Call("workgroupBarrier")));
- semantics &= ~SpvMemorySemanticsWorkgroupMemoryMask;
+ semantics &= ~static_cast<uint32_t>(SpvMemorySemanticsWorkgroupMemoryMask);
}
if (semantics & SpvMemorySemanticsUniformMemoryMask) {
if (memory != SpvScopeDevice) {
return Fail() << "storageBarrier requires device memory scope";
}
AddStatement(create<ast::CallStatement>(builder_.Call("storageBarrier")));
- semantics &= ~SpvMemorySemanticsUniformMemoryMask;
+ semantics &= ~static_cast<uint32_t>(SpvMemorySemanticsUniformMemoryMask);
}
if (semantics) {
return Fail() << "unsupported control barrier semantics: " << semantics;
@@ -4920,14 +4964,14 @@ TypedExpression FunctionEmitter::MakeBuiltinCall(const spvtools::opt::Instructio
auto* name = sem::str(builtin);
auto* ident = create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
- ast::ExpressionList params;
+ ExpressionList params;
const Type* first_operand_type = nullptr;
for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
TypedExpression operand = MakeOperand(inst, iarg);
if (first_operand_type == nullptr) {
first_operand_type = operand.type;
}
- params.emplace_back(operand.expr);
+ params.Push(operand.expr);
}
auto* call_expr = create<ast::CallExpression>(Source{}, ident, std::move(params));
auto* result_type = parser_impl_.ConvertType(inst.type_id());
@@ -4952,11 +4996,11 @@ TypedExpression FunctionEmitter::MakeSimpleSelect(const spvtools::opt::Instructi
auto* op_ty = true_value.type;
if (op_ty->Is<Vector>() || op_ty->IsFloatScalar() || op_ty->IsIntegerScalar() ||
op_ty->Is<Bool>()) {
- ast::ExpressionList params;
- params.push_back(false_value.expr);
- params.push_back(true_value.expr);
+ ExpressionList params;
+ params.Push(false_value.expr);
+ params.Push(true_value.expr);
// The condition goes last.
- params.push_back(condition.expr);
+ params.Push(condition.expr);
return {op_ty,
create<ast::CallExpression>(Source{},
create<ast::IdentifierExpression>(
@@ -5031,7 +5075,7 @@ const ast::Expression* FunctionEmitter::GetSamplerExpression(
}
bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
- ast::ExpressionList args;
+ ExpressionList args;
const auto opcode = inst.opcode();
// Form the texture operand.
@@ -5039,13 +5083,13 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
if (!image) {
return false;
}
- args.push_back(GetImageExpression(inst));
+ args.Push(GetImageExpression(inst));
// Form the sampler operand, if needed.
if (IsSampledImageAccess(opcode)) {
// Form the sampler operand.
if (auto* sampler = GetSamplerExpression(inst)) {
- args.push_back(sampler);
+ args.Push(sampler);
} else {
return false;
}
@@ -5067,10 +5111,12 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
// Push the coordinates operands.
auto coords = MakeCoordinateOperandsForImageAccess(inst);
- if (coords.empty()) {
+ if (coords.IsEmpty()) {
return false;
}
- args.insert(args.end(), coords.begin(), coords.end());
+ for (auto* coord : coords) {
+ args.Push(coord);
+ }
// Skip the coordinates operand.
arg_index++;
@@ -5080,7 +5126,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
// the parameter list. Issues a diagnostic and returns false on error.
auto consume_dref = [&]() -> bool {
if (arg_index < num_args) {
- args.push_back(MakeOperand(inst, arg_index).expr);
+ args.Push(MakeOperand(inst, arg_index).expr);
arg_index++;
} else {
return Fail() << "image depth-compare instruction is missing a Dref operand: "
@@ -5117,7 +5163,12 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
builtin_name = "textureGather";
if (!texture_type->Is<DepthTexture>()) {
// The explicit component is the *first* argument in WGSL.
- args.insert(args.begin(), ToI32(MakeOperand(inst, arg_index)).expr);
+ ExpressionList gather_args;
+ gather_args.Push(ToI32(MakeOperand(inst, arg_index)).expr);
+ for (auto* arg : args) {
+ gather_args.Push(arg);
+ }
+ args = std::move(gather_args);
}
// Skip over the component operand, even for depth textures.
arg_index++;
@@ -5145,7 +5196,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
return false;
}
- args.push_back(converted_texel);
+ args.Push(converted_texel);
arg_index++;
} else {
return Fail() << "image write is missing a Texel operand: " << inst.PrettyPrint();
@@ -5174,7 +5225,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
<< inst.PrettyPrint();
}
builtin_name += "Bias";
- args.push_back(MakeOperand(inst, arg_index).expr);
+ args.Push(MakeOperand(inst, arg_index).expr);
image_operands_mask ^= SpvImageOperandsBiasMask;
arg_index++;
}
@@ -5201,7 +5252,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
// Convert it to a signed integer type.
lod = ToI32(lod);
}
- args.push_back(lod.expr);
+ args.Push(lod.expr);
}
image_operands_mask ^= SpvImageOperandsLodMask;
@@ -5210,7 +5261,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
!texture_type->IsAnyOf<DepthMultisampledTexture, MultisampledTexture>()) {
// textureLoad requires an explicit level-of-detail parameter for
// non-multisampled texture types.
- args.push_back(parser_impl_.MakeNullValue(ty_.I32()));
+ args.Push(parser_impl_.MakeNullValue(ty_.I32()));
}
if (arg_index + 1 < num_args && (image_operands_mask & SpvImageOperandsGradMask)) {
if (is_dref_sample) {
@@ -5224,8 +5275,8 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
<< inst.PrettyPrint();
}
builtin_name += "Grad";
- args.push_back(MakeOperand(inst, arg_index).expr);
- args.push_back(MakeOperand(inst, arg_index + 1).expr);
+ args.Push(MakeOperand(inst, arg_index).expr);
+ args.Push(MakeOperand(inst, arg_index + 1).expr);
image_operands_mask ^= SpvImageOperandsGradMask;
arg_index += 2;
}
@@ -5246,13 +5297,13 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
<< inst.PrettyPrint();
}
- args.push_back(ToSignedIfUnsigned(MakeOperand(inst, arg_index)).expr);
+ args.Push(ToSignedIfUnsigned(MakeOperand(inst, arg_index)).expr);
image_operands_mask ^= SpvImageOperandsConstOffsetMask;
arg_index++;
}
if (arg_index < num_args && (image_operands_mask & SpvImageOperandsSampleMask)) {
// TODO(dneto): only permitted with ImageFetch
- args.push_back(ToI32(MakeOperand(inst, arg_index)).expr);
+ args.Push(ToI32(MakeOperand(inst, arg_index)).expr);
image_operands_mask ^= SpvImageOperandsSampleMask;
arg_index++;
}
@@ -5294,12 +5345,14 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
// first component.
if (texture_type->IsAnyOf<DepthTexture, DepthMultisampledTexture>()) {
if (is_non_dref_sample || (opcode == SpvOpImageFetch)) {
- value = builder_.Construct(
- Source{},
- result_type->Build(builder_), // a vec4
- ast::ExpressionList{value, parser_impl_.MakeNullValue(result_component_type),
- parser_impl_.MakeNullValue(result_component_type),
- parser_impl_.MakeNullValue(result_component_type)});
+ value = builder_.Construct(Source{},
+ result_type->Build(builder_), // a vec4
+ utils::Vector{
+ value,
+ parser_impl_.MakeNullValue(result_component_type),
+ parser_impl_.MakeNullValue(result_component_type),
+ parser_impl_.MakeNullValue(result_component_type),
+ });
}
}
@@ -5350,15 +5403,15 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
switch (opcode) {
case SpvOpImageQuerySize:
case SpvOpImageQuerySizeLod: {
- ast::ExpressionList exprs;
+ ExpressionList exprs;
// Invoke textureDimensions.
// If the texture is arrayed, combine with the result from
// textureNumLayers.
auto* dims_ident = create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register("textureDimensions"));
- ast::ExpressionList dims_args{GetImageExpression(inst)};
+ ExpressionList dims_args{GetImageExpression(inst)};
if (opcode == SpvOpImageQuerySizeLod) {
- dims_args.push_back(ToI32(MakeOperand(inst, 1)).expr);
+ dims_args.Push(ToI32(MakeOperand(inst, 1)).expr);
}
const ast::Expression* dims_call =
create<ast::CallExpression>(Source{}, dims_ident, dims_args);
@@ -5369,16 +5422,17 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
dims_call =
create<ast::MemberAccessorExpression>(Source{}, dims_call, PrefixSwizzle(2));
}
- exprs.push_back(dims_call);
+ exprs.Push(dims_call);
if (ast::IsTextureArray(dims)) {
auto* layers_ident = create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register("textureNumLayers"));
- exprs.push_back(create<ast::CallExpression>(
- Source{}, layers_ident, ast::ExpressionList{GetImageExpression(inst)}));
+ exprs.Push(create<ast::CallExpression>(Source{}, layers_ident,
+ utils::Vector{GetImageExpression(inst)}));
}
auto* result_type = parser_impl_.ConvertType(inst.type_id());
TypedExpression expr = {
- result_type, builder_.Construct(Source{}, result_type->Build(builder_), exprs)};
+ result_type,
+ builder_.Construct(Source{}, result_type->Build(builder_), std::move(exprs))};
return EmitConstDefOrWriteToHoistedVar(inst, expr);
}
case SpvOpImageQueryLod:
@@ -5392,13 +5446,13 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
auto* levels_ident =
create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
const ast::Expression* ast_expr = create<ast::CallExpression>(
- Source{}, levels_ident, ast::ExpressionList{GetImageExpression(inst)});
+ Source{}, levels_ident, utils::Vector{GetImageExpression(inst)});
auto* result_type = parser_impl_.ConvertType(inst.type_id());
// The SPIR-V result type must be integer scalar. The WGSL bulitin
// returns i32. If they aren't the same then convert the result.
if (!result_type->Is<I32>()) {
ast_expr = builder_.Construct(Source{}, result_type->Build(builder_),
- ast::ExpressionList{ast_expr});
+ utils::Vector{ast_expr});
}
TypedExpression expr{result_type, ast_expr};
return EmitConstDefOrWriteToHoistedVar(inst, expr);
@@ -5409,7 +5463,116 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
return Fail() << "unhandled image query: " << inst.PrettyPrint();
}
-ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
+bool FunctionEmitter::EmitAtomicOp(const spvtools::opt::Instruction& inst) {
+ auto emit_atomic = [&](sem::BuiltinType builtin, std::initializer_list<TypedExpression> args) {
+ // Split args into params and expressions
+ ParameterList params;
+ params.Reserve(args.size());
+ ExpressionList exprs;
+ exprs.Reserve(args.size());
+ size_t i = 0;
+ for (auto& a : args) {
+ params.Push(builder_.Param("p" + std::to_string(i++), a.type->Build(builder_)));
+ exprs.Push(a.expr);
+ }
+
+ // Function return type
+ const ast::Type* ret_type = nullptr;
+ if (inst.type_id() != 0) {
+ ret_type = parser_impl_.ConvertType(inst.type_id())->Build(builder_);
+ } else {
+ ret_type = builder_.ty.void_();
+ }
+
+ // Emit stub, will be removed by transform::SpirvAtomic
+ auto sym = builder_.Symbols().New(std::string("stub_") + sem::str(builtin));
+ auto* stub_deco = builder_.ASTNodes().Create<transform::SpirvAtomic::Stub>(
+ builder_.ID(), builder_.AllocateNodeID(), builtin);
+ auto* stub =
+ create<ast::Function>(Source{}, sym, std::move(params), ret_type,
+ /* body */ nullptr,
+ AttributeList{
+ stub_deco,
+ builder_.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+ },
+ AttributeList{});
+ builder_.AST().AddFunction(stub);
+
+ // Emit call to stub, will be replaced with call to atomic builtin by transform::SpirvAtomic
+ auto* call = builder_.Call(Source{}, sym, std::move(exprs));
+ if (inst.type_id() != 0) {
+ auto* result_type = parser_impl_.ConvertType(inst.type_id());
+ TypedExpression expr{result_type, call};
+ return EmitConstDefOrWriteToHoistedVar(inst, expr);
+ }
+ AddStatement(create<ast::CallStatement>(call));
+
+ return true;
+ };
+
+ auto oper = [&](uint32_t index) -> TypedExpression { //
+ return MakeOperand(inst, index);
+ };
+
+ auto lit = [&](int v) -> TypedExpression {
+ auto* result_type = parser_impl_.ConvertType(inst.type_id());
+ if (result_type->Is<I32>()) {
+ return TypedExpression(result_type, builder_.Expr(i32(v)));
+ } else if (result_type->Is<U32>()) {
+ return TypedExpression(result_type, builder_.Expr(u32(v)));
+ }
+ return {};
+ };
+
+ switch (inst.opcode()) {
+ case SpvOpAtomicLoad:
+ return emit_atomic(sem::BuiltinType::kAtomicLoad, {oper(/*ptr*/ 0)});
+ case SpvOpAtomicStore:
+ return emit_atomic(sem::BuiltinType::kAtomicStore,
+ {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicExchange:
+ return emit_atomic(sem::BuiltinType::kAtomicExchange,
+ {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicCompareExchange:
+ case SpvOpAtomicCompareExchangeWeak:
+ return emit_atomic(sem::BuiltinType::kAtomicCompareExchangeWeak,
+ {oper(/*ptr*/ 0), /*value*/ oper(5), /*comparator*/ oper(4)});
+ case SpvOpAtomicIIncrement:
+ return emit_atomic(sem::BuiltinType::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
+ case SpvOpAtomicIDecrement:
+ return emit_atomic(sem::BuiltinType::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
+ case SpvOpAtomicIAdd:
+ return emit_atomic(sem::BuiltinType::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicISub:
+ return emit_atomic(sem::BuiltinType::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicSMin:
+ return emit_atomic(sem::BuiltinType::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicUMin:
+ return emit_atomic(sem::BuiltinType::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicSMax:
+ return emit_atomic(sem::BuiltinType::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicUMax:
+ return emit_atomic(sem::BuiltinType::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicAnd:
+ return emit_atomic(sem::BuiltinType::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicOr:
+ return emit_atomic(sem::BuiltinType::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicXor:
+ return emit_atomic(sem::BuiltinType::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+ case SpvOpAtomicFlagTestAndSet:
+ case SpvOpAtomicFlagClear:
+ case SpvOpAtomicFMinEXT:
+ case SpvOpAtomicFMaxEXT:
+ case SpvOpAtomicFAddEXT:
+ return Fail() << "unsupported atomic op: " << inst.PrettyPrint();
+
+ default:
+ break;
+ }
+ return Fail() << "unhandled atomic op: " << inst.PrettyPrint();
+}
+
+FunctionEmitter::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
const spvtools::opt::Instruction& inst) {
if (!parser_impl_.success()) {
Fail();
@@ -5446,7 +5609,7 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
}
ast::TextureDimension dim = texture_type->dims;
// Number of regular coordinates.
- uint32_t num_axes = ast::NumCoordinateAxes(dim);
+ uint32_t num_axes = static_cast<uint32_t>(ast::NumCoordinateAxes(dim));
bool is_arrayed = ast::IsTextureArray(dim);
if ((num_axes == 0) || (num_axes > 3)) {
Fail() << "unsupported image dimensionality for " << texture_type->TypeInfo().name
@@ -5484,7 +5647,7 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
return {};
}
- ast::ExpressionList result;
+ ExpressionList result;
// Generates the expression for the WGSL coordinates, when it is a prefix
// swizzle with num_axes. If the result would be unsigned, also converts
@@ -5511,7 +5674,7 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
// The source must be a vector. It has at least one coordinate component
// and it must have an array component. Use a vector swizzle to get the
// first `num_axes` components.
- result.push_back(prefix_swizzle_expr());
+ result.Push(prefix_swizzle_expr());
// Now get the array index.
const ast::Expression* array_index =
@@ -5524,16 +5687,16 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
array_index = builder_.Call("round", array_index);
}
// Convert it to a signed integer type, if needed.
- result.push_back(ToI32({component_type, array_index}).expr);
+ result.Push(ToI32({component_type, array_index}).expr);
} else {
if (num_coords_supplied == num_coords_required && !is_proj) {
// Pass the value through, with possible unsigned->signed conversion.
- result.push_back(ToSignedIfUnsigned(raw_coords).expr);
+ result.Push(ToSignedIfUnsigned(raw_coords).expr);
} else {
// There are more coordinates supplied than needed. So the source type
// is a vector. Use a vector swizzle to get the first `num_axes`
// components.
- result.push_back(prefix_swizzle_expr());
+ result.Push(prefix_swizzle_expr());
}
}
return result;
@@ -5594,10 +5757,10 @@ const ast::Expression* FunctionEmitter::ConvertTexelForStorage(
// Expand the texel to a 4 element vector.
auto* component_type = texel.type->IsScalar() ? texel.type : texel.type->As<Vector>()->type;
texel.type = ty_.Vector(component_type, dest_count);
- ast::ExpressionList exprs;
- exprs.push_back(texel.expr);
+ ExpressionList exprs;
+ exprs.Push(texel.expr);
for (auto i = src_count; i < dest_count; i++) {
- exprs.push_back(parser_impl_.MakeNullExpression(component_type).expr);
+ exprs.Push(parser_impl_.MakeNullExpression(component_type).expr);
}
texel.expr = builder_.Construct(Source{}, texel.type->Build(builder_), std::move(exprs));
}
@@ -5609,8 +5772,7 @@ TypedExpression FunctionEmitter::ToI32(TypedExpression value) {
if (!value || value.type->Is<I32>()) {
return value;
}
- return {ty_.I32(),
- builder_.Construct(Source{}, builder_.ty.i32(), ast::ExpressionList{value.expr})};
+ return {ty_.I32(), builder_.Construct(Source{}, builder_.ty.i32(), utils::Vector{value.expr})};
}
TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression value) {
@@ -5619,8 +5781,7 @@ TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression value) {
}
if (auto* vec_type = value.type->As<Vector>()) {
auto* new_type = ty_.Vector(ty_.I32(), vec_type->size);
- return {new_type,
- builder_.Construct(new_type->Build(builder_), ast::ExpressionList{value.expr})};
+ return {new_type, builder_.Construct(new_type->Build(builder_), utils::Vector{value.expr})};
}
return ToI32(value);
}
@@ -5683,20 +5844,22 @@ TypedExpression FunctionEmitter::MakeOuterProduct(const spvtools::opt::Instructi
// | c.y * r.x c.y * r.y |
// | c.z * r.x c.z * r.y |
- ast::ExpressionList result_columns;
+ ExpressionList result_columns;
for (uint32_t icol = 0; icol < result_ty->columns; icol++) {
- ast::ExpressionList result_row;
+ ExpressionList result_row;
auto* row_factor = create<ast::MemberAccessorExpression>(Source{}, row.expr, Swizzle(icol));
for (uint32_t irow = 0; irow < result_ty->rows; irow++) {
auto* column_factor =
create<ast::MemberAccessorExpression>(Source{}, col.expr, Swizzle(irow));
auto* elem = create<ast::BinaryExpression>(Source{}, ast::BinaryOp::kMultiply,
row_factor, column_factor);
- result_row.push_back(elem);
+ result_row.Push(elem);
}
- result_columns.push_back(builder_.Construct(Source{}, col_ty->Build(builder_), result_row));
+ result_columns.Push(
+ builder_.Construct(Source{}, col_ty->Build(builder_), std::move(result_row)));
}
- return {result_ty, builder_.Construct(Source{}, result_ty->Build(builder_), result_columns)};
+ return {result_ty,
+ builder_.Construct(Source{}, result_ty->Build(builder_), std::move(result_columns))};
}
bool FunctionEmitter::MakeVectorInsertDynamic(const spvtools::opt::Instruction& inst) {
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/function.h b/chromium/third_party/dawn/src/tint/reader/spirv/function.h
index 8eb33ab8cd2..7a2a86b7b59 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/function.h
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/function.h
@@ -16,6 +16,7 @@
#define SRC_TINT_READER_SPIRV_FUNCTION_H_
#include <memory>
+#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -125,7 +126,7 @@ struct BlockInfo {
/// switch?
bool default_is_merge = false;
/// The list of switch values that cause a branch to this block.
- std::unique_ptr<std::vector<uint64_t>> case_values;
+ std::optional<utils::Vector<uint64_t, 4>> case_values;
/// The following fields record relationships among blocks in a selection
/// construct for an OpBranchConditional instruction.
@@ -158,7 +159,7 @@ struct BlockInfo {
/// The result IDs that this block is responsible for declaring as a
/// hoisted variable.
/// @see DefInfo#requires_hoisted_def
- std::vector<uint32_t> hoisted_ids;
+ utils::Vector<uint32_t, 4> hoisted_ids;
/// A PhiAssignment represents the assignment of a value to the state
/// variable associated with an OpPhi in a successor block.
@@ -170,10 +171,10 @@ struct BlockInfo {
};
/// If this basic block branches to a visited basic block containing phis,
/// then this is the list of writes to the variables associated those phis.
- std::vector<PhiAssignment> phi_assignments;
+ utils::Vector<PhiAssignment, 4> phi_assignments;
/// The IDs of OpPhi instructions which require their associated state
/// variable to be declared in this basic block.
- std::vector<uint32_t> phis_needing_state_vars;
+ utils::Vector<uint32_t, 4> phis_needing_state_vars;
};
/// Writes the BlockInfo to the ostream
@@ -241,14 +242,22 @@ enum class SkipReason {
struct DefInfo {
/// Constructor.
/// @param def_inst the SPIR-V instruction defining the ID
- /// @param block_pos the position of the basic block where the ID is defined.
+ /// @param locally_defined true if the defining instruction is in the function
+ /// @param block_pos the position of the basic block where the ID is defined
/// @param index an ordering index for this local definition
- DefInfo(const spvtools::opt::Instruction& def_inst, uint32_t block_pos, size_t index);
+ DefInfo(const spvtools::opt::Instruction& def_inst,
+ bool locally_defined,
+ uint32_t block_pos,
+ size_t index);
/// Destructor.
~DefInfo();
/// The SPIR-V instruction that defines the ID.
const spvtools::opt::Instruction& inst;
+
+ /// True if the definition of this ID is inside the function.
+ const bool locally_defined = true;
+
/// The position of the first block in which this ID is visible, in function
/// block order. For IDs defined outside of the function, it is 0.
/// For IDs defined in the function, it is the position of the block
@@ -320,8 +329,11 @@ struct DefInfo {
/// @returns the ostream so calls can be chained
inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
o << "DefInfo{"
- << " inst.result_id: " << di.inst.result_id() << " block_pos: " << di.block_pos
- << " num_uses: " << di.num_uses << " last_use_pos: " << di.last_use_pos
+ << " inst.result_id: " << di.inst.result_id()
+ << " locally_defined: " << (di.locally_defined ? "true" : "false")
+ << " block_pos: " << di.block_pos << " num_uses: " << di.num_uses
+ << " last_use_pos: " << di.last_use_pos
+ << " used_in_another_construct: " << (di.used_in_another_construct ? "true" : "false")
<< " requires_named_const_def: " << (di.requires_named_const_def ? "true" : "false")
<< " requires_hoisted_def: " << (di.requires_hoisted_def ? "true" : "false") << " phi_var: '"
<< di.phi_var << "'";
@@ -365,7 +377,7 @@ inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
class StatementBuilder : public Castable<StatementBuilder, ast::Statement> {
public:
/// Constructor
- StatementBuilder() : Base(ProgramID(), Source{}) {}
+ StatementBuilder() : Base(ProgramID(), ast::NodeID(), Source{}) {}
/// @param builder the program builder
/// @returns the build AST node
@@ -377,6 +389,12 @@ class StatementBuilder : public Castable<StatementBuilder, ast::Statement> {
/// A FunctionEmitter emits a SPIR-V function onto a Tint AST module.
class FunctionEmitter {
+ using AttributeList = utils::Vector<const ast::Attribute*, 8>;
+ using StructMemberList = utils::Vector<const ast::StructMember*, 8>;
+ using ExpressionList = utils::Vector<const ast::Expression*, 8>;
+ using ParameterList = utils::Vector<const ast::Parameter*, 8>;
+ using StatementList = utils::Vector<const ast::Statement*, 8>;
+
public:
/// Creates a FunctionEmitter, and prepares to write to the AST module
/// in `pi`
@@ -409,7 +427,7 @@ class FunctionEmitter {
/// Finalizes any StatementBuilders returns the body of the function.
/// Must only be called once, and to be used only for testing.
/// @returns the body of the function.
- const ast::StatementList ast_body();
+ StatementList ast_body();
/// Records failure.
/// @returns a FailStream on which to emit diagnostics.
@@ -444,12 +462,12 @@ class FunctionEmitter {
/// @returns false if emission failed
bool EmitPipelineInput(std::string var_name,
const Type* var_type,
- ast::AttributeList* decos,
- std::vector<int> index_prefix,
+ AttributeList* decos,
+ utils::Vector<int, 8> index_prefix,
const Type* tip_type,
const Type* forced_param_type,
- ast::VariableList* params,
- ast::StatementList* statements);
+ ParameterList* params,
+ StatementList* statements);
/// Creates one or more struct members from an output variable, and the
/// expressions that compute the value they contribute to the entry point
@@ -460,37 +478,30 @@ class FunctionEmitter {
/// @param var_name The name of the variable
/// @param var_type The store type of the variable
/// @param decos The variable's decorations
- /// @param index_prefix Indices stepping into the variable, indicating
- /// what part of the variable to populate.
- /// @param tip_type The type of the component inside variable, after indexing
- /// with the indices in `index_prefix`.
- /// @param forced_member_type The type forced by WGSL, if the variable is a
- /// builtin, otherwise the same as var_type.
- /// @param return_members The struct member list where the new member is
- /// added.
- /// @param return_exprs The expression list where the return expression is
- /// added.
+ /// @param index_prefix Indices stepping into the variable, indicating what part of the variable
+ /// to populate.
+ /// @param tip_type The type of the component inside variable, after indexing with the indices
+ /// in `index_prefix`.
+ /// @param forced_member_type The type forced by WGSL, if the variable is a builtin, otherwise
+ /// the same as var_type.
+ /// @param return_members The struct member list where the new member is added.
+ /// @param return_exprs The expression list where the return expression is added.
/// @returns false if emission failed
bool EmitPipelineOutput(std::string var_name,
const Type* var_type,
- ast::AttributeList* decos,
- std::vector<int> index_prefix,
+ AttributeList* decos,
+ utils::Vector<int, 8> index_prefix,
const Type* tip_type,
const Type* forced_member_type,
- ast::StructMemberList* return_members,
- ast::ExpressionList* return_exprs);
+ StructMemberList* return_members,
+ ExpressionList* return_exprs);
/// Updates the attribute list, replacing an existing Location attribute
/// with another having one higher location value. Does nothing if no
/// location attribute exists.
/// Assumes the list contains at most one Location attribute.
/// @param attributes the attribute list to modify
- void IncrementLocation(ast::AttributeList* attributes);
-
- /// Returns the Location attribute, if it exists.
- /// @param attributes the list of attributes to search
- /// @returns the Location attribute, or nullptr if it doesn't exist
- const ast::Attribute* GetLocation(const ast::AttributeList& attributes);
+ void IncrementLocation(AttributeList* attributes);
/// Create an ast::BlockStatement representing the body of the function.
/// This creates the statement stack, which is non-empty for the lifetime
@@ -840,7 +851,7 @@ class FunctionEmitter {
return info && info->pos != kInvalidBlockPos;
}
- /// Gets the local definition info for a result ID.
+ /// Gets the definition info for a result ID.
/// @param id the SPIR-V ID of local definition.
/// @returns the definition info for the given ID, if it exists, or nullptr
DefInfo* GetDefInfo(uint32_t id) const {
@@ -902,7 +913,7 @@ class FunctionEmitter {
/// On failure, issues an error and returns an empty expression list.
/// @param image_access the image access instruction
/// @returns an ExpressionList of the coordinate and array index (if any)
- ast::ExpressionList MakeCoordinateOperandsForImageAccess(
+ ExpressionList MakeCoordinateOperandsForImageAccess(
const spvtools::opt::Instruction& image_access);
/// Returns the given value as an I32. If it's already an I32 then this
@@ -940,11 +951,11 @@ class FunctionEmitter {
/// Function name
std::string name;
/// Function parameters
- ast::VariableList params;
+ ParameterList params;
/// Function return type
const Type* return_type;
/// Function attributes
- ast::AttributeList attributes;
+ AttributeList attributes;
};
/// Parse the function declaration, which comprises the name, parameters, and
@@ -1049,7 +1060,7 @@ class FunctionEmitter {
/// Emits a texture builtin function call for a SPIR-V instruction that
/// accesses an image or sampled image.
/// @param inst the SPIR-V instruction
- /// @returns an expression
+ /// @returns true on success, false on error
bool EmitImageAccess(const spvtools::opt::Instruction& inst);
/// Emits statements to implement a SPIR-V image query.
@@ -1057,6 +1068,11 @@ class FunctionEmitter {
/// @returns an expression
bool EmitImageQuery(const spvtools::opt::Instruction& inst);
+ /// Emits statements to implement a SPIR-V atomic op.
+ /// @param inst the SPIR-V instruction
+ /// @returns true on success, false on error
+ bool EmitAtomicOp(const spvtools::opt::Instruction& inst);
+
/// Converts the given texel to match the type required for the storage
/// texture with the given type. In WGSL the texel value is always provided
/// as a 4-element vector, but the component type is determined by the
@@ -1101,8 +1117,8 @@ class FunctionEmitter {
/// @return the built StatementBuilder
template <typename T, typename... ARGS>
T* AddStatementBuilder(ARGS&&... args) {
- TINT_ASSERT(Reader, !statements_stack_.empty());
- return statements_stack_.back().AddStatementBuilder<T>(std::forward<ARGS>(args)...);
+ TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+ return statements_stack_.Back().AddStatementBuilder<T>(std::forward<ARGS>(args)...);
}
/// Returns the source record for the given instruction.
@@ -1110,10 +1126,10 @@ class FunctionEmitter {
/// @return the Source record, or a default one
Source GetSourceForInst(const spvtools::opt::Instruction& inst) const;
- /// @returns the last statetment in the top of the statement stack.
+ /// @returns the last statement in the top of the statement stack.
const ast::Statement* LastStatement();
- using CompletionAction = std::function<void(const ast::StatementList&)>;
+ using CompletionAction = std::function<void(const StatementList&)>;
// A StatementBlock represents a braced-list of statements while it is being
// constructed.
@@ -1165,7 +1181,7 @@ class FunctionEmitter {
/// @return the list of statements being built, if this construct is not a
/// switch.
- const ast::StatementList& GetStatements() const { return statements_; }
+ const StatementList& GetStatements() const { return statements_; }
private:
/// The construct to which this construct constributes.
@@ -1177,7 +1193,7 @@ class FunctionEmitter {
/// The completion action finishes processing this statement block.
FunctionEmitter::CompletionAction const completion_action_;
/// The list of statements being built, if this construct is not a switch.
- ast::StatementList statements_;
+ StatementList statements_;
/// Owned statement builders
std::vector<std::unique_ptr<StatementBuilder>> builders_;
@@ -1235,7 +1251,6 @@ class FunctionEmitter {
return builder_.create<T>(std::forward<ARGS>(args)...);
}
- using StatementsStack = std::vector<StatementBlock>;
using PtrAs = ParserImpl::PtrAs;
ParserImpl& parser_impl_;
@@ -1259,7 +1274,7 @@ class FunctionEmitter {
// for the entire function. This stack is never empty.
// The `construct` member for the 0th element is only valid during the
// lifetime of the EmitFunctionBodyStatements method.
- StatementsStack statements_stack_;
+ utils::Vector<StatementBlock, 8> statements_stack_;
// The map of IDs that have already had an identifier name generated for it,
// to their Type.
@@ -1274,7 +1289,9 @@ class FunctionEmitter {
// Mapping from block ID to its bookkeeping info.
std::unordered_map<uint32_t, std::unique_ptr<BlockInfo>> block_info_;
- // Mapping from a locally-defined result ID to its bookkeeping info.
+ // Mapping from a result ID to its bookkeeping info. This may be
+ // either a result ID defined in the function body, or the ID of a
+ // module-scope variable.
std::unordered_map<uint32_t, std::unique_ptr<DefInfo>> def_info_;
// Structured constructs, where enclosing constructs precede their children.
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/function_call_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/function_call_test.cc
index 584ad16c2d4..6b12eced921 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/function_call_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/function_call_test.cc
@@ -87,13 +87,13 @@ TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParams) {
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
- ast::StatementList f100;
+ utils::Vector<const ast::Statement*, 4> f100;
{
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
f100 = fe.ast_body();
}
- ast::StatementList f50;
+ utils::Vector<const ast::Statement*, 4> f50;
{
auto fe = p->function_emitter(50);
EXPECT_TRUE(fe.EmitBody()) << p->error();
@@ -128,13 +128,13 @@ TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParamsUsedTwice) {
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
- ast::StatementList f100;
+ utils::Vector<const ast::Statement*, 4> f100;
{
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
f100 = fe.ast_body();
}
- ast::StatementList f50;
+ utils::Vector<const ast::Statement*, 4> f50;
{
auto fe = p->function_emitter(50);
EXPECT_TRUE(fe.EmitBody()) << p->error();
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/function_cfg_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/function_cfg_test.cc
index edeea55271e..fb5aff77db1 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/function_cfg_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/function_cfg_test.cc
@@ -2894,8 +2894,8 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_OuterConstructIsFunction_Sin
fe.ComputeBlockOrderAndPositions();
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
- EXPECT_EQ(fe.constructs().size(), 1u);
- auto& c = fe.constructs().front();
+ EXPECT_EQ(fe.constructs().Length(), 1u);
+ auto& c = fe.constructs().Front();
EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,1) begin_id:10 end_id:0 "
"depth:0 parent:null }"));
EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
@@ -2920,8 +2920,8 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_OuterConstructIsFunction_Mul
fe.ComputeBlockOrderAndPositions();
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
- EXPECT_EQ(fe.constructs().size(), 1u);
- auto& c = fe.constructs().front();
+ EXPECT_EQ(fe.constructs().Length(), 1u);
+ auto& c = fe.constructs().Front();
EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,2) begin_id:10 end_id:0 "
"depth:0 parent:null }"));
EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
@@ -2955,7 +2955,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_FunctionIsOnlyIfSelectionAnd
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 2u);
+ EXPECT_EQ(constructs.Length(), 2u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@@ -3001,7 +3001,7 @@ TEST_F(SpvParserCFGTest,
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 2u);
+ EXPECT_EQ(constructs.Length(), 2u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,6) begin_id:5 end_id:0 depth:0 parent:null }
Construct{ IfSelection [1,4) begin_id:10 end_id:99 depth:1 parent:Function@5 }
@@ -3045,7 +3045,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SwitchSelection) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 2u);
+ EXPECT_EQ(constructs.Length(), 2u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ SwitchSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 in-c-l-s:SwitchSelection@10 }
@@ -3082,7 +3082,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SingleBlockLoop) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 2u);
+ EXPECT_EQ(constructs.Length(), 2u);
// A single-block loop consists *only* of a continue target with one block in
// it.
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
@@ -3188,6 +3188,9 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MultiBlockLoop_HeaderIsConti
EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+
+ // SPIR-V 1.6 Rev 2 made this invalid SPIR-V.
+ p->DeliberatelyInvalidSpirv();
}
TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MergeBlockIsAlsoSingleBlockLoop) {
@@ -3220,7 +3223,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MergeBlockIsAlsoSingleBlockL
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 3u);
+ EXPECT_EQ(constructs.Length(), 3u);
// A single-block loop consists *only* of a continue target with one block in
// it.
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
@@ -3268,7 +3271,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MergeBlockIsAlsoMultiBlockLo
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
@@ -3327,7 +3330,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_If) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,9) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,8) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@@ -3387,7 +3390,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Switch_If) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
// The ordering among siblings depends on the computed block order.
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
@@ -3437,7 +3440,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_Switch) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 3u);
+ EXPECT_EQ(constructs.Length(), 3u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@@ -3491,7 +3494,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_Loop) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [4,6) begin_id:50 end_id:89 depth:1 parent:Function@10 in-c:Continue@50 }
@@ -3546,7 +3549,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_If) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [5,6) begin_id:80 end_id:99 depth:1 parent:Function@10 in-c:Continue@80 }
@@ -3597,7 +3600,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_LoopContinue_If) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [2,5) begin_id:30 end_id:99 depth:1 parent:Function@10 in-c:Continue@30 }
@@ -3641,7 +3644,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_SingleBlockLoop) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 3u);
+ EXPECT_EQ(constructs.Length(), 3u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@@ -3690,7 +3693,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_MultiBlockLoop) {
fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,6) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@@ -3740,7 +3743,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_LoopInterallyDiverge) {
auto fe = p->function_emitter(100);
ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
const auto& constructs = fe.constructs();
- EXPECT_EQ(constructs.size(), 4u);
+ EXPECT_EQ(constructs.Length(), 4u);
ASSERT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [4,5) begin_id:90 end_id:99 depth:1 parent:Function@10 in-c:Continue@90 }
@@ -4154,7 +4157,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_NoSwitch) {
EXPECT_EQ(bi10->case_head_for, nullptr);
EXPECT_EQ(bi10->default_head_for, nullptr);
EXPECT_FALSE(bi10->default_is_merge);
- EXPECT_EQ(bi10->case_values.get(), nullptr);
+ EXPECT_FALSE(bi10->case_values.has_value());
}
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsMerge) {
@@ -4189,7 +4192,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsMerge) {
ASSERT_NE(bi99->default_head_for, nullptr);
EXPECT_EQ(bi99->default_head_for->begin_id, 10u);
EXPECT_TRUE(bi99->default_is_merge);
- EXPECT_EQ(bi99->case_values.get(), nullptr);
+ EXPECT_FALSE(bi99->case_values.has_value());
}
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsNotMerge) {
@@ -4227,7 +4230,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsNotMerge) {
ASSERT_NE(bi30->default_head_for, nullptr);
EXPECT_EQ(bi30->default_head_for->begin_id, 10u);
EXPECT_FALSE(bi30->default_is_merge);
- EXPECT_EQ(bi30->case_values.get(), nullptr);
+ EXPECT_FALSE(bi30->case_values.has_value());
}
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsNotDefault) {
@@ -4265,7 +4268,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsNotDefault) {
EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
EXPECT_EQ(bi20->default_head_for, nullptr);
EXPECT_FALSE(bi20->default_is_merge);
- EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
+ EXPECT_THAT(bi20->case_values.value(), UnorderedElementsAre(200));
}
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsDefault) {
@@ -4300,7 +4303,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsDefault) {
EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
EXPECT_EQ(bi20->default_head_for, bi20->case_head_for);
EXPECT_FALSE(bi20->default_is_merge);
- EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
+ EXPECT_THAT(bi20->case_values.value(), UnorderedElementsAre(200));
}
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyCasesWithSameValue_IsError) {
@@ -4367,7 +4370,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyValuesWithSameCase) {
EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
EXPECT_EQ(bi20->default_head_for, nullptr);
EXPECT_FALSE(bi20->default_is_merge);
- EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200, 300));
+ EXPECT_THAT(bi20->case_values.value(), UnorderedElementsAre(200, 300));
}
TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BranchEscapesIfConstruct) {
@@ -4726,6 +4729,12 @@ TEST_F(
ASSERT_NE(bi50, nullptr);
EXPECT_EQ(bi50->succ_edge.count(20), 1u);
EXPECT_EQ(bi50->succ_edge[20], EdgeKind::kBack);
+
+ // SPIR-V 1.6 Rev 2 made this invalid SPIR-V.
+ // The continue target also has the LoopMerge in it, but the continue
+ // target 20 is not structurally post-dominated by the back-edge block 50.
+ // Don't dump this as an end-to-end test.
+ p->DeliberatelyInvalidSpirv();
}
TEST_F(SpvParserCFGTest, ClassifyCFGEdges_PrematureExitFromContinueConstruct) {
@@ -8640,6 +8649,9 @@ var_1 = 3u;
return;
)";
ASSERT_EQ(expect, got);
+
+ // Continue target does not structurally dominate the backedge block.
+ p->DeliberatelyInvalidSpirv();
}
TEST_F(SpvParserCFGTest, EmitBody_Loop_Never) {
@@ -12608,6 +12620,11 @@ TEST_F(SpvParserCFGTest, SiblingLoopConstruct_ContinueIsWholeMultiBlockLoop) {
const Construct* c = fe.GetBlockInfo(20)->construct;
EXPECT_EQ(c->kind, Construct::kContinue);
EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
+
+ // SPIR-V 1.6 Rev 2 made this invalid SPIR-V.
+ // Continue target is not structurally post dominated by the backedge block.
+ // Don't dump this as an end-to-end test.
+ p->DeliberatelyInvalidSpirv();
}
TEST_F(SpvParserCFGTest, SiblingLoopConstruct_HasSiblingLoop) {
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/function_misc_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/function_misc_test.cc
index 3f9c3985c62..5054c670bdb 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/function_misc_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/function_misc_test.cc
@@ -290,51 +290,6 @@ INSTANTIATE_TEST_SUITE_P(ValidIndex,
{4, "", "vector component index is larger than 3: 4"},
{99999, "", "vector component index is larger than 3: 99999"}}));
-TEST_F(SpvParserTest, ValueFromBlockNotInBlockOrder) {
- // crbug.com/tint/804
- const auto assembly = Preamble() + CommonTypes() + R"(
- %float_42 = OpConstant %float 42.0
- %cond = OpUndef %bool
-
- %100 = OpFunction %void None %voidfn
- %10 = OpLabel
- OpBranch %30
-
- ; unreachable
- %20 = OpLabel
- %499 = OpFAdd %float %float_42 %float_42
- %500 = OpFAdd %float %499 %float_42
- OpBranch %25
-
- %25 = OpLabel
- OpBranch %80
-
-
- %30 = OpLabel
- OpLoopMerge %90 %80 None
- OpBranchConditional %cond %90 %40
-
- %40 = OpLabel
- OpBranch %90
-
- %80 = OpLabel ; unreachable continue target
- ; but "dominated" by %20 and %25
- %81 = OpFMul %float %500 %float_42 ; %500 is defined in %20
- OpBranch %30 ; backedge
-
- %90 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
- auto p = parser(test::Assemble(assembly));
- ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
- auto fe = p->function_emitter(100);
- EXPECT_TRUE(fe.EmitBody()) << p->error();
- auto ast_body = fe.ast_body();
- const auto got = test::ToString(p->program(), ast_body);
- EXPECT_THAT(got, HasSubstr("let x_81 : f32 = (0.0f * 42.0f);"));
-}
-
// TODO(dneto): OpSizeof : requires Kernel (OpenCL)
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/function_var_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/function_var_test.cc
index 63712345884..ff282990df3 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/function_var_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/function_var_test.cc
@@ -1418,65 +1418,6 @@ return;
EXPECT_EQ(expect, got);
}
-TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_ValueFromBlockNotInBlockOrderIgnored) {
- // From crbug.com/tint/804
- const auto assembly = Preamble() + R"(
- %float_42 = OpConstant %float 42.0
- %cond = OpUndef %bool
-
- %100 = OpFunction %void None %voidfn
- %10 = OpLabel
- OpBranch %30
-
- ; unreachable
- %20 = OpLabel
- %499 = OpFAdd %float %float_42 %float_42
- %500 = OpFAdd %float %499 %float_42
- OpBranch %25
-
- %25 = OpLabel
- OpBranch %80
-
-
- %30 = OpLabel
- OpLoopMerge %90 %80 None
- OpBranchConditional %cond %90 %40
-
- %40 = OpLabel
- OpBranch %90
-
- %80 = OpLabel ; unreachable continue target
- ; but "dominated" by %20 and %25
- %81 = OpPhi %float %500 %25
- OpBranch %30 ; backedge
-
- %90 = OpLabel
- OpReturn
- OpFunctionEnd
-)";
- auto p = parser(test::Assemble(assembly));
- ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
- auto fe = p->function_emitter(100);
- EXPECT_TRUE(fe.EmitBody()) << p->error();
-
- const auto* expected = R"(loop {
- if (false) {
- break;
- }
- break;
-
- continuing {
- var x_81_phi_1 : f32;
- let x_81 : f32 = x_81_phi_1;
- }
-}
-return;
-)";
- auto ast_body = fe.ast_body();
- const auto got = test::ToString(p->program(), ast_body);
- EXPECT_EQ(got, expected);
-}
-
TEST_F(SpvParserFunctionVarTest, EmitStatement_Hoist_CompositeInsert) {
// From crbug.com/tint/804
const auto assembly = Preamble() + R"(
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser.cc
index f430d94f72c..ac43b9e54c0 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser.cc
@@ -22,6 +22,7 @@
#include "src/tint/transform/manager.h"
#include "src/tint/transform/remove_unreachable_statements.h"
#include "src/tint/transform/simplify_pointers.h"
+#include "src/tint/transform/spirv_atomic.h"
#include "src/tint/transform/unshadow.h"
namespace tint::reader::spirv {
@@ -55,6 +56,7 @@ Program Parse(const std::vector<uint32_t>& input) {
manager.Add<transform::DecomposeStridedMatrix>();
manager.Add<transform::DecomposeStridedArray>();
manager.Add<transform::RemoveUnreachableStatements>();
+ manager.Add<transform::SpirvAtomic>();
return manager.Run(&program).program;
}
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.cc
index bdc52e695ef..f9117a5e497 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.cc
@@ -447,10 +447,10 @@ std::string ParserImpl::ShowType(uint32_t type_id) {
return "SPIR-V type " + std::to_string(type_id);
}
-ast::AttributeList ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id,
- uint32_t member_index,
- const Type* member_ty,
- const Decoration& decoration) {
+ParserImpl::AttributeList ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id,
+ uint32_t member_index,
+ const Type* member_ty,
+ const Decoration& decoration) {
if (decoration.empty()) {
Fail() << "malformed SPIR-V decoration: it's empty";
return {};
@@ -513,7 +513,8 @@ ast::AttributeList ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id,
return {
create<ast::StrideAttribute>(Source{}, decoration[1]),
builder_.ASTNodes().Create<ast::DisableValidationAttribute>(
- builder_.ID(), ast::DisabledValidation::kIgnoreStrideAttribute),
+ builder_.ID(), builder_.AllocateNodeID(),
+ ast::DisabledValidation::kIgnoreStrideAttribute),
};
}
default:
@@ -816,7 +817,7 @@ bool ParserImpl::RegisterWorkgroupSizeBuiltin() {
/// Returns false and emits a diagnostic on error.
auto set_param = [this, composite_def](uint32_t* id_ptr, uint32_t* value_ptr,
int index) -> bool {
- const auto id = composite_def->GetSingleWordInOperand(index);
+ const auto id = composite_def->GetSingleWordInOperand(static_cast<uint32_t>(index));
const auto* def = def_use_mgr_->GetDef(id);
if (!def || (def->opcode() != SpvOpSpecConstant && def->opcode() != SpvOpConstant) ||
(def->NumInOperands() != 1)) {
@@ -877,17 +878,17 @@ bool ParserImpl::RegisterEntryPoints() {
TINT_ASSERT(Reader, !inner_implementation_name.empty());
TINT_ASSERT(Reader, ep_name != inner_implementation_name);
- utils::UniqueVector<uint32_t> inputs;
- utils::UniqueVector<uint32_t> outputs;
+ utils::UniqueVector<uint32_t, 8> inputs;
+ utils::UniqueVector<uint32_t, 8> outputs;
for (unsigned iarg = 3; iarg < entry_point.NumInOperands(); iarg++) {
const uint32_t var_id = entry_point.GetSingleWordInOperand(iarg);
if (const auto* var_inst = def_use_mgr_->GetDef(var_id)) {
switch (SpvStorageClass(var_inst->GetSingleWordInOperand(0))) {
case SpvStorageClassInput:
- inputs.add(var_id);
+ inputs.Add(var_id);
break;
case SpvStorageClassOutput:
- outputs.add(var_id);
+ outputs.Add(var_id);
break;
default:
break;
@@ -895,9 +896,9 @@ bool ParserImpl::RegisterEntryPoints() {
}
}
// Save the lists, in ID-sorted order.
- std::vector<uint32_t> sorted_inputs(inputs);
+ utils::Vector<uint32_t, 8> sorted_inputs(inputs);
std::sort(sorted_inputs.begin(), sorted_inputs.end());
- std::vector<uint32_t> sorted_outputs(outputs);
+ utils::Vector<uint32_t, 8> sorted_outputs(outputs);
std::sort(sorted_outputs.begin(), sorted_outputs.end());
const auto ast_stage = enum_converter_.ToPipelineStage(stage);
@@ -1066,7 +1067,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
}
// Compute members
- ast::StructMemberList ast_members;
+ utils::Vector<const ast::StructMember*, 8> ast_members;
const auto members = struct_ty->element_types();
if (members.empty()) {
Fail() << "WGSL does not support empty structures. can't convert type: "
@@ -1122,7 +1123,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
}
bool is_non_writable = false;
- ast::AttributeList ast_member_decorations;
+ AttributeList ast_member_decorations;
for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
if (IsPipelineDecoration(decoration)) {
// IO decorations are handled when emitting the entry point.
@@ -1136,7 +1137,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
auto decos =
ConvertMemberDecoration(type_id, member_index, ast_member_ty, decoration);
for (auto* deco : decos) {
- ast_member_decorations.emplace_back(deco);
+ ast_member_decorations.Push(deco);
}
if (!success_) {
return nullptr;
@@ -1153,10 +1154,10 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
auto* ast_struct_member = create<ast::StructMember>(
Source{}, builder_.Symbols().Register(member_name), ast_member_ty->Build(builder_),
std::move(ast_member_decorations));
- ast_members.push_back(ast_struct_member);
+ ast_members.Push(ast_struct_member);
}
- if (ast_members.empty()) {
+ if (ast_members.IsEmpty()) {
// All members were likely built-ins. Don't generate an empty AST structure.
return nullptr;
}
@@ -1167,8 +1168,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
// Now make the struct.
auto sym = builder_.Symbols().Register(name);
- auto* ast_struct =
- create<ast::Struct>(Source{}, sym, std::move(ast_members), ast::AttributeList());
+ auto* ast_struct = create<ast::Struct>(Source{}, sym, std::move(ast_members), utils::Empty);
if (num_non_writable_members == members.size()) {
read_only_struct_types_.insert(ast_struct->name);
}
@@ -1218,8 +1218,8 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
}
// Pipeline input and output variables map to private variables.
- if (ast_storage_class == ast::StorageClass::kInput ||
- ast_storage_class == ast::StorageClass::kOutput) {
+ if (ast_storage_class == ast::StorageClass::kIn ||
+ ast_storage_class == ast::StorageClass::kOut) {
ast_storage_class = ast::StorageClass::kPrivate;
}
switch (ptr_as) {
@@ -1336,7 +1336,7 @@ bool ParserImpl::EmitScalarSpecConstants() {
},
[&](const U32*) {
return create<ast::IntLiteralExpression>(
- Source{}, static_cast<uint64_t>(literal_value),
+ Source{}, static_cast<int64_t>(literal_value),
ast::IntLiteralExpression::Suffix::kU);
},
[&](const F32*) {
@@ -1357,7 +1357,7 @@ bool ParserImpl::EmitScalarSpecConstants() {
break;
}
if (ast_type && ast_expr) {
- ast::AttributeList spec_id_decos;
+ AttributeList spec_id_decos;
for (const auto& deco : GetDecorationsFor(inst.result_id())) {
if ((deco.size() == 2) && (deco[0] == SpvDecorationSpecId)) {
const uint32_t id = deco[1];
@@ -1367,12 +1367,12 @@ bool ParserImpl::EmitScalarSpecConstants() {
<< inst.result_id() << " has SpecId " << id;
}
auto* cid = create<ast::IdAttribute>(Source{}, id);
- spec_id_decos.push_back(cid);
+ spec_id_decos.Push(cid);
break;
}
}
- auto* ast_var = MakeVariable(inst.result_id(), ast::StorageClass::kNone, ast_type, true,
- true, ast_expr, std::move(spec_id_decos));
+ auto* ast_var =
+ MakeOverride(inst.result_id(), ast_type, ast_expr, std::move(spec_id_decos));
if (ast_var) {
builder_.AST().AddGlobalVariable(ast_var);
scalar_spec_constants_.insert(inst.result_id());
@@ -1445,8 +1445,8 @@ bool ParserImpl::EmitModuleScopeVariables() {
}
switch (enum_converter_.ToStorageClass(spirv_storage_class)) {
case ast::StorageClass::kNone:
- case ast::StorageClass::kInput:
- case ast::StorageClass::kOutput:
+ case ast::StorageClass::kIn:
+ case ast::StorageClass::kOut:
case ast::StorageClass::kUniform:
case ast::StorageClass::kHandle:
case ast::StorageClass::kStorage:
@@ -1489,8 +1489,8 @@ bool ParserImpl::EmitModuleScopeVariables() {
// here.)
ast_constructor = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
}
- auto* ast_var = MakeVariable(var.result_id(), ast_storage_class, ast_store_type, false,
- false, ast_constructor, ast::AttributeList{});
+ auto* ast_var = MakeVar(var.result_id(), ast_storage_class, ast_store_type, ast_constructor,
+ utils::Empty);
// TODO(dneto): initializers (a.k.a. constructor expression)
if (ast_var) {
builder_.AST().AddGlobalVariable(ast_var);
@@ -1521,10 +1521,9 @@ bool ParserImpl::EmitModuleScopeVariables() {
}
}
auto* ast_var =
- MakeVariable(builtin_position_.per_vertex_var_id,
- enum_converter_.ToStorageClass(builtin_position_.storage_class),
- ConvertType(builtin_position_.position_member_type_id), false, false,
- ast_constructor, {});
+ MakeVar(builtin_position_.per_vertex_var_id,
+ enum_converter_.ToStorageClass(builtin_position_.storage_class),
+ ConvertType(builtin_position_.position_member_type_id), ast_constructor, {});
builder_.AST().AddGlobalVariable(ast_var);
}
@@ -1554,13 +1553,11 @@ const spvtools::opt::analysis::IntConstant* ParserImpl::GetArraySize(uint32_t va
return size->AsIntConstant();
}
-ast::Variable* ParserImpl::MakeVariable(uint32_t id,
- ast::StorageClass sc,
- const Type* storage_type,
- bool is_const,
- bool is_overridable,
- const ast::Expression* constructor,
- ast::AttributeList decorations) {
+ast::Var* ParserImpl::MakeVar(uint32_t id,
+ ast::StorageClass sc,
+ const Type* storage_type,
+ const ast::Expression* constructor,
+ AttributeList decorations) {
if (storage_type == nullptr) {
Fail() << "internal error: can't make ast::Variable for null type";
return nullptr;
@@ -1588,20 +1585,41 @@ ast::Variable* ParserImpl::MakeVariable(uint32_t id,
return nullptr;
}
- std::string name = namer_.Name(id);
+ auto sym = builder_.Symbols().Register(namer_.Name(id));
+ return create<ast::Var>(Source{}, sym, storage_type->Build(builder_), sc, access, constructor,
+ decorations);
+}
+
+ast::Let* ParserImpl::MakeLet(uint32_t id, const Type* type, const ast::Expression* constructor) {
+ auto sym = builder_.Symbols().Register(namer_.Name(id));
+ return create<ast::Let>(Source{}, sym, type->Build(builder_), constructor, utils::Empty);
+}
- // Note: we're constructing the variable here with the *storage* type,
- // regardless of whether this is a `let`, `override`, or `var` declaration.
- // `var` declarations will have a resolved type of ref<storage>, but at the
- // AST level all three are declared with the same type.
- return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc, access,
- storage_type->Build(builder_), is_const, is_overridable,
- constructor, decorations);
+ast::Override* ParserImpl::MakeOverride(uint32_t id,
+ const Type* type,
+ const ast::Expression* constructor,
+ AttributeList decorations) {
+ if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) {
+ return nullptr;
+ }
+ auto sym = builder_.Symbols().Register(namer_.Name(id));
+ return create<ast::Override>(Source{}, sym, type->Build(builder_), constructor, decorations);
+}
+
+ast::Parameter* ParserImpl::MakeParameter(uint32_t id,
+ const Type* type,
+ AttributeList decorations) {
+ if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) {
+ return nullptr;
+ }
+
+ auto sym = builder_.Symbols().Register(namer_.Name(id));
+ return create<ast::Parameter>(Source{}, sym, type->Build(builder_), decorations);
}
bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
const Type** store_type,
- ast::AttributeList* decorations,
+ AttributeList* decorations,
bool transfer_pipeline_io) {
DecorationList non_builtin_pipeline_decorations;
for (auto& deco : GetDecorationsFor(id)) {
@@ -1656,12 +1674,12 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
break;
}
auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin);
- if (ast_builtin == ast::Builtin::kNone) {
+ if (ast_builtin == ast::BuiltinValue::kInvalid) {
// A diagnostic has already been emitted.
return false;
}
if (transfer_pipeline_io) {
- decorations->emplace_back(create<ast::BuiltinAttribute>(Source{}, ast_builtin));
+ decorations->Push(create<ast::BuiltinAttribute>(Source{}, ast_builtin));
}
}
if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
@@ -1672,13 +1690,13 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
return Fail() << "malformed DescriptorSet decoration on ID " << id
<< ": has no operand";
}
- decorations->emplace_back(create<ast::GroupAttribute>(Source{}, deco[1]));
+ decorations->Push(create<ast::GroupAttribute>(Source{}, deco[1]));
}
if (deco[0] == SpvDecorationBinding) {
if (deco.size() == 1) {
return Fail() << "malformed Binding decoration on ID " << id << ": has no operand";
}
- decorations->emplace_back(create<ast::BindingAttribute>(Source{}, deco[1]));
+ decorations->Push(create<ast::BindingAttribute>(Source{}, deco[1]));
}
}
@@ -1696,8 +1714,8 @@ DecorationList ParserImpl::GetMemberPipelineDecorations(const Struct& struct_typ
int member_index) {
// Yes, I could have used std::copy_if or std::copy_if.
DecorationList result;
- for (const auto& deco :
- GetDecorationsForMember(struct_id_for_symbol_[struct_type.name], member_index)) {
+ for (const auto& deco : GetDecorationsForMember(struct_id_for_symbol_[struct_type.name],
+ static_cast<uint32_t>(member_index))) {
if (IsPipelineDecoration(deco)) {
result.emplace_back(deco);
}
@@ -1705,7 +1723,7 @@ DecorationList ParserImpl::GetMemberPipelineDecorations(const Struct& struct_typ
return result;
}
-const ast::Attribute* ParserImpl::SetLocation(ast::AttributeList* attributes,
+const ast::Attribute* ParserImpl::SetLocation(AttributeList* attributes,
const ast::Attribute* replacement) {
if (!replacement) {
return nullptr;
@@ -1722,13 +1740,13 @@ const ast::Attribute* ParserImpl::SetLocation(ast::AttributeList* attributes,
}
}
// The list didn't have a location. Add it.
- attributes->push_back(replacement);
+ attributes->Push(replacement);
return nullptr;
}
bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
const DecorationList& decorations,
- ast::AttributeList* attributes) {
+ AttributeList* attributes) {
// Vulkan defaults to perspective-correct interpolation.
ast::InterpolationType type = ast::InterpolationType::kPerspective;
ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
@@ -1776,12 +1794,20 @@ bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
}
}
+ if (type == ast::InterpolationType::kFlat &&
+ !ast::HasAttribute<ast::LocationAttribute>(*attributes)) {
+ // WGSL requires that '@interpolate(flat)' needs to be paired with '@location', however
+ // SPIR-V requires all fragment shader integer Inputs are 'flat'. If the decorations do not
+ // contain a SpvDecorationLocation, then make this perspective.
+ type = ast::InterpolationType::kPerspective;
+ }
+
// Apply interpolation.
if (type == ast::InterpolationType::kPerspective &&
sampling == ast::InterpolationSampling::kNone) {
// This is the default. Don't add a decoration.
} else {
- attributes->emplace_back(create<ast::InterpolateAttribute>(type, sampling));
+ attributes->Push(create<ast::InterpolateAttribute>(type, sampling));
}
return success();
@@ -1814,7 +1840,7 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
auto z = MakeConstantExpression(workgroup_size_builtin_.z_id);
auto* ast_type = ty_.Vector(x.type, 3);
return {ast_type, builder_.Construct(Source{}, ast_type->Build(builder_),
- ast::ExpressionList{x.expr, y.expr, z.expr})};
+ utils::Vector{x.expr, y.expr, z.expr})};
} else if (id == workgroup_size_builtin_.x_id) {
return MakeConstantExpressionForScalarSpirvConstant(
Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
@@ -1870,14 +1896,14 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
// Handle vector, matrix, array, and struct
// Generate a composite from explicit components.
- ast::ExpressionList ast_components;
+ ExpressionList ast_components;
if (!inst->WhileEachInId([&](const uint32_t* id_ref) -> bool {
auto component = MakeConstantExpression(*id_ref);
if (!component) {
this->Fail() << "invalid constant with ID " << *id_ref;
return false;
}
- ast_components.emplace_back(component.expr);
+ ast_components.Push(component.expr);
return true;
})) {
// We've already emitted a diagnostic.
@@ -1968,9 +1994,9 @@ const ast::Expression* ParserImpl::MakeNullValue(const Type* type) {
[&](const Array*) { return builder_.Construct(Source{}, type->Build(builder_)); },
[&](const Bool*) { return create<ast::BoolLiteralExpression>(Source{}, false); },
[&](const Struct* struct_ty) {
- ast::ExpressionList ast_components;
+ ExpressionList ast_components;
for (auto* member : struct_ty->members) {
- ast_components.emplace_back(MakeNullValue(member));
+ ast_components.Push(MakeNullValue(member));
}
return builder_.Construct(Source{}, original_type->Build(builder_),
std::move(ast_components));
@@ -2448,7 +2474,7 @@ const Pointer* ParserImpl::GetTypeForHandleVar(const spvtools::opt::Instruction&
} else {
const auto access = ast::Access::kWrite;
const auto format = enum_converter_.ToTexelFormat(image_type->format());
- if (format == ast::TexelFormat::kNone) {
+ if (format == ast::TexelFormat::kInvalid) {
return nullptr;
}
ast_store_type = ty_.StorageTexture(dim, format, access);
@@ -2702,7 +2728,7 @@ std::string ParserImpl::GetMemberName(const Struct& struct_type, int member_inde
Fail() << "no structure type registered for symbol";
return "";
}
- return namer_.GetMemberName(where->second, member_index);
+ return namer_.GetMemberName(where->second, static_cast<uint32_t>(member_index));
}
WorkgroupSizeInfo::WorkgroupSizeInfo() = default;
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.h b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.h
index b91f1924a59..12d62266a84 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.h
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl.h
@@ -22,8 +22,18 @@
#include <utility>
#include <vector>
+#include "src/tint/utils/compiler_macros.h"
+
#if TINT_BUILD_SPV_READER
+TINT_BEGIN_DISABLE_WARNING(NEWLINE_EOF);
+TINT_BEGIN_DISABLE_WARNING(OLD_STYLE_CAST);
+TINT_BEGIN_DISABLE_WARNING(SIGN_CONVERSION);
+TINT_BEGIN_DISABLE_WARNING(WEAK_VTABLES);
#include "source/opt/ir_context.h"
+TINT_END_DISABLE_WARNING(WEAK_VTABLES);
+TINT_END_DISABLE_WARNING(SIGN_CONVERSION);
+TINT_END_DISABLE_WARNING(OLD_STYLE_CAST);
+TINT_END_DISABLE_WARNING(NEWLINE_EOF);
#endif
#include "src/tint/program_builder.h"
@@ -113,6 +123,9 @@ struct WorkgroupSizeInfo {
/// Parser implementation for SPIR-V.
class ParserImpl : Reader {
+ using AttributeList = utils::Vector<const ast::Attribute*, 8>;
+ using ExpressionList = utils::Vector<const ast::Expression*, 8>;
+
public:
/// Creates a new parser
/// @param input the input data to parse
@@ -242,15 +255,14 @@ class ParserImpl : Reader {
/// a diagnostic), or when the variable should not be emitted, e.g. for a
/// PointSize builtin.
/// @param id the ID of the SPIR-V variable
- /// @param store_type the WGSL store type for the variable, which should be
- /// prepopulatd
+ /// @param store_type the WGSL store type for the variable, which should be prepopulated
/// @param attributes the attribute list to populate
/// @param transfer_pipeline_io true if pipeline IO decorations (builtins,
/// or locations) will update the store type and the decorations list
/// @returns false when the variable should not be emitted as a variable
bool ConvertDecorationsForVariable(uint32_t id,
const Type** store_type,
- ast::AttributeList* attributes,
+ AttributeList* attributes,
bool transfer_pipeline_io);
/// Converts SPIR-V decorations for pipeline IO into AST decorations.
@@ -260,7 +272,7 @@ class ParserImpl : Reader {
/// @returns false if conversion fails
bool ConvertPipelineDecorations(const Type* store_type,
const DecorationList& decorations,
- ast::AttributeList* attributes);
+ AttributeList* attributes);
/// Updates the attribute list, placing a non-null location decoration into
/// the list, replacing an existing one if it exists. Does nothing if the
@@ -270,7 +282,7 @@ class ParserImpl : Reader {
/// @param replacement the location decoration to place into the list
/// @returns the location decoration that was replaced, if one was replaced,
/// or null otherwise.
- const ast::Attribute* SetLocation(ast::AttributeList* decos, const ast::Attribute* replacement);
+ const ast::Attribute* SetLocation(AttributeList* decos, const ast::Attribute* replacement);
/// Converts a SPIR-V struct member decoration into a number of AST
/// decorations. If the decoration is recognized but deliberately dropped,
@@ -281,10 +293,10 @@ class ParserImpl : Reader {
/// @param member_ty the type of the member
/// @param decoration an encoded SPIR-V Decoration
/// @returns the AST decorations
- ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
- uint32_t member_index,
- const Type* member_ty,
- const Decoration& decoration);
+ AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
+ uint32_t member_index,
+ const Type* member_ty,
+ const Decoration& decoration);
/// Returns a string for the given type. If the type ID is invalid,
/// then the resulting string only names the type ID.
@@ -411,24 +423,46 @@ class ParserImpl : Reader {
/// @returns a list of SPIR-V decorations.
DecorationList GetMemberPipelineDecorations(const Struct& struct_type, int member_index);
- /// Creates an AST Variable node for a SPIR-V ID, including any attached
- /// decorations, unless it's an ignorable builtin variable.
+ /// Creates an AST 'var' node for a SPIR-V ID, including any attached decorations, unless it's
+ /// an ignorable builtin variable.
/// @param id the SPIR-V result ID
/// @param sc the storage class, which cannot be ast::StorageClass::kNone
/// @param storage_type the storage type of the variable
- /// @param is_const if true, the variable is const
- /// @param is_overridable if true, the variable is pipeline-overridable
/// @param constructor the variable constructor
/// @param decorations the variable decorations
/// @returns a new Variable node, or null in the ignorable variable case and
/// in the error case
- ast::Variable* MakeVariable(uint32_t id,
- ast::StorageClass sc,
- const Type* storage_type,
- bool is_const,
- bool is_overridable,
+ ast::Var* MakeVar(uint32_t id,
+ ast::StorageClass sc,
+ const Type* storage_type,
+ const ast::Expression* constructor,
+ AttributeList decorations);
+
+ /// Creates an AST 'let' node for a SPIR-V ID, including any attached decorations,.
+ /// @param id the SPIR-V result ID
+ /// @param type the type of the variable
+ /// @param constructor the variable constructor
+ /// @returns the AST 'let' node
+ ast::Let* MakeLet(uint32_t id, const Type* type, const ast::Expression* constructor);
+
+ /// Creates an AST 'override' node for a SPIR-V ID, including any attached decorations.
+ /// @param id the SPIR-V result ID
+ /// @param type the type of the variable
+ /// @param constructor the variable constructor
+ /// @param decorations the variable decorations
+ /// @returns the AST 'override' node
+ ast::Override* MakeOverride(uint32_t id,
+ const Type* type,
const ast::Expression* constructor,
- ast::AttributeList decorations);
+ AttributeList decorations);
+
+ /// Creates an AST parameter node for a SPIR-V ID, including any attached decorations, unless
+ /// it's an ignorable builtin variable.
+ /// @param id the SPIR-V result ID
+ /// @param type the type of the parameter
+ /// @param decorations the parameter decorations
+ /// @returns the AST parameter node
+ ast::Parameter* MakeParameter(uint32_t id, const Type* type, AttributeList decorations);
/// Returns true if a constant expression can be generated.
/// @param id the SPIR-V ID of the value
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_barrier_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_barrier_test.cc
index fdfa3bf6815..a59409844bf 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_barrier_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_barrier_test.cc
@@ -65,10 +65,10 @@ TEST_F(SpvParserTest, WorkgroupBarrier) {
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper"));
ASSERT_NE(helper, nullptr);
- ASSERT_GT(helper->body->statements.size(), 0u);
+ ASSERT_GT(helper->body->statements.Length(), 0u);
auto* call = helper->body->statements[0]->As<ast::CallStatement>();
ASSERT_NE(call, nullptr);
- EXPECT_EQ(call->expr->args.size(), 0u);
+ EXPECT_EQ(call->expr->args.Length(), 0u);
auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
ASSERT_NE(sem_call, nullptr);
auto* builtin = sem_call->Target()->As<sem::Builtin>();
@@ -98,10 +98,10 @@ TEST_F(SpvParserTest, StorageBarrier) {
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper"));
ASSERT_NE(helper, nullptr);
- ASSERT_GT(helper->body->statements.size(), 0u);
+ ASSERT_GT(helper->body->statements.Length(), 0u);
auto* call = helper->body->statements[0]->As<ast::CallStatement>();
ASSERT_NE(call, nullptr);
- EXPECT_EQ(call->expr->args.size(), 0u);
+ EXPECT_EQ(call->expr->args.Length(), 0u);
auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
ASSERT_NE(sem_call, nullptr);
auto* builtin = sem_call->Target()->As<sem::Builtin>();
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
index 3147ac12bdf..cd3e7b50023 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
@@ -20,11 +20,11 @@ namespace {
using ::testing::Eq;
-TEST_F(SpvParserTest, ConvertMemberDecoration_Empty) {
+TEST_F(SpvParserTest, ConvertMemberDecoration_IsEmpty) {
auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(1, 1, nullptr, {});
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed SPIR-V decoration: it's empty"));
}
@@ -32,7 +32,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithoutOperand) {
auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset});
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
"operand, has 0: member 13 of SPIR-V type 12"));
}
@@ -41,7 +41,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithTooManyOperands) {
auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset, 3, 4});
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
"operand, has 2: member 13 of SPIR-V type 12"));
}
@@ -50,7 +50,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Offset) {
auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationOffset, 8});
- ASSERT_FALSE(result.empty());
+ ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StructMemberOffsetAttribute>());
auto* offset_deco = result[0]->As<ast::StructMemberOffsetAttribute>();
ASSERT_NE(offset_deco, nullptr);
@@ -64,7 +64,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x2_Stride_Natural) {
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 2);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 8});
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty());
}
@@ -74,7 +74,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x2_Stride_Custom) {
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 2);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
- ASSERT_FALSE(result.empty());
+ ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>();
ASSERT_NE(stride_deco, nullptr);
@@ -88,7 +88,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x4_Stride_Natural) {
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 4);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty());
}
@@ -98,7 +98,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x4_Stride_Custom) {
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 4);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 64});
- ASSERT_FALSE(result.empty());
+ ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>();
ASSERT_NE(stride_deco, nullptr);
@@ -112,7 +112,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x3_Stride_Custom) {
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 3);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 32});
- ASSERT_FALSE(result.empty());
+ ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>();
ASSERT_NE(stride_deco, nullptr);
@@ -127,7 +127,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_RelaxedPrecision) {
auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationRelaxedPrecision});
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty());
}
@@ -135,7 +135,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_UnhandledDecoration) {
auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(12, 13, nullptr, {12345678});
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("unhandled member decoration: 12345678 on member "
"13 of SPIR-V type 12"));
}
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_handle_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_handle_test.cc
index 84f3dcb3efa..e1b4889c4c4 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_handle_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_handle_test.cc
@@ -3076,7 +3076,7 @@ TEST_P(SpvParserHandleTest_ImageCoordsTest, MakeCoordinateOperandsForImageAccess
ASSERT_NE(anchor, nullptr);
const spvtools::opt::Instruction& image_access = *(anchor->PreviousNode());
- ast::ExpressionList result = fe.MakeCoordinateOperandsForImageAccess(image_access);
+ auto result = fe.MakeCoordinateOperandsForImageAccess(image_access);
if (GetParam().expected_error.empty()) {
EXPECT_TRUE(fe.success()) << p->error();
EXPECT_TRUE(p->error().empty());
@@ -3090,7 +3090,7 @@ TEST_P(SpvParserHandleTest_ImageCoordsTest, MakeCoordinateOperandsForImageAccess
} else {
EXPECT_FALSE(fe.success());
EXPECT_THAT(p->error(), Eq(GetParam().expected_error)) << assembly;
- EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(result.IsEmpty());
}
}
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_module_var_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_module_var_test.cc
index e4ac8cbb574..8eb506b8bdc 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_module_var_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_module_var_test.cc
@@ -2537,6 +2537,68 @@ fn main(@builtin(vertex_index) x_1_param : u32) -> main_out {
EXPECT_EQ(module_str, expected) << module_str;
}
+TEST_F(SpvModuleScopeVarParserTest, VertexIndex_UsedTwice_DifferentConstructs) {
+ // Test crbug.com/tint/1577
+ // Builtin variables must not be hoisted. Before the fix, the reader
+ // would see two uses of the variable in different constructs and try
+ // to hoist it. Only function-local definitions should be hoisted.
+ const std::string assembly = VertexIndexPreamble("%uint") + R"(
+ %bool = OpTypeBool
+ %900 = OpConstantTrue %bool
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %2 = OpLoad %uint %1 ; used in outer selection
+ OpSelectionMerge %99 None
+ OpBranchConditional %900 %30 %99
+
+ %30 = OpLabel
+ %3 = OpLoad %uint %1 ; used in inner selection
+ OpSelectionMerge %40 None
+ OpBranchConditional %900 %35 %40
+
+ %35 = OpLabel
+ OpBranch %40
+
+ %40 = OpLabel
+ OpBranch %99
+
+ %99 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+ EXPECT_TRUE(p->error().empty());
+ const auto module_str = test::ToString(p->program());
+ const std::string expected = R"(var<private> x_1 : u32;
+
+var<private> x_5 : vec4<f32>;
+
+fn main_1() {
+ let x_2 : u32 = x_1;
+ if (true) {
+ let x_3 : u32 = x_1;
+ if (true) {
+ }
+ }
+ return;
+}
+
+struct main_out {
+ @builtin(position)
+ x_5_1 : vec4<f32>,
+}
+
+@vertex
+fn main(@builtin(vertex_index) x_1_param : u32) -> main_out {
+ x_1 = x_1_param;
+ main_1();
+ return main_out(x_5);
+}
+)";
+ EXPECT_EQ(module_str, expected) << module_str;
+}
+
TEST_F(SpvModuleScopeVarParserTest, VertexIndex_I32_Load_CopyObject) {
const std::string assembly = VertexIndexPreamble("%int") + R"(
%main = OpFunction %void None %voidfn
@@ -3366,13 +3428,13 @@ TEST_F(SpvModuleScopeVarParserTest, RegisterInputOutputVars) {
const auto& info_1000 = p->GetEntryPointInfo(1000);
EXPECT_EQ(1u, info_1000.size());
- EXPECT_TRUE(info_1000[0].inputs.empty());
- EXPECT_TRUE(info_1000[0].outputs.empty());
+ EXPECT_TRUE(info_1000[0].inputs.IsEmpty());
+ EXPECT_TRUE(info_1000[0].outputs.IsEmpty());
const auto& info_1100 = p->GetEntryPointInfo(1100);
EXPECT_EQ(1u, info_1100.size());
EXPECT_THAT(info_1100[0].inputs, ElementsAre(1));
- EXPECT_TRUE(info_1100[0].outputs.empty());
+ EXPECT_TRUE(info_1100[0].outputs.IsEmpty());
const auto& info_1200 = p->GetEntryPointInfo(1200);
EXPECT_EQ(1u, info_1200.size());
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.cc
index 1e52d815ace..e624984983f 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.cc
@@ -39,7 +39,7 @@ std::string ToString(const Program& program) {
return writer.result();
}
-std::string ToString(const Program& program, const ast::StatementList& stmts) {
+std::string ToString(const Program& program, utils::VectorRef<const ast::Statement*> stmts) {
writer::wgsl::GeneratorImpl writer(&program);
for (const auto* stmt : stmts) {
if (!writer.EmitStatement(stmt)) {
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.h b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.h
index 7362a2d75ed..d1b0e35f84f 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.h
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_impl_test_helper.h
@@ -21,8 +21,18 @@
#include <utility>
#include <vector>
+#include "src/tint/utils/compiler_macros.h"
+
#if TINT_BUILD_SPV_READER
+TINT_BEGIN_DISABLE_WARNING(NEWLINE_EOF);
+TINT_BEGIN_DISABLE_WARNING(OLD_STYLE_CAST);
+TINT_BEGIN_DISABLE_WARNING(SIGN_CONVERSION);
+TINT_BEGIN_DISABLE_WARNING(WEAK_VTABLES);
#include "source/opt/ir_context.h"
+TINT_END_DISABLE_WARNING(WEAK_VTABLES);
+TINT_END_DISABLE_WARNING(SIGN_CONVERSION);
+TINT_END_DISABLE_WARNING(OLD_STYLE_CAST);
+TINT_END_DISABLE_WARNING(NEWLINE_EOF);
#endif
#include "gtest/gtest.h"
@@ -185,10 +195,10 @@ class ParserImplWrapperForTest {
/// @param member_ty the type of the member
/// @param decoration an encoded SPIR-V Decoration
/// @returns the AST decorations
- ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
- uint32_t member_index,
- const Type* member_ty,
- const Decoration& decoration) {
+ auto ConvertMemberDecoration(uint32_t struct_type_id,
+ uint32_t member_index,
+ const Type* member_ty,
+ const Decoration& decoration) {
return impl_.ConvertMemberDecoration(struct_type_id, member_index, member_ty, decoration);
}
@@ -265,7 +275,7 @@ std::string ToString(const Program& program);
/// @param program the Program
/// @param stmts the statement list
/// @returns the WGSL printed string of a statement list.
-std::string ToString(const Program& program, const ast::StatementList& stmts);
+std::string ToString(const Program& program, utils::VectorRef<const ast::Statement*> stmts);
/// Returns the WGSL printed string of an AST node.
/// @param program the Program
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.cc
index 3332cd4f747..5de62f6bce8 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.cc
@@ -21,6 +21,7 @@
#include "src/tint/program_builder.h"
#include "src/tint/utils/hash.h"
#include "src/tint/utils/map.h"
+#include "src/tint/utils/string.h"
#include "src/tint/utils/unique_allocator.h"
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Type);
@@ -163,6 +164,12 @@ const ast::Type* I32::Build(ProgramBuilder& b) const {
return b.ty.i32();
}
+Type::Type() = default;
+Type::Type(const Type&) = default;
+Type::~Type() = default;
+
+Texture::~Texture() = default;
+
Pointer::Pointer(const Type* t, ast::StorageClass s) : type(t), storage_class(s) {}
Pointer::Pointer(const Pointer&) = default;
@@ -512,13 +519,13 @@ std::string I32::String() const {
std::string Pointer::String() const {
std::stringstream ss;
- ss << "ptr<" << std::string(ast::ToString(storage_class)) << ", " << type->String() + ">";
+ ss << "ptr<" << utils::ToString(storage_class) << ", " << type->String() + ">";
return ss.str();
}
std::string Reference::String() const {
std::stringstream ss;
- ss << "ref<" + std::string(ast::ToString(storage_class)) << ", " << type->String() << ">";
+ ss << "ref<" + utils::ToString(storage_class) << ", " << type->String() << ">";
return ss.str();
}
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.h b/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.h
index 605ac9b0b6e..9543b51cc46 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.h
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_type.h
@@ -40,6 +40,13 @@ namespace tint::reader::spirv {
/// Type is the base class for all types
class Type : public Castable<Type> {
public:
+ /// Constructor
+ Type();
+ /// Copy constructor
+ Type(const Type&);
+ /// Destructor
+ ~Type() override;
+
/// @param b the ProgramBuilder used to construct the AST types
/// @returns the constructed ast::Type node for the given type
virtual const ast::Type* Build(ProgramBuilder& b) const = 0;
@@ -314,6 +321,8 @@ struct Sampler final : public Castable<Sampler, Type> {
/// Base class for texture types
struct Texture : public Castable<Texture, Type> {
+ ~Texture() override;
+
/// Constructor
/// @param d the texture dimensions
explicit Texture(ast::TextureDimension d);
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/parser_type_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/parser_type_test.cc
index c031cd75670..37ac113b48a 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/parser_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/parser_type_test.cc
@@ -56,7 +56,7 @@ TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
ty.Pointer(ty.U32(), ast::StorageClass::kNone));
EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
- ty.Pointer(ty.I32(), ast::StorageClass::kInput));
+ ty.Pointer(ty.I32(), ast::StorageClass::kIn));
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.U32(), 3));
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 2));
EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.U32(), 3, 2));
diff --git a/chromium/third_party/dawn/src/tint/reader/spirv/usage_test.cc b/chromium/third_party/dawn/src/tint/reader/spirv/usage_test.cc
index d01d1a264ef..bb64bb35e7b 100644
--- a/chromium/third_party/dawn/src/tint/reader/spirv/usage_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/spirv/usage_test.cc
@@ -45,7 +45,7 @@ TEST_F(SpvParserTest, Usage_Trivial_Output) {
}
TEST_F(SpvParserTest, Usage_Equality_OneDifference) {
- const int num_usages = 9;
+ const size_t num_usages = 9u;
std::vector<Usage> usages(num_usages);
usages[1].AddSampler();
usages[2].AddComparisonSampler();
@@ -55,8 +55,8 @@ TEST_F(SpvParserTest, Usage_Equality_OneDifference) {
usages[6].AddDepthTexture();
usages[7].AddStorageReadTexture();
usages[8].AddStorageWriteTexture();
- for (int i = 0; i < num_usages; ++i) {
- for (int j = 0; j < num_usages; ++j) {
+ for (size_t i = 0; i < num_usages; ++i) {
+ for (size_t j = 0; j < num_usages; ++j) {
const auto& lhs = usages[i];
const auto& rhs = usages[j];
if (i == j) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.cc
index 58e3c85cc5a..0bc19ad1328 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.cc
@@ -19,7 +19,7 @@
#include <cstring>
#include <functional>
#include <limits>
-#include <optional> // NOLINT(build/include_order)
+#include <optional>
#include <tuple>
#include <type_traits>
#include <utility>
@@ -37,6 +37,8 @@ static_assert(sizeof(decltype(tint::Source::FileContent::data[0])) == sizeof(uin
"tint::reader::wgsl requires the size of a std::string element "
"to be a single byte");
+static constexpr size_t kDefaultListSize = 512;
+
bool read_blankspace(std::string_view str, size_t i, bool* is_blankspace, size_t* blankspace_size) {
// See https://www.w3.org/TR/WGSL/#blankspace
@@ -88,6 +90,27 @@ Lexer::Lexer(const Source::File* file) : file_(file), location_{1, 1} {}
Lexer::~Lexer() = default;
+std::vector<Token> Lexer::Lex() {
+ std::vector<Token> tokens;
+ tokens.reserve(kDefaultListSize);
+ while (true) {
+ tokens.emplace_back(next());
+
+ // If the token can be split, we insert a placeholder element into
+ // the stream to hold the split character.
+ if (tokens.back().IsSplittable()) {
+ auto src = tokens.back().source();
+ src.range.begin.column++;
+ tokens.emplace_back(Token(Token::Type::kPlaceholder, src));
+ }
+
+ if (tokens.back().IsEof() || tokens.back().IsError()) {
+ break;
+ }
+ }
+ return tokens;
+}
+
const std::string_view Lexer::line() const {
if (file_->content.lines.size() == 0) {
static const char* empty_string = "";
@@ -204,6 +227,13 @@ bool Lexer::matches(size_t pos, std::string_view sub_string) {
return substr(pos, sub_string.size()) == sub_string;
}
+bool Lexer::matches(size_t pos, char ch) {
+ if (pos >= length()) {
+ return false;
+ }
+ return line()[pos] == ch;
+}
+
Token Lexer::skip_blankspace_and_comments() {
for (;;) {
auto loc = location_;
@@ -298,7 +328,7 @@ Token Lexer::try_float() {
auto source = begin_source();
bool has_mantissa_digits = false;
- if (matches(end, "-")) {
+ if (matches(end, '-')) {
end++;
}
while (end < length() && is_digit(at(end))) {
@@ -307,7 +337,7 @@ Token Lexer::try_float() {
}
bool has_point = false;
- if (end < length() && matches(end, ".")) {
+ if (end < length() && matches(end, '.')) {
has_point = true;
end++;
}
@@ -323,9 +353,9 @@ Token Lexer::try_float() {
// Parse the exponent if one exists
bool has_exponent = false;
- if (end < length() && (matches(end, "e") || matches(end, "E"))) {
+ if (end < length() && (matches(end, 'e') || matches(end, 'E'))) {
end++;
- if (end < length() && (matches(end, "+") || matches(end, "-"))) {
+ if (end < length() && (matches(end, '+') || matches(end, '-'))) {
end++;
}
@@ -343,19 +373,20 @@ Token Lexer::try_float() {
}
bool has_f_suffix = false;
- if (end < length() && matches(end, "f")) {
+ bool has_h_suffix = false;
+ if (end < length() && matches(end, 'f')) {
end++;
has_f_suffix = true;
+ } else if (end < length() && matches(end, 'h')) {
+ end++;
+ has_h_suffix = true;
}
- if (!has_point && !has_exponent && !has_f_suffix) {
+ if (!has_point && !has_exponent && !has_f_suffix && !has_h_suffix) {
// If it only has digits then it's an integer.
return {};
}
- // Save the error string, for use by diagnostics.
- const auto str = std::string{substr(start, end - start)};
-
advance(end - start);
end_source(source);
@@ -369,6 +400,14 @@ Token Lexer::try_float() {
}
}
+ if (has_h_suffix) {
+ if (auto f = CheckedConvert<f16>(AFloat(value))) {
+ return {Token::Type::kFloatLiteral_H, source, static_cast<double>(f.Get())};
+ } else {
+ return {Token::Type::kError, source, "value cannot be represented as 'f16'"};
+ }
+ }
+
if (value == HUGE_VAL || -value == HUGE_VAL) {
return {Token::Type::kError, source, "value cannot be represented as 'abstract-float'"};
} else {
@@ -400,13 +439,13 @@ Token Lexer::try_hex_float() {
// clang-format on
// -?
- int64_t sign_bit = 0;
- if (matches(end, "-")) {
+ uint64_t sign_bit = 0;
+ if (matches(end, '-')) {
sign_bit = 1;
end++;
}
// 0[xX]
- if (matches(end, "0x") || matches(end, "0X")) {
+ if (matches(end, '0') && (matches(end + 1, 'x') || matches(end + 1, 'X'))) {
end += 2;
} else {
return {};
@@ -452,7 +491,7 @@ Token Lexer::try_hex_float() {
// .?
bool hex_point = false;
- if (matches(end, ".")) {
+ if (matches(end, '.')) {
hex_point = true;
end++;
}
@@ -470,7 +509,7 @@ Token Lexer::try_hex_float() {
}
// Is the binary exponent present? It's optional.
- const bool has_exponent = (matches(end, "p") || matches(end, "P"));
+ const bool has_exponent = (matches(end, 'p') || matches(end, 'P'));
if (has_exponent) {
end++;
}
@@ -547,12 +586,13 @@ Token Lexer::try_hex_float() {
int64_t exponent_sign = 1;
// If the 'p' part is present, the rest of the exponent must exist.
bool has_f_suffix = false;
+ bool has_h_suffix = false;
if (has_exponent) {
// Parse the rest of the exponent.
// (+|-)?
- if (matches(end, "+")) {
+ if (matches(end, '+')) {
end++;
- } else if (matches(end, "-")) {
+ } else if (matches(end, '-')) {
exponent_sign = -1;
end++;
}
@@ -574,12 +614,15 @@ Token Lexer::try_hex_float() {
end++;
}
- // Parse optional 'f' suffix. For a hex float, it can only exist
+ // Parse optional 'f' or 'h' suffix. For a hex float, it can only exist
// when the exponent is present. Otherwise it will look like
// one of the mantissa digits.
- if (end < length() && matches(end, "f")) {
+ if (end < length() && matches(end, 'f')) {
has_f_suffix = true;
end++;
+ } else if (end < length() && matches(end, 'h')) {
+ has_h_suffix = true;
+ end++;
}
if (!has_exponent_digits) {
@@ -648,7 +691,7 @@ Token Lexer::try_hex_float() {
}
if (signed_exponent >= kExponentMax || (signed_exponent == kExponentMax && mantissa != 0)) {
- std::string type = has_f_suffix ? "f32" : "abstract-float";
+ std::string type = has_f_suffix ? "f32" : (has_h_suffix ? "f16" : "abstract-float");
return {Token::Type::kError, source, "value cannot be represented as '" + type + "'"};
}
@@ -663,18 +706,111 @@ Token Lexer::try_hex_float() {
if (has_f_suffix) {
// Check value fits in f32
- if (result_f64 < static_cast<double>(f32::kLowest) ||
- result_f64 > static_cast<double>(f32::kHighest)) {
+ if (result_f64 < static_cast<double>(f32::kLowestValue) ||
+ result_f64 > static_cast<double>(f32::kHighestValue)) {
return {Token::Type::kError, source, "value cannot be represented as 'f32'"};
}
- // Check the value can be exactly represented (low 29 mantissa bits must be 0)
- if (result_u64 & 0x1fffffff) {
+ // Check the value can be exactly represented, i.e. only high 23 mantissa bits are valid for
+ // normal f32 values, and less for subnormal f32 values. The rest low mantissa bits must be
+ // 0.
+ int valid_mantissa_bits = 0;
+ double abs_result_f64 = std::fabs(result_f64);
+ if (abs_result_f64 >= static_cast<double>(f32::kSmallestValue)) {
+ // The result shall be a normal f32 value.
+ valid_mantissa_bits = 23;
+ } else if (abs_result_f64 >= static_cast<double>(f32::kSmallestSubnormalValue)) {
+ // The result shall be a subnormal f32 value, represented as double.
+ // The smallest positive normal f32 is f32::kSmallestValue = 2^-126 = 0x1.0p-126, and
+ // the
+ // smallest positive subnormal f32 is f32::kSmallestSubnormalValue = 2^-149. Thus, the
+ // value v in range 2^-126 > v >= 2^-149 must be represented as a subnormal f32
+ // number, but is still normal double (f64) number, and has a exponent in range -127
+ // to -149, inclusive.
+ // A value v, if 2^-126 > v >= 2^-127, its binary32 representation will have binary form
+ // s_00000000_1xxxxxxxxxxxxxxxxxxxxxx, having mantissa of 1 leading 1 bit and 22
+ // arbitrary bits. Since this value is represented as normal double number, the
+ // leading 1 bit is omitted, only the highest 22 mantissia bits can be arbitrary, and
+ // the rest lowest 40 mantissa bits of f64 number must be zero.
+ // 2^-127 > v >= 2^-128, binary32 s_00000000_01xxxxxxxxxxxxxxxxxxxxx, having mantissa of
+ // 1 leading 0 bit, 1 leading 1 bit, and 21 arbitrary bits. The f64 representation
+ // omits the leading 0 and 1 bits, and only the highest 21 mantissia bits can be
+ // arbitrary.
+ // 2^-128 > v >= 2^-129, binary32 s_00000000_001xxxxxxxxxxxxxxxxxxxx, 20 arbitrary bits.
+ // ...
+ // 2^-147 > v >= 2^-148, binary32 s_00000000_0000000000000000000001x, 1 arbitrary bit.
+ // 2^-148 > v >= 2^-149, binary32 s_00000000_00000000000000000000001, 0 arbitrary bit.
+
+ // signed_exponent must be in range -149 + 1023 = 874 to -127 + 1023 = 896, inclusive
+ TINT_ASSERT(Reader, (874 <= signed_exponent) && (signed_exponent <= 896));
+ int unbiased_exponent =
+ static_cast<int>(signed_exponent) - static_cast<int>(kExponentBias);
+ TINT_ASSERT(Reader, (-149 <= unbiased_exponent) && (unbiased_exponent <= -127));
+ valid_mantissa_bits = unbiased_exponent + 149; // 0 for -149, and 22 for -127
+ } else if (abs_result_f64 != 0.0) {
+ // The result is smaller than the smallest subnormal f32 value, but not equal to zero.
+ // Such value will never be exactly represented by f32.
return {Token::Type::kError, source, "value cannot be exactly represented as 'f32'"};
}
+ // Check the low 52-valid_mantissa_bits mantissa bits must be 0.
+ TINT_ASSERT(Reader, (0 <= valid_mantissa_bits) && (valid_mantissa_bits <= 23));
+ if (result_u64 & ((uint64_t(1) << (52 - valid_mantissa_bits)) - 1)) {
+ return {Token::Type::kError, source, "value cannot be exactly represented as 'f32'"};
+ }
+ return {Token::Type::kFloatLiteral_F, source, result_f64};
+ } else if (has_h_suffix) {
+ // Check value fits in f16
+ if (result_f64 < static_cast<double>(f16::kLowestValue) ||
+ result_f64 > static_cast<double>(f16::kHighestValue)) {
+ return {Token::Type::kError, source, "value cannot be represented as 'f16'"};
+ }
+ // Check the value can be exactly represented, i.e. only high 10 mantissa bits are valid for
+ // normal f16 values, and less for subnormal f16 values. The rest low mantissa bits must be
+ // 0.
+ int valid_mantissa_bits = 0;
+ double abs_result_f64 = std::fabs(result_f64);
+ if (abs_result_f64 >= static_cast<double>(f16::kSmallestValue)) {
+ // The result shall be a normal f16 value.
+ valid_mantissa_bits = 10;
+ } else if (abs_result_f64 >= static_cast<double>(f16::kSmallestSubnormalValue)) {
+ // The result shall be a subnormal f16 value, represented as double.
+ // The smallest positive normal f16 is f16::kSmallestValue = 2^-14 = 0x1.0p-14, and the
+ // smallest positive subnormal f16 is f16::kSmallestSubnormalValue = 2^-24. Thus, the
+ // value v in range 2^-14 > v >= 2^-24 must be represented as a subnormal f16 number,
+ // but is still normal double (f64) number, and has a exponent in range -15 to -24,
+ // inclusive.
+ // A value v, if 2^-14 > v >= 2^-15, its binary16 representation will have binary form
+ // s_00000_1xxxxxxxxx, having mantissa of 1 leading 1 bit and 9 arbitrary bits. Since
+ // this value is represented as normal double number, the leading 1 bit is omitted,
+ // only the highest 9 mantissia bits can be arbitrary, and the rest lowest 43 mantissa
+ // bits of f64 number must be zero.
+ // 2^-15 > v >= 2^-16, binary16 s_00000_01xxxxxxxx, having mantissa of 1 leading 0 bit,
+ // 1 leading 1 bit, and 8 arbitrary bits. The f64 representation omits the leading 0
+ // and 1 bits, and only the highest 8 mantissia bits can be arbitrary.
+ // 2^-16 > v >= 2^-17, binary16 s_00000_001xxxxxxx, 7 arbitrary bits.
+ // ...
+ // 2^-22 > v >= 2^-23, binary16 s_00000_000000001x, 1 arbitrary bits.
+ // 2^-23 > v >= 2^-24, binary16 s_00000_0000000001, 0 arbitrary bits.
+
+ // signed_exponent must be in range -24 + 1023 = 999 to -15 + 1023 = 1008, inclusive
+ TINT_ASSERT(Reader, (999 <= signed_exponent) && (signed_exponent <= 1008));
+ int unbiased_exponent =
+ static_cast<int>(signed_exponent) - static_cast<int>(kExponentBias);
+ TINT_ASSERT(Reader, (-24 <= unbiased_exponent) && (unbiased_exponent <= -15));
+ valid_mantissa_bits = unbiased_exponent + 24; // 0 for -24, and 9 for -15
+ } else if (abs_result_f64 != 0.0) {
+ // The result is smaller than the smallest subnormal f16 value, but not equal to zero.
+ // Such value will never be exactly represented by f16.
+ return {Token::Type::kError, source, "value cannot be exactly represented as 'f16'"};
+ }
+ // Check the low 52-valid_mantissa_bits mantissa bits must be 0.
+ TINT_ASSERT(Reader, (0 <= valid_mantissa_bits) && (valid_mantissa_bits <= 10));
+ if (result_u64 & ((uint64_t(1) << (52 - valid_mantissa_bits)) - 1)) {
+ return {Token::Type::kError, source, "value cannot be exactly represented as 'f16'"};
+ }
+ return {Token::Type::kFloatLiteral_H, source, result_f64};
}
- return {has_f_suffix ? Token::Type::kFloatLiteral_F : Token::Type::kFloatLiteral, source,
- result_f64};
+ return {Token::Type::kFloatLiteral, source, result_f64};
}
Token Lexer::build_token_from_int_if_possible(Source source, size_t start, int32_t base) {
@@ -686,10 +822,10 @@ Token Lexer::build_token_from_int_if_possible(Source source, size_t start, int32
const bool overflow = errno == ERANGE;
if (end_ptr) {
- advance(end_ptr - start_ptr);
+ advance(static_cast<size_t>(end_ptr - start_ptr));
}
- if (matches(pos(), "u")) {
+ if (matches(pos(), 'u')) {
if (!overflow && CheckedConvert<u32>(AInt(res))) {
advance(1);
end_source(source);
@@ -698,7 +834,7 @@ Token Lexer::build_token_from_int_if_possible(Source source, size_t start, int32
return {Token::Type::kError, source, "value cannot be represented as 'u32'"};
}
- if (matches(pos(), "i")) {
+ if (matches(pos(), 'i')) {
if (!overflow && CheckedConvert<i32>(AInt(res))) {
advance(1);
end_source(source);
@@ -720,11 +856,11 @@ Token Lexer::try_hex_integer() {
auto source = begin_source();
- if (matches(curr, "-")) {
+ if (matches(curr, '-')) {
curr++;
}
- if (matches(curr, "0x") || matches(curr, "0X")) {
+ if (matches(curr, '0') && (matches(curr + 1, 'x') || matches(curr + 1, 'X'))) {
curr += 2;
} else {
return {};
@@ -744,7 +880,7 @@ Token Lexer::try_integer() {
auto source = begin_source();
- if (matches(curr, "-")) {
+ if (matches(curr, '-')) {
curr++;
}
@@ -822,138 +958,172 @@ Token Lexer::try_punctuation() {
auto source = begin_source();
auto type = Token::Type::kUninitialized;
- if (matches(pos(), "@")) {
+ if (matches(pos(), '@')) {
type = Token::Type::kAttr;
advance(1);
- } else if (matches(pos(), "(")) {
+ } else if (matches(pos(), '(')) {
type = Token::Type::kParenLeft;
advance(1);
- } else if (matches(pos(), ")")) {
+ } else if (matches(pos(), ')')) {
type = Token::Type::kParenRight;
advance(1);
- } else if (matches(pos(), "[")) {
+ } else if (matches(pos(), '[')) {
type = Token::Type::kBracketLeft;
advance(1);
- } else if (matches(pos(), "]")) {
+ } else if (matches(pos(), ']')) {
type = Token::Type::kBracketRight;
advance(1);
- } else if (matches(pos(), "{")) {
+ } else if (matches(pos(), '{')) {
type = Token::Type::kBraceLeft;
advance(1);
- } else if (matches(pos(), "}")) {
+ } else if (matches(pos(), '}')) {
type = Token::Type::kBraceRight;
advance(1);
- } else if (matches(pos(), "&&")) {
- type = Token::Type::kAndAnd;
- advance(2);
- } else if (matches(pos(), "&=")) {
- type = Token::Type::kAndEqual;
- advance(2);
- } else if (matches(pos(), "&")) {
- type = Token::Type::kAnd;
- advance(1);
- } else if (matches(pos(), "/=")) {
- type = Token::Type::kDivisionEqual;
- advance(2);
- } else if (matches(pos(), "/")) {
- type = Token::Type::kForwardSlash;
- advance(1);
- } else if (matches(pos(), "!=")) {
- type = Token::Type::kNotEqual;
- advance(2);
- } else if (matches(pos(), "!")) {
- type = Token::Type::kBang;
- advance(1);
- } else if (matches(pos(), ":")) {
+ } else if (matches(pos(), '&')) {
+ if (matches(pos() + 1, '&')) {
+ type = Token::Type::kAndAnd;
+ advance(2);
+ } else if (matches(pos() + 1, '=')) {
+ type = Token::Type::kAndEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kAnd;
+ advance(1);
+ }
+ } else if (matches(pos(), '/')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kDivisionEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kForwardSlash;
+ advance(1);
+ }
+ } else if (matches(pos(), '!')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kNotEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kBang;
+ advance(1);
+ }
+ } else if (matches(pos(), ':')) {
type = Token::Type::kColon;
advance(1);
- } else if (matches(pos(), ",")) {
+ } else if (matches(pos(), ',')) {
type = Token::Type::kComma;
advance(1);
- } else if (matches(pos(), "==")) {
- type = Token::Type::kEqualEqual;
- advance(2);
- } else if (matches(pos(), "=")) {
- type = Token::Type::kEqual;
- advance(1);
- } else if (matches(pos(), ">=")) {
- type = Token::Type::kGreaterThanEqual;
- advance(2);
- } else if (matches(pos(), ">>")) {
- type = Token::Type::kShiftRight;
- advance(2);
- } else if (matches(pos(), ">")) {
- type = Token::Type::kGreaterThan;
- advance(1);
- } else if (matches(pos(), "<=")) {
- type = Token::Type::kLessThanEqual;
- advance(2);
- } else if (matches(pos(), "<<")) {
- type = Token::Type::kShiftLeft;
- advance(2);
- } else if (matches(pos(), "<")) {
- type = Token::Type::kLessThan;
- advance(1);
- } else if (matches(pos(), "%=")) {
- type = Token::Type::kModuloEqual;
- advance(2);
- } else if (matches(pos(), "%")) {
- type = Token::Type::kMod;
- advance(1);
- } else if (matches(pos(), "->")) {
- type = Token::Type::kArrow;
- advance(2);
- } else if (matches(pos(), "--")) {
- type = Token::Type::kMinusMinus;
- advance(2);
- } else if (matches(pos(), "-=")) {
- type = Token::Type::kMinusEqual;
- advance(2);
- } else if (matches(pos(), "-")) {
- type = Token::Type::kMinus;
- advance(1);
- } else if (matches(pos(), ".")) {
+ } else if (matches(pos(), '=')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kEqualEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kEqual;
+ advance(1);
+ }
+ } else if (matches(pos(), '>')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kGreaterThanEqual;
+ advance(2);
+ } else if (matches(pos() + 1, '>')) {
+ if (matches(pos() + 2, '=')) {
+ type = Token::Type::kShiftRightEqual;
+ advance(3);
+ } else {
+ type = Token::Type::kShiftRight;
+ advance(2);
+ }
+ } else {
+ type = Token::Type::kGreaterThan;
+ advance(1);
+ }
+ } else if (matches(pos(), '<')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kLessThanEqual;
+ advance(2);
+ } else if (matches(pos() + 1, '<')) {
+ if (matches(pos() + 2, '=')) {
+ type = Token::Type::kShiftLeftEqual;
+ advance(3);
+ } else {
+ type = Token::Type::kShiftLeft;
+ advance(2);
+ }
+ } else {
+ type = Token::Type::kLessThan;
+ advance(1);
+ }
+ } else if (matches(pos(), '%')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kModuloEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kMod;
+ advance(1);
+ }
+ } else if (matches(pos(), '-')) {
+ if (matches(pos() + 1, '>')) {
+ type = Token::Type::kArrow;
+ advance(2);
+ } else if (matches(pos() + 1, '-')) {
+ type = Token::Type::kMinusMinus;
+ advance(2);
+ } else if (matches(pos() + 1, '=')) {
+ type = Token::Type::kMinusEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kMinus;
+ advance(1);
+ }
+ } else if (matches(pos(), '.')) {
type = Token::Type::kPeriod;
advance(1);
- } else if (matches(pos(), "++")) {
- type = Token::Type::kPlusPlus;
- advance(2);
- } else if (matches(pos(), "+=")) {
- type = Token::Type::kPlusEqual;
- advance(2);
- } else if (matches(pos(), "+")) {
- type = Token::Type::kPlus;
- advance(1);
- } else if (matches(pos(), "||")) {
- type = Token::Type::kOrOr;
- advance(2);
- } else if (matches(pos(), "|=")) {
- type = Token::Type::kOrEqual;
- advance(2);
- } else if (matches(pos(), "|")) {
- type = Token::Type::kOr;
- advance(1);
- } else if (matches(pos(), ";")) {
+ } else if (matches(pos(), '+')) {
+ if (matches(pos() + 1, '+')) {
+ type = Token::Type::kPlusPlus;
+ advance(2);
+ } else if (matches(pos() + 1, '=')) {
+ type = Token::Type::kPlusEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kPlus;
+ advance(1);
+ }
+ } else if (matches(pos(), '|')) {
+ if (matches(pos() + 1, '|')) {
+ type = Token::Type::kOrOr;
+ advance(2);
+ } else if (matches(pos() + 1, '=')) {
+ type = Token::Type::kOrEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kOr;
+ advance(1);
+ }
+ } else if (matches(pos(), ';')) {
type = Token::Type::kSemicolon;
advance(1);
- } else if (matches(pos(), "*=")) {
- type = Token::Type::kTimesEqual;
- advance(2);
- } else if (matches(pos(), "*")) {
- type = Token::Type::kStar;
- advance(1);
- } else if (matches(pos(), "~")) {
+ } else if (matches(pos(), '*')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kTimesEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kStar;
+ advance(1);
+ }
+ } else if (matches(pos(), '~')) {
type = Token::Type::kTilde;
advance(1);
- } else if (matches(pos(), "_")) {
+ } else if (matches(pos(), '_')) {
type = Token::Type::kUnderscore;
advance(1);
- } else if (matches(pos(), "^=")) {
- type = Token::Type::kXorEqual;
- advance(2);
- } else if (matches(pos(), "^")) {
- type = Token::Type::kXor;
- advance(1);
+ } else if (matches(pos(), '^')) {
+ if (matches(pos() + 1, '=')) {
+ type = Token::Type::kXorEqual;
+ advance(2);
+ } else {
+ type = Token::Type::kXor;
+ advance(1);
+ }
}
end_source(source);
@@ -980,6 +1150,9 @@ Token Lexer::check_keyword(const Source& source, std::string_view str) {
if (str == "case") {
return {Token::Type::kCase, source, "case"};
}
+ if (str == "const") {
+ return {Token::Type::kConst, source, "const"};
+ }
if (str == "continue") {
return {Token::Type::kContinue, source, "continue"};
}
@@ -1016,18 +1189,12 @@ Token Lexer::check_keyword(const Source& source, std::string_view str) {
if (str == "for") {
return {Token::Type::kFor, source, "for"};
}
- if (str == "function") {
- return {Token::Type::kFunction, source, "function"};
- }
if (str == "i32") {
return {Token::Type::kI32, source, "i32"};
}
if (str == "if") {
return {Token::Type::kIf, source, "if"};
}
- if (str == "import") {
- return {Token::Type::kImport, source, "import"};
- }
if (str == "let") {
return {Token::Type::kLet, source, "let"};
}
@@ -1064,9 +1231,6 @@ Token Lexer::check_keyword(const Source& source, std::string_view str) {
if (str == "override") {
return {Token::Type::kOverride, source, "override"};
}
- if (str == "private") {
- return {Token::Type::kPrivate, source, "private"};
- }
if (str == "ptr") {
return {Token::Type::kPtr, source, "ptr"};
}
@@ -1079,8 +1243,8 @@ Token Lexer::check_keyword(const Source& source, std::string_view str) {
if (str == "sampler_comparison") {
return {Token::Type::kComparisonSampler, source, "sampler_comparison"};
}
- if (str == "storage_buffer" || str == "storage") {
- return {Token::Type::kStorage, source, "storage"};
+ if (str == "static_assert") {
+ return {Token::Type::kStaticAssert, source, "static_assert"};
}
if (str == "struct") {
return {Token::Type::kStruct, source, "struct"};
@@ -1148,9 +1312,6 @@ Token Lexer::check_keyword(const Source& source, std::string_view str) {
if (str == "u32") {
return {Token::Type::kU32, source, "u32"};
}
- if (str == "uniform") {
- return {Token::Type::kUniform, source, "uniform"};
- }
if (str == "var") {
return {Token::Type::kVar, source, "var"};
}
@@ -1163,8 +1324,8 @@ Token Lexer::check_keyword(const Source& source, std::string_view str) {
if (str == "vec4") {
return {Token::Type::kVec4, source, "vec4"};
}
- if (str == "workgroup") {
- return {Token::Type::kWorkgroup, source, "workgroup"};
+ if (str == "while") {
+ return {Token::Type::kWhile, source, "while"};
}
return {};
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.h b/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.h
index d93848ff5d0..8e0306b6a8b 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.h
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/lexer.h
@@ -16,6 +16,7 @@
#define SRC_TINT_READER_WGSL_LEXER_H_
#include <string>
+#include <vector>
#include "src/tint/reader/wgsl/token.h"
@@ -29,11 +30,14 @@ class Lexer {
explicit Lexer(const Source::File* file);
~Lexer();
+ /// @return the token list.
+ std::vector<Token> Lex();
+
+ private:
/// Returns the next token in the input stream.
/// @return Token
Token next();
- private:
/// Advances past blankspace and comments, if present at the current position.
/// @returns error token, EOF, or uninitialized
Token skip_blankspace_and_comments();
@@ -96,7 +100,8 @@ class Lexer {
bool is_hex(char ch) const;
/// @returns true if string at `pos` matches `substr`
bool matches(size_t pos, std::string_view substr);
-
+ /// @returns true if char at `pos` matches `ch`
+ bool matches(size_t pos, char ch);
/// The source file content
Source::File const* const file_;
/// The current location within the input
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/lexer_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/lexer_test.cc
index 16ae46d4304..dfd1b851a85 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/lexer_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/lexer_test.cc
@@ -19,6 +19,7 @@
#include <vector>
#include "gtest/gtest.h"
+#include "src/tint/number.h"
namespace tint::reader::wgsl {
namespace {
@@ -45,24 +46,33 @@ using LexerTest = testing::Test;
TEST_F(LexerTest, Empty) {
Source::File file("", "");
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsEof());
+
+ auto list = l.Lex();
+ ASSERT_EQ(1u, list.size());
+ EXPECT_TRUE(list[0].IsEof());
}
TEST_F(LexerTest, Skips_Blankspace_Basic) {
Source::File file("", "\t\r\n\t ident\t\n\t \r ");
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 2u);
- EXPECT_EQ(t.source().range.begin.column, 6u);
- EXPECT_EQ(t.source().range.end.line, 2u);
- EXPECT_EQ(t.source().range.end.column, 11u);
- EXPECT_EQ(t.to_str(), "ident");
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 2u);
+ EXPECT_EQ(t.source().range.begin.column, 6u);
+ EXPECT_EQ(t.source().range.end.line, 2u);
+ EXPECT_EQ(t.source().range.end.column, 11u);
+ EXPECT_EQ(t.to_str(), "ident");
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsEof());
+ }
}
TEST_F(LexerTest, Skips_Blankspace_Exotic) {
@@ -72,16 +82,23 @@ TEST_F(LexerTest, Skips_Blankspace_Exotic) {
kVTab kFF kNL kLS kPS kL2R kR2L);
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 6u);
- EXPECT_EQ(t.source().range.begin.column, 7u);
- EXPECT_EQ(t.source().range.end.line, 6u);
- EXPECT_EQ(t.source().range.end.column, 12u);
- EXPECT_EQ(t.to_str(), "ident");
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 6u);
+ EXPECT_EQ(t.source().range.begin.column, 7u);
+ EXPECT_EQ(t.source().range.end.line, 6u);
+ EXPECT_EQ(t.source().range.end.column, 12u);
+ EXPECT_EQ(t.to_str(), "ident");
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsEof());
+ }
}
TEST_F(LexerTest, Skips_Comments_Line) {
@@ -91,24 +108,33 @@ ident1 //ends with comment
ident2)");
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 2u);
- EXPECT_EQ(t.source().range.begin.column, 1u);
- EXPECT_EQ(t.source().range.end.line, 2u);
- EXPECT_EQ(t.source().range.end.column, 7u);
- EXPECT_EQ(t.to_str(), "ident1");
+ auto list = l.Lex();
+ ASSERT_EQ(3u, list.size());
- t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 4u);
- EXPECT_EQ(t.source().range.begin.column, 2u);
- EXPECT_EQ(t.source().range.end.line, 4u);
- EXPECT_EQ(t.source().range.end.column, 8u);
- EXPECT_EQ(t.to_str(), "ident2");
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 2u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 2u);
+ EXPECT_EQ(t.source().range.end.column, 7u);
+ EXPECT_EQ(t.to_str(), "ident1");
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 4u);
+ EXPECT_EQ(t.source().range.begin.column, 2u);
+ EXPECT_EQ(t.source().range.end.line, 4u);
+ EXPECT_EQ(t.source().range.end.column, 8u);
+ EXPECT_EQ(t.to_str(), "ident2");
+ }
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[2];
+ EXPECT_TRUE(t.IsEof());
+ }
}
TEST_F(LexerTest, Skips_Comments_Unicode) {
@@ -118,24 +144,33 @@ ident1 //ends with 🙂🙂🙂
ident2)");
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 2u);
- EXPECT_EQ(t.source().range.begin.column, 1u);
- EXPECT_EQ(t.source().range.end.line, 2u);
- EXPECT_EQ(t.source().range.end.column, 7u);
- EXPECT_EQ(t.to_str(), "ident1");
+ auto list = l.Lex();
+ ASSERT_EQ(3u, list.size());
- t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 4u);
- EXPECT_EQ(t.source().range.begin.column, 2u);
- EXPECT_EQ(t.source().range.end.line, 4u);
- EXPECT_EQ(t.source().range.end.column, 8u);
- EXPECT_EQ(t.to_str(), "ident2");
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 2u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 2u);
+ EXPECT_EQ(t.source().range.end.column, 7u);
+ EXPECT_EQ(t.to_str(), "ident1");
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 4u);
+ EXPECT_EQ(t.source().range.begin.column, 2u);
+ EXPECT_EQ(t.source().range.end.line, 4u);
+ EXPECT_EQ(t.source().range.end.column, 8u);
+ EXPECT_EQ(t.to_str(), "ident2");
+ }
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[2];
+ EXPECT_TRUE(t.IsEof());
+ }
}
using LineCommentTerminatorTest = testing::TestWithParam<const char*>;
@@ -143,27 +178,35 @@ TEST_P(LineCommentTerminatorTest, Terminators) {
// Test that line comments are ended by blankspace characters other than
// space, horizontal tab, left-to-right mark, and right-to-left mark.
auto* c = GetParam();
- std::string src = "let// This is a comment";
+ std::string src = "const// This is a comment";
src += c;
src += "ident";
Source::File file("", src);
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.Is(Token::Type::kLet));
- EXPECT_EQ(t.source().range.begin.line, 1u);
- EXPECT_EQ(t.source().range.begin.column, 1u);
- EXPECT_EQ(t.source().range.end.line, 1u);
- EXPECT_EQ(t.source().range.end.column, 4u);
-
auto is_same_line = [](std::string_view v) {
return v == kSpace || v == kHTab || v == kL2R || v == kR2L;
};
+ auto list = l.Lex();
+ ASSERT_EQ(is_same_line(c) ? 2u : 3u, list.size());
+
+ size_t idx = 0;
+
+ {
+ auto& t = list[idx++];
+ EXPECT_TRUE(t.Is(Token::Type::kConst));
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 6u);
+ }
+
if (!is_same_line(c)) {
size_t line = is_same_line(c) ? 1u : 2u;
size_t col = is_same_line(c) ? 25u : 1u;
- t = l.next();
+
+ auto& t = list[idx++];
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, line);
EXPECT_EQ(t.source().range.begin.column, col);
@@ -172,8 +215,10 @@ TEST_P(LineCommentTerminatorTest, Terminators) {
EXPECT_EQ(t.to_str(), "ident");
}
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[idx];
+ EXPECT_TRUE(t.IsEof());
+ }
}
INSTANTIATE_TEST_SUITE_P(LexerTest,
LineCommentTerminatorTest,
@@ -197,16 +242,23 @@ TEST_F(LexerTest, Skips_Comments_Block) {
text */ident)");
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 2u);
- EXPECT_EQ(t.source().range.begin.column, 8u);
- EXPECT_EQ(t.source().range.end.line, 2u);
- EXPECT_EQ(t.source().range.end.column, 13u);
- EXPECT_EQ(t.to_str(), "ident");
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
+
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 2u);
+ EXPECT_EQ(t.source().range.begin.column, 8u);
+ EXPECT_EQ(t.source().range.end.line, 2u);
+ EXPECT_EQ(t.source().range.end.column, 13u);
+ EXPECT_EQ(t.to_str(), "ident");
+ }
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsEof());
+ }
}
TEST_F(LexerTest, Skips_Comments_Block_Nested) {
@@ -215,16 +267,23 @@ text // nested line comments are ignored /* more text
/////**/ */*/ident)");
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 3u);
- EXPECT_EQ(t.source().range.begin.column, 14u);
- EXPECT_EQ(t.source().range.end.line, 3u);
- EXPECT_EQ(t.source().range.end.column, 19u);
- EXPECT_EQ(t.to_str(), "ident");
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 3u);
+ EXPECT_EQ(t.source().range.begin.column, 14u);
+ EXPECT_EQ(t.source().range.end.line, 3u);
+ EXPECT_EQ(t.source().range.end.column, 19u);
+ EXPECT_EQ(t.to_str(), "ident");
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsEof());
+ }
}
TEST_F(LexerTest, Skips_Comments_Block_Unterminated) {
@@ -236,7 +295,10 @@ TEST_F(LexerTest, Skips_Comments_Block_Unterminated) {
abcd)");
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_EQ(1u, list.size());
+
+ auto& t = list[0];
ASSERT_TRUE(t.Is(Token::Type::kError));
EXPECT_EQ(t.to_str(), "unterminated block comment");
EXPECT_EQ(t.source().range.begin.line, 2u);
@@ -249,7 +311,10 @@ TEST_F(LexerTest, Null_InBlankspace_IsError) {
Source::File file("", std::string{' ', 0, ' '});
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_EQ(1u, list.size());
+
+ auto& t = list[0];
EXPECT_TRUE(t.IsError());
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 2u);
@@ -262,7 +327,10 @@ TEST_F(LexerTest, Null_InLineComment_IsError) {
Source::File file("", std::string{'/', '/', ' ', 0, ' '});
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_EQ(1u, list.size());
+
+ auto& t = list[0];
EXPECT_TRUE(t.IsError());
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 4u);
@@ -275,7 +343,10 @@ TEST_F(LexerTest, Null_InBlockComment_IsError) {
Source::File file("", std::string{'/', '*', ' ', 0, '*', '/'});
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_EQ(1u, list.size());
+
+ auto& t = list[0];
EXPECT_TRUE(t.IsError());
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 4u);
@@ -291,16 +362,24 @@ TEST_F(LexerTest, Null_InIdentifier_IsError) {
Source::File file("", std::string{'a', 0, 'c'});
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.to_str(), "a");
- t = l.next();
- EXPECT_TRUE(t.IsError());
- EXPECT_EQ(t.source().range.begin.line, 1u);
- EXPECT_EQ(t.source().range.begin.column, 2u);
- EXPECT_EQ(t.source().range.end.line, 1u);
- EXPECT_EQ(t.source().range.end.column, 2u);
- EXPECT_EQ(t.to_str(), "null character found");
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
+
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.to_str(), "a");
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsError());
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 2u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 2u);
+ EXPECT_EQ(t.to_str(), "null character found");
+ }
}
struct FloatData {
@@ -317,20 +396,29 @@ TEST_P(FloatTest, Parse) {
Source::File file("", params.input);
Lexer l(&file);
- auto t = l.next();
- if (std::string(params.input).back() == 'f') {
- EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral_F));
- } else {
- EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral));
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
+
+ {
+ auto& t = list[0];
+ if (std::string(params.input).back() == 'f') {
+ EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral_F));
+ } else if (std::string(params.input).back() == 'h') {
+ EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral_H));
+ } else {
+ EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral));
+ }
+ EXPECT_EQ(t.to_f64(), params.result);
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
}
- EXPECT_EQ(t.to_f64(), params.result);
- EXPECT_EQ(t.source().range.begin.line, 1u);
- EXPECT_EQ(t.source().range.begin.column, 1u);
- EXPECT_EQ(t.source().range.end.line, 1u);
- EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
- t = l.next();
- EXPECT_TRUE(t.IsEof());
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsEof());
+ }
}
INSTANTIATE_TEST_SUITE_P(LexerTest,
FloatTest,
@@ -340,6 +428,11 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
FloatData{"1f", 1.0},
FloatData{"-0f", 0.0},
FloatData{"-1f", -1.0},
+ // No decimal, with 'h' suffix
+ FloatData{"0h", 0.0},
+ FloatData{"1h", 1.0},
+ FloatData{"-0h", 0.0},
+ FloatData{"-1h", -1.0},
// Zero, with decimal.
FloatData{"0.0", 0.0},
@@ -354,7 +447,14 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
FloatData{".0f", 0.0},
FloatData{"-0.0f", 0.0},
FloatData{"-0.f", 0.0},
- FloatData{"-.0", 0.0},
+ FloatData{"-.0f", 0.0},
+ // Zero, with decimal and 'h' suffix
+ FloatData{"0.0h", 0.0},
+ FloatData{"0.h", 0.0},
+ FloatData{".0h", 0.0},
+ FloatData{"-0.0h", 0.0},
+ FloatData{"-0.h", 0.0},
+ FloatData{"-.0h", 0.0},
// Non-zero with decimal
FloatData{"5.7", 5.7},
@@ -370,6 +470,13 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
FloatData{"-5.7f", static_cast<double>(-5.7f)},
FloatData{"-5.f", static_cast<double>(-5.f)},
FloatData{"-.7f", static_cast<double>(-.7f)},
+ // Non-zero with decimal and 'h' suffix
+ FloatData{"5.7h", static_cast<double>(f16::Quantize(5.7f))},
+ FloatData{"5.h", static_cast<double>(f16::Quantize(5.f))},
+ FloatData{".7h", static_cast<double>(f16::Quantize(.7f))},
+ FloatData{"-5.7h", static_cast<double>(f16::Quantize(-5.7f))},
+ FloatData{"-5.h", static_cast<double>(f16::Quantize(-5.f))},
+ FloatData{"-.7h", static_cast<double>(f16::Quantize(-.7f))},
// No decimal, with exponent
FloatData{"1e5", 1e5},
@@ -381,6 +488,11 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
FloatData{"1E5f", static_cast<double>(1e5f)},
FloatData{"1e-5f", static_cast<double>(1e-5f)},
FloatData{"1E-5f", static_cast<double>(1e-5f)},
+ // No decimal, with exponent and 'h' suffix
+ FloatData{"6e4h", static_cast<double>(f16::Quantize(6e4f))},
+ FloatData{"6E4h", static_cast<double>(f16::Quantize(6e4f))},
+ FloatData{"1e-5h", static_cast<double>(f16::Quantize(1e-5f))},
+ FloatData{"1E-5h", static_cast<double>(f16::Quantize(1e-5f))},
// With decimal and exponents
FloatData{"0.2e+12", 0.2e12},
FloatData{"1.2e-5", 1.2e-5},
@@ -393,9 +505,16 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
FloatData{"2.57e23f", static_cast<double>(2.57e23f)},
FloatData{"2.5e+0f", static_cast<double>(2.5f)},
FloatData{"2.5e-0f", static_cast<double>(2.5f)},
+ // With decimal and exponents and 'h' suffix
+ FloatData{"0.2e+5h", static_cast<double>(f16::Quantize(0.2e5f))},
+ FloatData{"1.2e-5h", static_cast<double>(f16::Quantize(1.2e-5f))},
+ FloatData{"6.55e4h", static_cast<double>(f16::Quantize(6.55e4f))},
+ FloatData{"2.5e+0h", static_cast<double>(f16::Quantize(2.5f))},
+ FloatData{"2.5e-0h", static_cast<double>(f16::Quantize(2.5f))},
// Quantization
- FloatData{"3.141592653589793", 3.141592653589793}, // no quantization
- FloatData{"3.141592653589793f", 3.1415927410125732} // f32 quantized
+ FloatData{"3.141592653589793", 3.141592653589793}, // no quantization
+ FloatData{"3.141592653589793f", 3.1415927410125732}, // f32 quantized
+ FloatData{"3.141592653589793h", 3.140625} // f16 quantized
));
using FloatTest_Invalid = testing::TestWithParam<const char*>;
@@ -403,8 +522,12 @@ TEST_P(FloatTest_Invalid, Handles) {
Source::File file("", GetParam());
Lexer l(&file);
- auto t = l.next();
- EXPECT_FALSE(t.Is(Token::Type::kFloatLiteral));
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
+ EXPECT_FALSE(t.Is(Token::Type::kFloatLiteral) || t.Is(Token::Type::kFloatLiteral_F) ||
+ t.Is(Token::Type::kFloatLiteral_H));
}
INSTANTIATE_TEST_SUITE_P(LexerTest,
FloatTest_Invalid,
@@ -423,9 +546,8 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
// Overflow
"2.5e+256f",
"-2.5e+127f",
- // Magnitude smaller than smallest positive f32.
- "2.5e-300f",
- "-2.5e-300f",
+ "6.5520e+4h",
+ "-6.5e+12h",
// Decimal exponent must immediately
// follow the 'e'.
"2.5e 12",
@@ -444,13 +566,23 @@ TEST_P(AsciiIdentifierTest, Parse) {
Source::File file("", GetParam());
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 1u);
- EXPECT_EQ(t.source().range.begin.column, 1u);
- EXPECT_EQ(t.source().range.end.line, 1u);
- EXPECT_EQ(t.source().range.end.column, 1u + strlen(GetParam()));
- EXPECT_EQ(t.to_str(), GetParam());
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
+
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 1u + strlen(GetParam()));
+ EXPECT_EQ(t.to_str(), GetParam());
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsEof());
+ }
}
INSTANTIATE_TEST_SUITE_P(LexerTest,
AsciiIdentifierTest,
@@ -476,13 +608,23 @@ TEST_P(ValidUnicodeIdentifierTest, Parse) {
Source::File file("", GetParam().utf8);
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.source().range.begin.line, 1u);
- EXPECT_EQ(t.source().range.begin.column, 1u);
- EXPECT_EQ(t.source().range.end.line, 1u);
- EXPECT_EQ(t.source().range.end.column, 1u + GetParam().count);
- EXPECT_EQ(t.to_str(), GetParam().utf8);
+ auto list = l.Lex();
+ ASSERT_EQ(2u, list.size());
+
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.IsIdentifier());
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 1u + GetParam().count);
+ EXPECT_EQ(t.to_str(), GetParam().utf8);
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.IsEof());
+ }
}
INSTANTIATE_TEST_SUITE_P(
LexerTest,
@@ -520,7 +662,10 @@ TEST_P(InvalidUnicodeIdentifierTest, Parse) {
Source::File file("", GetParam());
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
EXPECT_TRUE(t.IsError());
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 1u);
@@ -568,7 +713,10 @@ TEST_F(LexerTest, IdentifierTest_SingleUnderscoreDoesNotMatch) {
Source::File file("", "_");
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
EXPECT_FALSE(t.IsIdentifier());
}
@@ -576,7 +724,10 @@ TEST_F(LexerTest, IdentifierTest_DoesNotStartWithDoubleUnderscore) {
Source::File file("", "__test");
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
EXPECT_FALSE(t.IsIdentifier());
}
@@ -584,7 +735,10 @@ TEST_F(LexerTest, IdentifierTest_DoesNotStartWithNumber) {
Source::File file("", "01test");
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ EXPECT_FALSE(list.empty());
+
+ auto& t = list[0];
EXPECT_FALSE(t.IsIdentifier());
}
@@ -607,7 +761,12 @@ TEST_P(ParseIntegerTest, Parse) {
auto params = std::get<1>(GetParam());
Source::File file("", params.input);
- auto t = Lexer(&file).next();
+ Lexer l(&file);
+
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
switch (suffix) {
case 'i':
EXPECT_TRUE(t.Is(Token::Type::kIntLiteral_I));
@@ -736,7 +895,12 @@ TEST_P(ParseIntegerTest_CannotBeRepresented, Parse) {
auto type = std::get<0>(GetParam());
auto source = std::get<1>(GetParam());
Source::File file("", source);
- auto t = Lexer(&file).next();
+
+ Lexer l(&file);
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
EXPECT_TRUE(t.Is(Token::Type::kError));
auto expect = "value cannot be represented as '" + std::string(type) + "'";
EXPECT_EQ(t.to_str(), expect);
@@ -766,7 +930,12 @@ INSTANTIATE_TEST_SUITE_P(u32,
using ParseIntegerTest_LeadingZeros = testing::TestWithParam<const char*>;
TEST_P(ParseIntegerTest_LeadingZeros, Parse) {
Source::File file("", GetParam());
- auto t = Lexer(&file).next();
+
+ Lexer l(&file);
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
EXPECT_TRUE(t.Is(Token::Type::kError));
EXPECT_EQ(t.to_str(), "integer literal cannot have leading 0s");
}
@@ -781,7 +950,12 @@ INSTANTIATE_TEST_SUITE_P(LeadingZero,
using ParseIntegerTest_NoSignificantDigits = testing::TestWithParam<const char*>;
TEST_P(ParseIntegerTest_NoSignificantDigits, Parse) {
Source::File file("", GetParam());
- auto t = Lexer(&file).next();
+
+ Lexer l(&file);
+ auto list = l.Lex();
+ ASSERT_FALSE(list.empty());
+
+ auto& t = list[0];
EXPECT_TRUE(t.Is(Token::Type::kError));
EXPECT_EQ(t.to_str(), "integer or float hex literal has no significant digits");
}
@@ -815,20 +989,26 @@ TEST_P(PunctuationTest, Parses) {
Source::File file("", params.input);
Lexer l(&file);
- auto t = l.next();
- EXPECT_TRUE(t.Is(params.type));
- EXPECT_EQ(t.source().range.begin.line, 1u);
- EXPECT_EQ(t.source().range.begin.column, 1u);
- EXPECT_EQ(t.source().range.end.line, 1u);
- EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+ auto list = l.Lex();
+ ASSERT_GE(list.size(), 2u);
+
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.Is(params.type));
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+ }
- t = l.next();
- EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
+ {
+ auto& t = list[1];
+ EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
+ }
}
INSTANTIATE_TEST_SUITE_P(LexerTest,
PunctuationTest,
testing::Values(TokenData{"&", Token::Type::kAnd},
- TokenData{"&&", Token::Type::kAndAnd},
TokenData{"->", Token::Type::kArrow},
TokenData{"@", Token::Type::kAttr},
TokenData{"/", Token::Type::kForwardSlash},
@@ -842,8 +1022,6 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
TokenData{"=", Token::Type::kEqual},
TokenData{"==", Token::Type::kEqualEqual},
TokenData{">", Token::Type::kGreaterThan},
- TokenData{">=", Token::Type::kGreaterThanEqual},
- TokenData{">>", Token::Type::kShiftRight},
TokenData{"<", Token::Type::kLessThan},
TokenData{"<=", Token::Type::kLessThanEqual},
TokenData{"<<", Token::Type::kShiftLeft},
@@ -870,7 +1048,47 @@ INSTANTIATE_TEST_SUITE_P(LexerTest,
TokenData{"%=", Token::Type::kModuloEqual},
TokenData{"&=", Token::Type::kAndEqual},
TokenData{"|=", Token::Type::kOrEqual},
- TokenData{"^=", Token::Type::kXorEqual}));
+ TokenData{"^=", Token::Type::kXorEqual},
+ TokenData{">>=", Token::Type::kShiftRightEqual},
+ TokenData{"<<=", Token::Type::kShiftLeftEqual}));
+
+using SplittablePunctuationTest = testing::TestWithParam<TokenData>;
+TEST_P(SplittablePunctuationTest, Parses) {
+ auto params = GetParam();
+ Source::File file("", params.input);
+ Lexer l(&file);
+
+ auto list = l.Lex();
+ ASSERT_GE(list.size(), 3u);
+
+ {
+ auto& t = list[0];
+ EXPECT_TRUE(t.Is(params.type));
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+ }
+
+ {
+ auto& t = list[1];
+ EXPECT_TRUE(t.Is(Token::Type::kPlaceholder));
+ EXPECT_EQ(t.source().range.begin.line, 1u);
+ EXPECT_EQ(t.source().range.begin.column, 2u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+ }
+
+ {
+ auto& t = list[2];
+ EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
+ }
+}
+INSTANTIATE_TEST_SUITE_P(LexerTest,
+ SplittablePunctuationTest,
+ testing::Values(TokenData{"&&", Token::Type::kAndAnd},
+ TokenData{">=", Token::Type::kGreaterThanEqual},
+ TokenData{">>", Token::Type::kShiftRight}));
using KeywordTest = testing::TestWithParam<TokenData>;
TEST_P(KeywordTest, Parses) {
@@ -878,15 +1096,17 @@ TEST_P(KeywordTest, Parses) {
Source::File file("", params.input);
Lexer l(&file);
- auto t = l.next();
+ auto list = l.Lex();
+ ASSERT_GE(list.size(), 2u);
+
+ auto& t = list[0];
EXPECT_TRUE(t.Is(params.type)) << params.input;
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 1u);
EXPECT_EQ(t.source().range.end.line, 1u);
EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
- t = l.next();
- EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
+ EXPECT_EQ(list[1].source().range.begin.column, 1 + std::string(params.input).size());
}
INSTANTIATE_TEST_SUITE_P(
LexerTest,
@@ -896,6 +1116,7 @@ INSTANTIATE_TEST_SUITE_P(
TokenData{"bool", Token::Type::kBool},
TokenData{"break", Token::Type::kBreak},
TokenData{"case", Token::Type::kCase},
+ TokenData{"const", Token::Type::kConst},
TokenData{"continue", Token::Type::kContinue},
TokenData{"continuing", Token::Type::kContinuing},
TokenData{"default", Token::Type::kDefault},
@@ -906,10 +1127,8 @@ INSTANTIATE_TEST_SUITE_P(
TokenData{"false", Token::Type::kFalse},
TokenData{"fn", Token::Type::kFn},
TokenData{"for", Token::Type::kFor},
- TokenData{"function", Token::Type::kFunction},
TokenData{"i32", Token::Type::kI32},
TokenData{"if", Token::Type::kIf},
- TokenData{"import", Token::Type::kImport},
TokenData{"let", Token::Type::kLet},
TokenData{"loop", Token::Type::kLoop},
TokenData{"mat2x2", Token::Type::kMat2x2},
@@ -922,13 +1141,11 @@ INSTANTIATE_TEST_SUITE_P(
TokenData{"mat4x3", Token::Type::kMat4x3},
TokenData{"mat4x4", Token::Type::kMat4x4},
TokenData{"override", Token::Type::kOverride},
- TokenData{"private", Token::Type::kPrivate},
TokenData{"ptr", Token::Type::kPtr},
TokenData{"return", Token::Type::kReturn},
TokenData{"sampler", Token::Type::kSampler},
TokenData{"sampler_comparison", Token::Type::kComparisonSampler},
- TokenData{"storage", Token::Type::kStorage},
- TokenData{"storage_buffer", Token::Type::kStorage},
+ TokenData{"static_assert", Token::Type::kStaticAssert},
TokenData{"struct", Token::Type::kStruct},
TokenData{"switch", Token::Type::kSwitch},
TokenData{"texture_1d", Token::Type::kTextureSampled1d},
@@ -951,12 +1168,11 @@ INSTANTIATE_TEST_SUITE_P(
TokenData{"true", Token::Type::kTrue},
TokenData{"type", Token::Type::kType},
TokenData{"u32", Token::Type::kU32},
- TokenData{"uniform", Token::Type::kUniform},
TokenData{"var", Token::Type::kVar},
TokenData{"vec2", Token::Type::kVec2},
TokenData{"vec3", Token::Type::kVec3},
TokenData{"vec4", Token::Type::kVec4},
- TokenData{"workgroup", Token::Type::kWorkgroup}));
+ TokenData{"while", Token::Type::kWhile}));
} // namespace
} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.cc
index a28b7987fbc..e4e681281b2 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.cc
@@ -47,6 +47,12 @@
namespace tint::reader::wgsl {
namespace {
+using Void = ParserImpl::Void;
+
+/// An instance of Void that can be used to signal success for functions that return Expect<Void> or
+/// Maybe<NoError>.
+static constexpr Void kSuccess;
+
template <typename T>
using Expect = ParserImpl::Expect<T>;
@@ -62,72 +68,42 @@ constexpr uint32_t kMaxParseDepth = 128;
/// parser on error.
constexpr size_t const kMaxResynchronizeLookahead = 32;
-const char kVertexStage[] = "vertex";
-const char kFragmentStage[] = "fragment";
-const char kComputeStage[] = "compute";
-
-const char kReadAccess[] = "read";
-const char kWriteAccess[] = "write";
-const char kReadWriteAccess[] = "read_write";
-
-ast::Builtin ident_to_builtin(std::string_view str) {
- if (str == "position") {
- return ast::Builtin::kPosition;
- }
- if (str == "vertex_index") {
- return ast::Builtin::kVertexIndex;
- }
- if (str == "instance_index") {
- return ast::Builtin::kInstanceIndex;
- }
- if (str == "front_facing") {
- return ast::Builtin::kFrontFacing;
- }
- if (str == "frag_depth") {
- return ast::Builtin::kFragDepth;
- }
- if (str == "local_invocation_id") {
- return ast::Builtin::kLocalInvocationId;
- }
- if (str == "local_invocation_idx" || str == "local_invocation_index") {
- return ast::Builtin::kLocalInvocationIndex;
- }
- if (str == "global_invocation_id") {
- return ast::Builtin::kGlobalInvocationId;
- }
- if (str == "workgroup_id") {
- return ast::Builtin::kWorkgroupId;
- }
- if (str == "num_workgroups") {
- return ast::Builtin::kNumWorkgroups;
- }
- if (str == "sample_index") {
- return ast::Builtin::kSampleIndex;
- }
- if (str == "sample_mask") {
- return ast::Builtin::kSampleMask;
- }
- return ast::Builtin::kNone;
-}
-
-const char kBindingAttribute[] = "binding";
-const char kBuiltinAttribute[] = "builtin";
-const char kGroupAttribute[] = "group";
-const char kIdAttribute[] = "id";
-const char kInterpolateAttribute[] = "interpolate";
-const char kInvariantAttribute[] = "invariant";
-const char kLocationAttribute[] = "location";
-const char kSizeAttribute[] = "size";
-const char kAlignAttribute[] = "align";
-const char kStageAttribute[] = "stage";
-const char kWorkgroupSizeAttribute[] = "workgroup_size";
-
// https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords
-bool is_reserved(Token t) {
- return t == "asm" || t == "bf16" || t == "const" || t == "do" || t == "enum" || t == "f64" ||
- t == "handle" || t == "i8" || t == "i16" || t == "i64" || t == "mat" ||
- t == "premerge" || t == "regardless" || t == "typedef" || t == "u8" || t == "u16" ||
- t == "u64" || t == "unless" || t == "using" || t == "vec" || t == "void" || t == "while";
+bool is_reserved(const Token& t) {
+ return t == "CompileShader" || t == "ComputeShader" || t == "DomainShader" ||
+ t == "GeometryShader" || t == "Hullshader" || t == "NULL" || t == "Self" ||
+ t == "abstract" || t == "active" || t == "alignas" || t == "alignof" || t == "as" ||
+ t == "asm" || t == "asm_fragment" || t == "async" || t == "attribute" || t == "auto" ||
+ t == "await" || t == "become" || t == "binding_array" || t == "cast" || t == "catch" ||
+ t == "class" || t == "co_await" || t == "co_return" || t == "co_yield" ||
+ t == "coherent" || t == "column_major" || t == "common" || t == "compile" ||
+ t == "compile_fragment" || t == "concept" || t == "const_cast" || t == "consteval" ||
+ t == "constexpr" || t == "constinit" || t == "crate" || t == "debugger" ||
+ t == "decltype" || t == "delete" || t == "demote" || t == "demote_to_helper" ||
+ t == "do" || t == "dynamic_cast" || t == "enum" || t == "explicit" || t == "export" ||
+ t == "extends" || t == "extern" || t == "external" || t == "filter" || t == "final" ||
+ t == "finally" || t == "friend" || t == "from" || t == "fxgroup" || t == "get" ||
+ t == "goto" || t == "groupshared" || t == "handle" || t == "highp" || t == "impl" ||
+ t == "implements" || t == "import" || t == "inline" || t == "inout" ||
+ t == "instanceof" || t == "interface" || t == "invariant" || t == "layout" ||
+ t == "line" || t == "lineadj" || t == "lowp" || t == "macro" || t == "macro_rules" ||
+ t == "match" || t == "mediump" || t == "meta" || t == "mod" || t == "module" ||
+ t == "move" || t == "mut" || t == "mutable" || t == "namespace" || t == "new" ||
+ t == "nil" || t == "noexcept" || t == "noinline" || t == "nointerpolation" ||
+ t == "noperspective" || t == "null" || t == "nullptr" || t == "of" || t == "operator" ||
+ t == "package" || t == "packoffset" || t == "partition" || t == "pass" || t == "patch" ||
+ t == "pixelfragment" || t == "point" || t == "precise" || t == "precision" ||
+ t == "premerge" || t == "priv" || t == "protected" || t == "pub" || t == "public" ||
+ t == "readonly" || t == "ref" || t == "regardless" || t == "register" ||
+ t == "reinterpret_cast" || t == "requires" || t == "resource" || t == "restrict" ||
+ t == "self" || t == "set" || t == "shared" || t == "signed" || t == "sizeof" ||
+ t == "smooth" || t == "snorm" || t == "static" || t == "static_cast" || t == "std" ||
+ t == "subroutine" || t == "super" || t == "target" || t == "template" || t == "this" ||
+ t == "thread_local" || t == "throw" || t == "trait" || t == "try" || t == "typedef" ||
+ t == "typeid" || t == "typename" || t == "typeof" || t == "union" || t == "unless" ||
+ t == "unorm" || t == "unsafe" || t == "unsized" || t == "use" || t == "using" ||
+ t == "varying" || t == "virtual" || t == "volatile" || t == "wgsl" || t == "where" ||
+ t == "with" || t == "writeonly" || t == "yield";
}
/// Enter-exit counters for block token types.
@@ -181,7 +157,7 @@ class ParserImpl::MultiTokenSource {
/// Implicit conversion to Source that returns the combined source from start
/// to the current last token's source.
operator Source() const {
- Source end = parser_->last_token().source().End();
+ Source end = parser_->last_source().End();
if (end < start_) {
end = start_;
}
@@ -210,10 +186,14 @@ ParserImpl::FunctionHeader::FunctionHeader(const FunctionHeader&) = default;
ParserImpl::FunctionHeader::FunctionHeader(Source src,
std::string n,
- ast::VariableList p,
+ utils::VectorRef<const ast::Parameter*> p,
const ast::Type* ret_ty,
- ast::AttributeList ret_attrs)
- : source(src), name(n), params(p), return_type(ret_ty), return_type_attributes(ret_attrs) {}
+ utils::VectorRef<const ast::Attribute*> ret_attrs)
+ : source(src),
+ name(n),
+ params(std::move(p)),
+ return_type(ret_ty),
+ return_type_attributes(std::move(ret_attrs)) {}
ParserImpl::FunctionHeader::~FunctionHeader() = default;
@@ -237,7 +217,7 @@ ParserImpl::VarDeclInfo::VarDeclInfo(Source source_in,
ParserImpl::VarDeclInfo::~VarDeclInfo() = default;
-ParserImpl::ParserImpl(Source::File const* file) : lexer_(std::make_unique<Lexer>(file)) {}
+ParserImpl::ParserImpl(Source::File const* file) : file_(file) {}
ParserImpl::~ParserImpl() = default;
@@ -270,58 +250,94 @@ void ParserImpl::deprecated(const Source& source, const std::string& msg) {
"use of deprecated language feature: " + msg, source);
}
-Token ParserImpl::next() {
- if (!token_queue_.empty()) {
- auto t = token_queue_.front();
- token_queue_.pop_front();
- last_token_ = t;
- return last_token_;
+const Token& ParserImpl::next() {
+ // If the next token is already an error or the end of file, stay there.
+ if (tokens_[next_token_idx_].IsEof() || tokens_[next_token_idx_].IsError()) {
+ return tokens_[next_token_idx_];
+ }
+
+ // Skip over any placeholder elements
+ while (true) {
+ if (!tokens_[next_token_idx_].IsPlaceholder()) {
+ break;
+ }
+ next_token_idx_++;
+ }
+ last_source_idx_ = next_token_idx_;
+
+ if (!tokens_[next_token_idx_].IsEof() && !tokens_[next_token_idx_].IsError()) {
+ next_token_idx_++;
}
- last_token_ = lexer_->next();
- return last_token_;
+ return tokens_[last_source_idx_];
}
-Token ParserImpl::peek(size_t idx) {
- while (token_queue_.size() < (idx + 1)) {
- token_queue_.push_back(lexer_->next());
+const Token& ParserImpl::peek(size_t idx) {
+ if (next_token_idx_ + idx >= tokens_.size()) {
+ return tokens_[tokens_.size() - 1];
+ }
+
+ // Skip over any placeholder elements
+ while (true) {
+ if (!tokens_[next_token_idx_ + idx].IsPlaceholder()) {
+ break;
+ }
+ idx++;
+ }
+ if (next_token_idx_ + idx >= tokens_.size()) {
+ return tokens_[tokens_.size() - 1];
}
- return token_queue_[idx];
+
+ return tokens_[next_token_idx_ + idx];
}
bool ParserImpl::peek_is(Token::Type tok, size_t idx) {
return peek(idx).Is(tok);
}
-Token ParserImpl::last_token() const {
- return last_token_;
+void ParserImpl::split_token(Token::Type lhs, Token::Type rhs) {
+ if (next_token_idx_ == 0) {
+ TINT_ICE(Reader, builder_.Diagnostics())
+ << "attempt to update placeholder at beginning of tokens";
+ }
+ if (next_token_idx_ >= tokens_.size()) {
+ TINT_ICE(Reader, builder_.Diagnostics())
+ << "attempt to update placeholder past end of tokens";
+ }
+ if (!tokens_[next_token_idx_].IsPlaceholder()) {
+ TINT_ICE(Reader, builder_.Diagnostics()) << "attempt to update non-placeholder token";
+ }
+ tokens_[next_token_idx_ - 1].SetType(lhs);
+ tokens_[next_token_idx_].SetType(rhs);
+}
+
+Source ParserImpl::last_source() const {
+ return tokens_[last_source_idx_].source();
+}
+
+void ParserImpl::InitializeLex() {
+ Lexer l{file_};
+ tokens_ = l.Lex();
}
bool ParserImpl::Parse() {
+ InitializeLex();
translation_unit();
return !has_error();
}
// translation_unit
-// : enable_directive* global_decl* EOF
+// : global_directive* global_decl* EOF
void ParserImpl::translation_unit() {
bool after_global_decl = false;
while (continue_parsing()) {
- auto p = peek();
+ auto& p = peek();
if (p.IsEof()) {
break;
}
- auto ed = enable_directive();
- if (ed.matched) {
- if (after_global_decl) {
- add_error(p, "enable directives must come before all global declarations");
- }
- } else if (ed.errored) {
- // Found a invalid enable directive.
- continue;
- } else {
+ auto ed = global_directive(after_global_decl);
+ if (!ed.matched && !ed.errored) {
auto gd = global_decl();
-
if (gd.matched) {
after_global_decl = true;
}
@@ -339,17 +355,28 @@ void ParserImpl::translation_unit() {
}
}
+// global_directive
+// : enable_directive
+Maybe<Void> ParserImpl::global_directive(bool have_parsed_decl) {
+ auto& p = peek();
+ auto ed = enable_directive();
+ if (ed.matched && have_parsed_decl) {
+ return add_error(p, "enable directives must come before all global declarations");
+ }
+ return ed;
+}
+
// enable_directive
// : enable name SEMICLON
-Maybe<bool> ParserImpl::enable_directive() {
- auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<bool> {
+Maybe<Void> ParserImpl::enable_directive() {
+ auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<Void> {
if (!match(Token::Type::kEnable)) {
return Failure::kNoMatch;
}
// Match the extension name.
Expect<std::string> name = {""};
- auto t = peek();
+ auto& t = peek();
if (t.IsIdentifier()) {
synchronized_ = true;
next();
@@ -359,6 +386,10 @@ Maybe<bool> ParserImpl::enable_directive() {
synchronized_ = true;
next();
name = {"f16", t.source()};
+ } else if (t.Is(Token::Type::kParenLeft)) {
+ // A common error case is writing `enable(foo);` instead of `enable foo;`.
+ synchronized_ = false;
+ return add_error(t.source(), "enable directives don't take parenthesis");
} else if (handle_error(t)) {
// The token might itself be an error.
return Failure::kErrored;
@@ -373,19 +404,19 @@ Maybe<bool> ParserImpl::enable_directive() {
}
auto extension = ast::ParseExtension(name.value);
- if (extension == ast::Extension::kNone) {
+ if (extension == ast::Extension::kInvalid) {
return add_error(name.source, "unsupported extension: '" + name.value + "'");
}
builder_.AST().AddEnable(create<ast::Enable>(name.source, extension));
- return true;
+ return kSuccess;
});
if (decl.errored) {
return Failure::kErrored;
}
if (decl.matched) {
- return true;
+ return kSuccess;
}
return Failure::kNoMatch;
@@ -393,18 +424,18 @@ Maybe<bool> ParserImpl::enable_directive() {
// global_decl
// : SEMICOLON
-// | global_variable_decl SEMICLON
+// | global_variable_decl SEMICOLON
// | global_constant_decl SEMICOLON
-// | type_alias SEMICOLON
+// | type_alias_decl SEMICOLON
// | struct_decl
// | function_decl
-Maybe<bool> ParserImpl::global_decl() {
+// | static_assert_statement SEMICOLON
+Maybe<Void> ParserImpl::global_decl() {
if (match(Token::Type::kSemicolon) || match(Token::Type::kEOF)) {
- return true;
+ return kSuccess;
}
bool errored = false;
-
auto attrs = attribute_list();
if (attrs.errored) {
errored = true;
@@ -413,7 +444,7 @@ Maybe<bool> ParserImpl::global_decl() {
return Failure::kErrored;
}
- auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<bool> {
+ auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<Void> {
auto gv = global_variable_decl(attrs.value);
if (gv.errored) {
return Failure::kErrored;
@@ -424,45 +455,49 @@ Maybe<bool> ParserImpl::global_decl() {
}
builder_.AST().AddGlobalVariable(gv.value);
- return true;
+ return kSuccess;
}
auto gc = global_constant_decl(attrs.value);
if (gc.errored) {
return Failure::kErrored;
}
-
if (gc.matched) {
- if (!expect("let declaration", Token::Type::kSemicolon)) {
- return Failure::kErrored;
+ // Avoid the cost of the string allocation for the common no-error case
+ if (!peek().Is(Token::Type::kSemicolon)) {
+ std::string kind = gc->Kind();
+ if (!expect("'" + kind + "' declaration", Token::Type::kSemicolon)) {
+ return Failure::kErrored;
+ }
}
builder_.AST().AddGlobalVariable(gc.value);
- return true;
+ return kSuccess;
}
- auto ta = type_alias();
+ auto ta = type_alias_decl();
if (ta.errored) {
return Failure::kErrored;
}
-
if (ta.matched) {
if (!expect("type alias", Token::Type::kSemicolon)) {
return Failure::kErrored;
}
builder_.AST().AddTypeDecl(ta.value);
- return true;
+ return kSuccess;
}
- auto str = struct_decl();
- if (str.errored) {
+ auto assertion = static_assert_statement();
+ if (assertion.errored) {
return Failure::kErrored;
}
-
- if (str.matched) {
- builder_.AST().AddTypeDecl(str.value);
- return true;
+ if (assertion.matched) {
+ builder_.AST().AddStaticAssert(assertion.value);
+ if (!expect("static assertion declaration", Token::Type::kSemicolon)) {
+ return Failure::kErrored;
+ }
+ return kSuccess;
}
return Failure::kNoMatch;
@@ -472,7 +507,22 @@ Maybe<bool> ParserImpl::global_decl() {
errored = true;
}
if (decl.matched) {
- return expect_attributes_consumed(attrs.value);
+ if (!expect_attributes_consumed(attrs.value)) {
+ return Failure::kErrored;
+ }
+ return kSuccess;
+ }
+
+ auto str = struct_decl();
+ if (str.errored) {
+ errored = true;
+ }
+ if (str.matched) {
+ builder_.AST().AddTypeDecl(str.value);
+ if (!expect_attributes_consumed(attrs.value)) {
+ return Failure::kErrored;
+ }
+ return kSuccess;
}
auto func = function_decl(attrs.value);
@@ -481,7 +531,7 @@ Maybe<bool> ParserImpl::global_decl() {
}
if (func.matched) {
builder_.AST().AddFunction(func.value);
- return true;
+ return kSuccess;
}
if (errored) {
@@ -491,12 +541,12 @@ Maybe<bool> ParserImpl::global_decl() {
// Invalid syntax found - try and determine the best error message
// We have attributes parsed, but nothing to consume them?
- if (attrs.value.size() > 0) {
+ if (attrs.value.Length() > 0) {
return add_error(next(), "expected declaration after attributes");
}
// We have a statement outside of a function?
- auto t = peek();
+ auto& t = peek();
auto stat = without_error([&] { return statement(); });
if (stat.matched) {
// Attempt to jump to the next '}' - the function might have just been
@@ -522,9 +572,8 @@ Maybe<bool> ParserImpl::global_decl() {
}
// global_variable_decl
-// : variable_attribute_list* variable_decl
-// | variable_attribute_list* variable_decl EQUAL const_expr
-Maybe<const ast::Variable*> ParserImpl::global_variable_decl(ast::AttributeList& attrs) {
+// : variable_attribute_list* variable_decl (EQUAL expression)?
+Maybe<const ast::Variable*> ParserImpl::global_variable_decl(AttributeList& attrs) {
auto decl = variable_decl();
if (decl.errored) {
return Failure::kErrored;
@@ -533,71 +582,104 @@ Maybe<const ast::Variable*> ParserImpl::global_variable_decl(ast::AttributeList&
return Failure::kNoMatch;
}
- const ast::Expression* constructor = nullptr;
+ const ast::Expression* initializer = nullptr;
if (match(Token::Type::kEqual)) {
- auto expr = expect_const_expr();
+ auto expr = expression();
if (expr.errored) {
return Failure::kErrored;
}
- constructor = expr.value;
+ if (!expr.matched) {
+ return add_error(peek(), "missing initializer for 'var' declaration");
+ }
+ initializer = expr.value;
}
- return create<ast::Variable>(decl->source, // source
- builder_.Symbols().Register(decl->name), // symbol
- decl->storage_class, // storage class
- decl->access, // access control
- decl->type, // type
- false, // is_const
- false, // is_overridable
- constructor, // constructor
- std::move(attrs)); // attributes
+ TINT_DEFER(attrs.Clear());
+
+ return create<ast::Var>(decl->source, // source
+ builder_.Symbols().Register(decl->name), // symbol
+ decl->type, // type
+ decl->storage_class, // storage class
+ decl->access, // access control
+ initializer, // initializer
+ std::move(attrs)); // attributes
}
// global_constant_decl :
-// | LET (ident | variable_ident_decl) global_const_initializer
-// | attribute* override (ident | variable_ident_decl) (equal expression)?
+// | LET optionally_typed_ident global_const_initializer
+// | attribute* override optionally_typed_ident (equal expression)?
// global_const_initializer
// : EQUAL const_expr
-Maybe<const ast::Variable*> ParserImpl::global_constant_decl(ast::AttributeList& attrs) {
+Maybe<const ast::Variable*> ParserImpl::global_constant_decl(AttributeList& attrs) {
+ bool is_const = false;
bool is_overridable = false;
const char* use = nullptr;
- if (match(Token::Type::kLet)) {
- use = "let declaration";
+ Source source;
+ if (match(Token::Type::kConst)) {
+ use = "'const' declaration";
+ } else if (match(Token::Type::kLet, &source)) {
+ use = "'let' declaration";
+ deprecated(source, "module-scope 'let' has been replaced with 'const'");
} else if (match(Token::Type::kOverride)) {
- use = "override declaration";
+ use = "'override' declaration";
is_overridable = true;
} else {
return Failure::kNoMatch;
}
- auto decl = expect_variable_ident_decl(use, /* allow_inferred = */ true);
+ auto decl = expect_optionally_typed_ident(use);
if (decl.errored) {
return Failure::kErrored;
}
+ bool has_initializer = false;
+ if (is_overridable) {
+ has_initializer = match(Token::Type::kEqual);
+ } else {
+ if (!expect(use, Token::Type::kEqual)) {
+ return Failure::kErrored;
+ }
+ has_initializer = true;
+ }
+
const ast::Expression* initializer = nullptr;
- if (match(Token::Type::kEqual)) {
- auto init = expect_const_expr();
- if (init.errored) {
+ if (has_initializer) {
+ auto expr = expression();
+ if (expr.errored) {
return Failure::kErrored;
}
- initializer = std::move(init.value);
+ if (!expr.matched) {
+ return add_error(peek(), "missing initializer for " + std::string(use));
+ }
+ initializer = std::move(expr.value);
}
- return create<ast::Variable>(decl->source, // source
- builder_.Symbols().Register(decl->name), // symbol
- ast::StorageClass::kNone, // storage class
- ast::Access::kUndefined, // access control
- decl->type, // type
- true, // is_const
- is_overridable, // is_overridable
- initializer, // constructor
- std::move(attrs)); // attributes
+ TINT_DEFER(attrs.Clear());
+
+ if (is_const) {
+ return create<ast::Const>(decl->source, // source
+ builder_.Symbols().Register(decl->name), // symbol
+ decl->type, // type
+ initializer, // initializer
+ std::move(attrs)); // attributes
+ }
+ if (is_overridable) {
+ return create<ast::Override>(decl->source, // source
+ builder_.Symbols().Register(decl->name), // symbol
+ decl->type, // type
+ initializer, // initializer
+ std::move(attrs)); // attributes
+ }
+ return create<ast::Const>(decl->source, // source
+ builder_.Symbols().Register(decl->name), // symbol
+ decl->type, // type
+ initializer, // initializer
+ std::move(attrs)); // attributes
}
// variable_decl
-// : VAR variable_qualifier? variable_ident_decl
-Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl(bool allow_inferred) {
+// : VAR variable_qualifier? optionally_typed_ident
+Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl() {
Source source;
if (!match(Token::Type::kVar, &source)) {
return Failure::kNoMatch;
@@ -612,7 +694,7 @@ Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl(bool allow_inferred) {
vq = explicit_vq.value;
}
- auto decl = expect_variable_ident_decl("variable declaration", allow_inferred);
+ auto decl = expect_optionally_typed_ident("variable declaration");
if (decl.errored) {
return Failure::kErrored;
}
@@ -620,20 +702,20 @@ Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl(bool allow_inferred) {
return VarDeclInfo{decl->source, decl->name, vq.storage_class, vq.access, decl->type};
}
-// texture_samplers
-// : sampler
-// | depth_texture
-// | sampled_texture LESS_THAN type_decl GREATER_THAN
-// | multisampled_texture LESS_THAN type_decl GREATER_THAN
-// | storage_texture LESS_THAN texel_format
-// COMMA access GREATER_THAN
-Maybe<const ast::Type*> ParserImpl::texture_samplers() {
- auto type = sampler();
+// texture_and_sampler_types
+// : sampler_type
+// | depth_texture_type
+// | sampled_texture_type LESS_THAN type_decl GREATER_THAN
+// | multisampled_texture_type LESS_THAN type_decl GREATER_THAN
+// | storage_texture_type LESS_THAN texel_format
+// COMMA access_mode GREATER_THAN
+Maybe<const ast::Type*> ParserImpl::texture_and_sampler_types() {
+ auto type = sampler_type();
if (type.matched) {
return type;
}
- type = depth_texture();
+ type = depth_texture_type();
if (type.matched) {
return type;
}
@@ -645,7 +727,7 @@ Maybe<const ast::Type*> ParserImpl::texture_samplers() {
auto source_range = make_source_range();
- auto dim = sampled_texture();
+ auto dim = sampled_texture_type();
if (dim.matched) {
const char* use = "sampled texture type";
@@ -657,7 +739,7 @@ Maybe<const ast::Type*> ParserImpl::texture_samplers() {
return builder_.ty.sampled_texture(source_range, dim.value, subtype.value);
}
- auto ms_dim = multisampled_texture();
+ auto ms_dim = multisampled_texture_type();
if (ms_dim.matched) {
const char* use = "multisampled texture type";
@@ -669,7 +751,7 @@ Maybe<const ast::Type*> ParserImpl::texture_samplers() {
return builder_.ty.multisampled_texture(source_range, ms_dim.value, subtype.value);
}
- auto storage = storage_texture();
+ auto storage = storage_texture_type();
if (storage.matched) {
const char* use = "storage texture type";
using StorageTextureInfo = std::pair<tint::ast::TexelFormat, tint::ast::Access>;
@@ -683,7 +765,7 @@ Maybe<const ast::Type*> ParserImpl::texture_samplers() {
return Failure::kErrored;
}
- auto access = expect_access("access control");
+ auto access = expect_access_mode("access control");
if (access.errored) {
return Failure::kErrored;
}
@@ -702,10 +784,10 @@ Maybe<const ast::Type*> ParserImpl::texture_samplers() {
return Failure::kNoMatch;
}
-// sampler
+// sampler_type
// : SAMPLER
// | SAMPLER_COMPARISON
-Maybe<const ast::Type*> ParserImpl::sampler() {
+Maybe<const ast::Type*> ParserImpl::sampler_type() {
Source source;
if (match(Token::Type::kSampler, &source)) {
return builder_.ty.sampler(source, ast::SamplerKind::kSampler);
@@ -718,14 +800,14 @@ Maybe<const ast::Type*> ParserImpl::sampler() {
return Failure::kNoMatch;
}
-// sampled_texture
+// sampled_texture_type
// : TEXTURE_SAMPLED_1D
// | TEXTURE_SAMPLED_2D
// | TEXTURE_SAMPLED_2D_ARRAY
// | TEXTURE_SAMPLED_3D
// | TEXTURE_SAMPLED_CUBE
// | TEXTURE_SAMPLED_CUBE_ARRAY
-Maybe<const ast::TextureDimension> ParserImpl::sampled_texture() {
+Maybe<const ast::TextureDimension> ParserImpl::sampled_texture_type() {
if (match(Token::Type::kTextureSampled1d)) {
return ast::TextureDimension::k1d;
}
@@ -764,9 +846,9 @@ Maybe<const ast::Type*> ParserImpl::external_texture() {
return Failure::kNoMatch;
}
-// multisampled_texture
+// multisampled_texture_type
// : TEXTURE_MULTISAMPLED_2D
-Maybe<const ast::TextureDimension> ParserImpl::multisampled_texture() {
+Maybe<const ast::TextureDimension> ParserImpl::multisampled_texture_type() {
if (match(Token::Type::kTextureMultisampled2d)) {
return ast::TextureDimension::k2d;
}
@@ -774,12 +856,12 @@ Maybe<const ast::TextureDimension> ParserImpl::multisampled_texture() {
return Failure::kNoMatch;
}
-// storage_texture
+// storage_texture_type
// : TEXTURE_STORAGE_1D
// | TEXTURE_STORAGE_2D
// | TEXTURE_STORAGE_2D_ARRAY
// | TEXTURE_STORAGE_3D
-Maybe<const ast::TextureDimension> ParserImpl::storage_texture() {
+Maybe<const ast::TextureDimension> ParserImpl::storage_texture_type() {
if (match(Token::Type::kTextureStorage1d)) {
return ast::TextureDimension::k1d;
}
@@ -796,13 +878,13 @@ Maybe<const ast::TextureDimension> ParserImpl::storage_texture() {
return Failure::kNoMatch;
}
-// depth_texture
+// depth_texture_type
// : TEXTURE_DEPTH_2D
// | TEXTURE_DEPTH_2D_ARRAY
// | TEXTURE_DEPTH_CUBE
// | TEXTURE_DEPTH_CUBE_ARRAY
// | TEXTURE_DEPTH_MULTISAMPLED_2D
-Maybe<const ast::Type*> ParserImpl::depth_texture() {
+Maybe<const ast::Type*> ParserImpl::depth_texture_type() {
Source source;
if (match(Token::Type::kTextureDepth2d, &source)) {
return builder_.ty.depth_texture(source, ast::TextureDimension::k2d);
@@ -840,62 +922,17 @@ Maybe<const ast::Type*> ParserImpl::depth_texture() {
// | 'rgba32sint'
// | 'rgba32float'
Expect<ast::TexelFormat> ParserImpl::expect_texel_format(std::string_view use) {
- auto t = next();
- if (t == "rgba8unorm") {
- return ast::TexelFormat::kRgba8Unorm;
+ auto& t = next();
+ auto fmt = ast::ParseTexelFormat(t.to_str());
+ if (fmt == ast::TexelFormat::kInvalid) {
+ return add_error(t.source(), "invalid format", use);
}
- if (t == "rgba8snorm") {
- return ast::TexelFormat::kRgba8Snorm;
- }
- if (t == "rgba8uint") {
- return ast::TexelFormat::kRgba8Uint;
- }
- if (t == "rgba8sint") {
- return ast::TexelFormat::kRgba8Sint;
- }
- if (t == "rgba16uint") {
- return ast::TexelFormat::kRgba16Uint;
- }
- if (t == "rgba16sint") {
- return ast::TexelFormat::kRgba16Sint;
- }
- if (t == "rgba16float") {
- return ast::TexelFormat::kRgba16Float;
- }
- if (t == "r32uint") {
- return ast::TexelFormat::kR32Uint;
- }
- if (t == "r32sint") {
- return ast::TexelFormat::kR32Sint;
- }
- if (t == "r32float") {
- return ast::TexelFormat::kR32Float;
- }
- if (t == "rg32uint") {
- return ast::TexelFormat::kRg32Uint;
- }
- if (t == "rg32sint") {
- return ast::TexelFormat::kRg32Sint;
- }
- if (t == "rg32float") {
- return ast::TexelFormat::kRg32Float;
- }
- if (t == "rgba32uint") {
- return ast::TexelFormat::kRgba32Uint;
- }
- if (t == "rgba32sint") {
- return ast::TexelFormat::kRgba32Sint;
- }
- if (t == "rgba32float") {
- return ast::TexelFormat::kRgba32Float;
- }
- return add_error(t.source(), "invalid format", use);
+ return fmt;
}
-// variable_ident_decl
-// : IDENT COLON type_decl
-Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(std::string_view use,
- bool allow_inferred) {
+Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_ident_with_optional_type_decl(
+ std::string_view use,
+ bool allow_inferred) {
auto ident = expect_ident(use);
if (ident.errored) {
return Failure::kErrored;
@@ -909,7 +946,7 @@ Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(std::
return Failure::kErrored;
}
- auto t = peek();
+ auto& t = peek();
auto type = type_decl();
if (type.errored) {
return Failure::kErrored;
@@ -921,19 +958,36 @@ Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(std::
return TypedIdentifier{type.value, ident.value, ident.source};
}
-Expect<ast::Access> ParserImpl::expect_access(std::string_view use) {
+// optionally_typed_ident
+// : ident ( COLON typed_decl ) ?
+Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_optionally_typed_ident(
+ std::string_view use) {
+ return expect_ident_with_optional_type_decl(use, true);
+}
+
+// ident_with_type_decl
+// : IDENT COLON type_decl
+Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_ident_with_type_decl(std::string_view use) {
+ return expect_ident_with_optional_type_decl(use, false);
+}
+
+// access_mode
+// : 'read'
+// | 'write'
+// | 'read_write'
+Expect<ast::Access> ParserImpl::expect_access_mode(std::string_view use) {
auto ident = expect_ident(use);
if (ident.errored) {
return Failure::kErrored;
}
- if (ident.value == kReadAccess) {
+ if (ident.value == "read") {
return {ast::Access::kRead, ident.source};
}
- if (ident.value == kWriteAccess) {
+ if (ident.value == "write") {
return {ast::Access::kWrite, ident.source};
}
- if (ident.value == kReadWriteAccess) {
+ if (ident.value == "read_write") {
return {ast::Access::kReadWrite, ident.source};
}
@@ -950,12 +1004,12 @@ Maybe<ParserImpl::VariableQualifier> ParserImpl::variable_qualifier() {
auto* use = "variable declaration";
auto vq = expect_lt_gt_block(use, [&]() -> Expect<VariableQualifier> {
auto source = make_source_range();
- auto sc = expect_storage_class(use);
+ auto sc = expect_address_space(use);
if (sc.errored) {
return Failure::kErrored;
}
if (match(Token::Type::kComma)) {
- auto ac = expect_access(use);
+ auto ac = expect_access_mode(use);
if (ac.errored) {
return Failure::kErrored;
}
@@ -972,14 +1026,14 @@ Maybe<ParserImpl::VariableQualifier> ParserImpl::variable_qualifier() {
return vq;
}
-// type_alias
+// type_alias_decl
// : TYPE IDENT EQUAL type_decl
-Maybe<const ast::Alias*> ParserImpl::type_alias() {
+Maybe<const ast::Alias*> ParserImpl::type_alias_decl() {
if (!peek_is(Token::Type::kType)) {
return Failure::kNoMatch;
}
- auto t = next();
+ auto& t = next();
const char* use = "type alias";
auto name = expect_ident(use);
@@ -1012,10 +1066,8 @@ Maybe<const ast::Alias*> ParserImpl::type_alias() {
// | VEC3 LESS_THAN type_decl GREATER_THAN
// | VEC4 LESS_THAN type_decl GREATER_THAN
// | PTR LESS_THAN storage_class, type_decl (COMMA access_mode)? GREATER_THAN
-// | array_attribute_list* ARRAY LESS_THAN type_decl COMMA
-// INT_LITERAL GREATER_THAN
-// | array_attribute_list* ARRAY LESS_THAN type_decl
-// GREATER_THAN
+// | array_attribute_list* ARRAY LESS_THAN type_decl COMMA INT_LITERAL GREATER_THAN
+// | array_attribute_list* ARRAY LESS_THAN type_decl GREATER_THAN
// | MAT2x2 LESS_THAN type_decl GREATER_THAN
// | MAT2x3 LESS_THAN type_decl GREATER_THAN
// | MAT2x4 LESS_THAN type_decl GREATER_THAN
@@ -1025,9 +1077,9 @@ Maybe<const ast::Alias*> ParserImpl::type_alias() {
// | MAT4x2 LESS_THAN type_decl GREATER_THAN
// | MAT4x3 LESS_THAN type_decl GREATER_THAN
// | MAT4x4 LESS_THAN type_decl GREATER_THAN
-// | texture_samplers
+// | texture_and_sampler_types
Maybe<const ast::Type*> ParserImpl::type_decl() {
- auto t = peek();
+ auto& t = peek();
Source source;
if (match(Token::Type::kIdentifier, &source)) {
return builder_.create<ast::TypeName>(source, builder_.Symbols().Register(t.to_str()));
@@ -1075,7 +1127,7 @@ Maybe<const ast::Type*> ParserImpl::type_decl() {
return expect_type_decl_matrix(t);
}
- auto texture_or_sampler = texture_samplers();
+ auto texture_or_sampler = texture_and_sampler_types();
if (texture_or_sampler.errored) {
return Failure::kErrored;
}
@@ -1097,14 +1149,14 @@ Expect<const ast::Type*> ParserImpl::expect_type(std::string_view use) {
return type.value;
}
-Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(Token t) {
+Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Token& t) {
const char* use = "ptr declaration";
auto storage_class = ast::StorageClass::kNone;
auto access = ast::Access::kUndefined;
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
- auto sc = expect_storage_class(use);
+ auto sc = expect_address_space(use);
if (sc.errored) {
return Failure::kErrored;
}
@@ -1120,7 +1172,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(Token t) {
}
if (match(Token::Type::kComma)) {
- auto ac = expect_access("access control");
+ auto ac = expect_access_mode("access control");
if (ac.errored) {
return Failure::kErrored;
}
@@ -1138,7 +1190,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(Token t) {
access);
}
-Expect<const ast::Type*> ParserImpl::expect_type_decl_atomic(Token t) {
+Expect<const ast::Type*> ParserImpl::expect_type_decl_atomic(const Token& t) {
const char* use = "atomic declaration";
auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
@@ -1149,7 +1201,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_atomic(Token t) {
return builder_.ty.atomic(make_source_range_from(t.source()), subtype.value);
}
-Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(Token t) {
+Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(const Token& t) {
uint32_t count = 2;
if (t.Is(Token::Type::kVec3)) {
count = 3;
@@ -1170,39 +1222,46 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(Token t) {
return builder_.ty.vec(make_source_range_from(t.source()), subtype, count);
}
-Expect<const ast::Type*> ParserImpl::expect_type_decl_array(Token t) {
+Expect<const ast::Type*> ParserImpl::expect_type_decl_array(const Token& t) {
const char* use = "array declaration";
- const ast::Expression* size = nullptr;
+ struct TypeAndSize {
+ const ast::Type* type = nullptr;
+ const ast::Expression* size = nullptr;
+ };
- auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
+ if (!peek_is(Token::Type::kLessThan)) {
+ return builder_.ty.array(make_source_range_from(t.source()), nullptr, nullptr);
+ }
+
+ auto type_size = expect_lt_gt_block(use, [&]() -> Expect<TypeAndSize> {
auto type = expect_type(use);
if (type.errored) {
return Failure::kErrored;
}
- if (match(Token::Type::kComma)) {
- auto expr = primary_expression();
- if (expr.errored) {
- return Failure::kErrored;
- } else if (!expr.matched) {
- return add_error(peek(), "expected array size expression");
- }
+ if (!match(Token::Type::kComma)) {
+ return TypeAndSize{type.value, nullptr};
+ }
- size = std::move(expr.value);
+ auto size = primary_expression();
+ if (size.errored) {
+ return Failure::kErrored;
+ } else if (!size.matched) {
+ return add_error(peek(), "expected array size expression");
}
- return type.value;
+ return TypeAndSize{type.value, size.value};
});
- if (subtype.errored) {
+ if (type_size.errored) {
return Failure::kErrored;
}
- return builder_.ty.array(make_source_range_from(t.source()), subtype.value, size);
+ return builder_.ty.array(make_source_range_from(t.source()), type_size->type, type_size->size);
}
-Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(Token t) {
+Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(const Token& t) {
uint32_t rows = 2;
uint32_t columns = 2;
if (t.IsMat3xN()) {
@@ -1229,45 +1288,33 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(Token t) {
return builder_.ty.mat(make_source_range_from(t.source()), subtype, columns, rows);
}
-// storage_class
-// : INPUT
-// | OUTPUT
-// | UNIFORM
-// | WORKGROUP
-// | STORAGE
-// | PRIVATE
-// | FUNCTION
-Expect<ast::StorageClass> ParserImpl::expect_storage_class(std::string_view use) {
- auto source = peek().source();
-
- if (match(Token::Type::kUniform)) {
- return {ast::StorageClass::kUniform, source};
- }
-
- if (match(Token::Type::kWorkgroup)) {
- return {ast::StorageClass::kWorkgroup, source};
- }
-
- if (match(Token::Type::kStorage)) {
- return {ast::StorageClass::kStorage, source};
- }
-
- if (match(Token::Type::kPrivate)) {
- return {ast::StorageClass::kPrivate, source};
+// address_space
+// : 'function'
+// | 'private'
+// | 'workgroup'
+// | 'uniform'
+// | 'storage'
+//
+// Note, we also parse `push_constant` from the experimental extension
+Expect<ast::StorageClass> ParserImpl::expect_address_space(std::string_view use) {
+ auto& t = peek();
+ auto ident = expect_ident("storage class");
+ if (ident.errored) {
+ return Failure::kErrored;
}
- if (match(Token::Type::kFunction)) {
- return {ast::StorageClass::kFunction, source};
+ auto storage_class = ast::ParseStorageClass(ident.value);
+ if (storage_class == ast::StorageClass::kInvalid) {
+ return add_error(t.source(), "invalid storage class", use);
}
- return add_error(source, "invalid storage class", use);
+ return {storage_class, t.source()};
}
// struct_decl
// : STRUCT IDENT struct_body_decl
Maybe<const ast::Struct*> ParserImpl::struct_decl() {
- auto t = peek();
- auto source = t.source();
+ auto& t = peek();
if (!match(Token::Type::kStruct)) {
return Failure::kNoMatch;
@@ -1284,18 +1331,18 @@ Maybe<const ast::Struct*> ParserImpl::struct_decl() {
}
auto sym = builder_.Symbols().Register(name.value);
- return create<ast::Struct>(source, sym, std::move(body.value), ast::AttributeList{});
+ return create<ast::Struct>(t.source(), sym, std::move(body.value), utils::Empty);
}
// struct_body_decl
// : BRACE_LEFT (struct_member COMMA)* struct_member COMMA? BRACE_RIGHT
-Expect<ast::StructMemberList> ParserImpl::expect_struct_body_decl() {
- return expect_brace_block("struct declaration", [&]() -> Expect<ast::StructMemberList> {
- ast::StructMemberList members;
+Expect<ParserImpl::StructMemberList> ParserImpl::expect_struct_body_decl() {
+ return expect_brace_block("struct declaration", [&]() -> Expect<StructMemberList> {
+ StructMemberList members;
bool errored = false;
while (continue_parsing()) {
// Check for the end of the list.
- auto t = peek();
+ auto& t = peek();
if (!t.IsIdentifier() && !t.Is(Token::Type::kAttr)) {
break;
}
@@ -1307,15 +1354,9 @@ Expect<ast::StructMemberList> ParserImpl::expect_struct_body_decl() {
return Failure::kErrored;
}
} else {
- members.push_back(member.value);
+ members.Push(member.value);
}
- // TODO(crbug.com/tint/1475): Remove support for semicolons.
- if (auto sc = peek(); sc.Is(Token::Type::kSemicolon)) {
- deprecated(sc.source(), "struct members should be separated with commas");
- next();
- continue;
- }
if (!match(Token::Type::kComma)) {
break;
}
@@ -1328,14 +1369,14 @@ Expect<ast::StructMemberList> ParserImpl::expect_struct_body_decl() {
}
// struct_member
-// : attribute* variable_ident_decl
+// : attribute* ident_with_type_decl
Expect<ast::StructMember*> ParserImpl::expect_struct_member() {
auto attrs = attribute_list();
if (attrs.errored) {
return Failure::kErrored;
}
- auto decl = expect_variable_ident_decl("struct member");
+ auto decl = expect_ident_with_type_decl("struct member");
if (decl.errored) {
return Failure::kErrored;
}
@@ -1344,9 +1385,29 @@ Expect<ast::StructMember*> ParserImpl::expect_struct_member() {
decl->type, std::move(attrs.value));
}
+// static_assert_statement
+// : STATIC_ASSERT expression
+Maybe<const ast::StaticAssert*> ParserImpl::static_assert_statement() {
+ Source start;
+ if (!match(Token::Type::kStaticAssert, &start)) {
+ return Failure::kNoMatch;
+ }
+
+ auto condition = expression();
+ if (condition.errored) {
+ return Failure::kErrored;
+ }
+ if (!condition.matched) {
+ return add_error(peek(), "unable to parse condition expression");
+ }
+
+ Source source = make_source_range_from(start);
+ return create<ast::StaticAssert>(source, condition.value);
+}
+
// function_decl
-// : function_header body_stmt
-Maybe<const ast::Function*> ParserImpl::function_decl(ast::AttributeList& attrs) {
+// : function_header compound_statement
+Maybe<const ast::Function*> ParserImpl::function_decl(AttributeList& attrs) {
auto header = function_header();
if (header.errored) {
if (sync_to(Token::Type::kBraceLeft, /* consume: */ false)) {
@@ -1356,7 +1417,7 @@ Maybe<const ast::Function*> ParserImpl::function_decl(ast::AttributeList& attrs)
// function body. The AST isn't used as we've already errored, but this
// catches any errors inside the body, and can help keep the parser in
// sync.
- expect_body_stmt();
+ expect_compound_statement();
}
return Failure::kErrored;
}
@@ -1366,7 +1427,7 @@ Maybe<const ast::Function*> ParserImpl::function_decl(ast::AttributeList& attrs)
bool errored = false;
- auto body = expect_body_stmt();
+ auto body = expect_compound_statement();
if (body.errored) {
errored = true;
}
@@ -1375,8 +1436,10 @@ Maybe<const ast::Function*> ParserImpl::function_decl(ast::AttributeList& attrs)
return Failure::kErrored;
}
+ TINT_DEFER(attrs.Clear());
+
return create<ast::Function>(header->source, builder_.Symbols().Register(header->name),
- header->params, header->return_type, body.value, attrs,
+ header->params, header->return_type, body.value, std::move(attrs),
header->return_type_attributes);
}
@@ -1411,7 +1474,7 @@ Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
}
const ast::Type* return_type = nullptr;
- ast::AttributeList return_attributes;
+ AttributeList return_attributes;
if (match(Token::Type::kArrow)) {
auto attrs = attribute_list();
@@ -1436,18 +1499,20 @@ Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
return Failure::kErrored;
}
- return FunctionHeader{source, name.value, std::move(params.value), return_type,
- std::move(return_attributes)};
+ return FunctionHeader{
+ source, std::move(name.value), std::move(params.value),
+ return_type, std::move(return_attributes),
+ };
}
// param_list
// :
// | (param COMMA)* param COMMA?
-Expect<ast::VariableList> ParserImpl::expect_param_list() {
- ast::VariableList ret;
+Expect<ParserImpl::ParameterList> ParserImpl::expect_param_list() {
+ ParameterList ret;
while (continue_parsing()) {
// Check for the end of the list.
- auto t = peek();
+ auto& t = peek();
if (!t.IsIdentifier() && !t.Is(Token::Type::kAttr)) {
break;
}
@@ -1456,7 +1521,7 @@ Expect<ast::VariableList> ParserImpl::expect_param_list() {
if (param.errored) {
return Failure::kErrored;
}
- ret.push_back(param.value);
+ ret.Push(param.value);
if (!match(Token::Type::kComma)) {
break;
@@ -1467,70 +1532,119 @@ Expect<ast::VariableList> ParserImpl::expect_param_list() {
}
// param
-// : attribute_list* variable_ident_decl
-Expect<ast::Variable*> ParserImpl::expect_param() {
+// : attribute_list* ident_with_type_decl
+Expect<ast::Parameter*> ParserImpl::expect_param() {
auto attrs = attribute_list();
- auto decl = expect_variable_ident_decl("parameter");
+ auto decl = expect_ident_with_type_decl("parameter");
if (decl.errored) {
return Failure::kErrored;
}
- auto* var = create<ast::Variable>(decl->source, // source
- builder_.Symbols().Register(decl->name), // symbol
- ast::StorageClass::kNone, // storage class
- ast::Access::kUndefined, // access control
- decl->type, // type
- true, // is_const
- false, // is_overridable
- nullptr, // constructor
- std::move(attrs.value)); // attributes
- // Formal parameters are treated like a const declaration where the
- // initializer value is provided by the call's argument. The key point is
- // that it's not updatable after initially set. This is unlike C or GLSL
- // which treat formal parameters like local variables that can be updated.
-
- return var;
+ return create<ast::Parameter>(decl->source, // source
+ builder_.Symbols().Register(decl->name), // symbol
+ decl->type, // type
+ std::move(attrs.value)); // attributes
}
// pipeline_stage
// : VERTEX
// | FRAGMENT
// | COMPUTE
+//
+// TODO(crbug.com/tint/1503): Remove when deprecation period is over.
Expect<ast::PipelineStage> ParserImpl::expect_pipeline_stage() {
- auto t = peek();
- if (t == kVertexStage) {
+ auto& t = peek();
+ if (t == "vertex") {
next(); // Consume the peek
return {ast::PipelineStage::kVertex, t.source()};
}
- if (t == kFragmentStage) {
+ if (t == "fragment") {
next(); // Consume the peek
return {ast::PipelineStage::kFragment, t.source()};
}
- if (t == kComputeStage) {
+ if (t == "compute") {
next(); // Consume the peek
return {ast::PipelineStage::kCompute, t.source()};
}
return add_error(peek(), "invalid value for stage attribute");
}
-Expect<ast::Builtin> ParserImpl::expect_builtin() {
+// interpolation_sample_name
+// : 'center'
+// | 'centroid'
+// | 'sample'
+Expect<ast::InterpolationSampling> ParserImpl::expect_interpolation_sample_name() {
+ auto ident = expect_ident("interpolation sample name");
+ if (ident.errored) {
+ return Failure::kErrored;
+ }
+
+ if (ident.value == "center") {
+ return {ast::InterpolationSampling::kCenter, ident.source};
+ }
+ if (ident.value == "centroid") {
+ return {ast::InterpolationSampling::kCentroid, ident.source};
+ }
+ if (ident.value == "sample") {
+ return {ast::InterpolationSampling::kSample, ident.source};
+ }
+ return add_error(ident.source, "invalid interpolation sampling");
+}
+
+// interpolation_type_name
+// : 'perspective'
+// | 'linear'
+// | 'flat'
+Expect<ast::InterpolationType> ParserImpl::expect_interpolation_type_name() {
+ auto ident = expect_ident("interpolation type name");
+ if (ident.errored) {
+ return Failure::kErrored;
+ }
+
+ if (ident.value == "perspective") {
+ return {ast::InterpolationType::kPerspective, ident.source};
+ }
+ if (ident.value == "linear") {
+ return {ast::InterpolationType::kLinear, ident.source};
+ }
+ if (ident.value == "flat") {
+ return {ast::InterpolationType::kFlat, ident.source};
+ }
+
+ return add_error(ident.source, "invalid interpolation type");
+}
+
+// builtin_value_name
+// : frag_depth
+// | front_facing
+// | global_invocation_id
+// | instance_index
+// | local_invocation_id
+// | local_invocation_index
+// | num_workgroups
+// | position
+// | sample_index
+// | sample_mask
+// | vertex_index
+// | workgroup_id
+Expect<ast::BuiltinValue> ParserImpl::expect_builtin() {
auto ident = expect_ident("builtin");
if (ident.errored) {
return Failure::kErrored;
}
- ast::Builtin builtin = ident_to_builtin(ident.value);
- if (builtin == ast::Builtin::kNone) {
+ ast::BuiltinValue builtin = ast::ParseBuiltinValue(ident.value);
+ if (builtin == ast::BuiltinValue::kInvalid) {
return add_error(ident.source, "invalid value for builtin attribute");
}
return {builtin, ident.source};
}
-// body_stmt
-// : BRACE_LEFT statements BRACE_RIGHT
-Expect<ast::BlockStatement*> ParserImpl::expect_body_stmt() {
+// compound_statement
+// : BRACE_LEFT statement* BRACE_RIGHT
+Expect<ast::BlockStatement*> ParserImpl::expect_compound_statement() {
return expect_brace_block("", [&]() -> Expect<ast::BlockStatement*> {
auto stmts = expect_statements();
if (stmts.errored) {
@@ -1540,11 +1654,11 @@ Expect<ast::BlockStatement*> ParserImpl::expect_body_stmt() {
});
}
-// paren_rhs_stmt
-// : PAREN_LEFT logical_or_expression PAREN_RIGHT
-Expect<const ast::Expression*> ParserImpl::expect_paren_rhs_stmt() {
+// paren_expression
+// : PAREN_LEFT expression PAREN_RIGHT
+Expect<const ast::Expression*> ParserImpl::expect_paren_expression() {
return expect_paren_block("", [&]() -> Expect<const ast::Expression*> {
- auto expr = logical_or_expression();
+ auto expr = expression();
if (expr.errored) {
return Failure::kErrored;
}
@@ -1558,16 +1672,16 @@ Expect<const ast::Expression*> ParserImpl::expect_paren_rhs_stmt() {
// statements
// : statement*
-Expect<ast::StatementList> ParserImpl::expect_statements() {
+Expect<ParserImpl::StatementList> ParserImpl::expect_statements() {
bool errored = false;
- ast::StatementList stmts;
+ StatementList stmts;
while (continue_parsing()) {
auto stmt = statement();
if (stmt.errored) {
errored = true;
} else if (stmt.matched) {
- stmts.emplace_back(stmt.value);
+ stmts.Push(stmt.value);
} else {
break;
}
@@ -1582,29 +1696,20 @@ Expect<ast::StatementList> ParserImpl::expect_statements() {
// statement
// : SEMICOLON
-// | body_stmt?
-// | if_stmt
-// | switch_stmt
-// | loop_stmt
-// | for_stmt
-// | non_block_statement
-// : return_stmt SEMICOLON
-// | func_call_stmt SEMICOLON
-// | variable_stmt SEMICOLON
-// | break_stmt SEMICOLON
-// | continue_stmt SEMICOLON
-// | DISCARD SEMICOLON
-// | assignment_stmt SEMICOLON
-// | increment_stmt SEMICOLON
-// | decrement_stmt SEMICOLON
+// | if_statement
+// | switch_statement
+// | loop_statement
+// | for_statement
+// | while_statement
+// | compound_statement
+// | non_block_statement // Note, we inject an extra rule in here for simpler parsing
Maybe<const ast::Statement*> ParserImpl::statement() {
while (match(Token::Type::kSemicolon)) {
// Skip empty statements
}
- // Non-block statments that error can resynchronize on semicolon.
+ // Non-block statements that error can resynchronize on semicolon.
auto stmt = sync(Token::Type::kSemicolon, [&] { return non_block_statement(); });
-
if (stmt.errored) {
return Failure::kErrored;
}
@@ -1612,7 +1717,7 @@ Maybe<const ast::Statement*> ParserImpl::statement() {
return stmt;
}
- auto stmt_if = if_stmt();
+ auto stmt_if = if_statement();
if (stmt_if.errored) {
return Failure::kErrored;
}
@@ -1620,7 +1725,7 @@ Maybe<const ast::Statement*> ParserImpl::statement() {
return stmt_if.value;
}
- auto sw = switch_stmt();
+ auto sw = switch_statement();
if (sw.errored) {
return Failure::kErrored;
}
@@ -1628,7 +1733,7 @@ Maybe<const ast::Statement*> ParserImpl::statement() {
return sw.value;
}
- auto loop = loop_stmt();
+ auto loop = loop_statement();
if (loop.errored) {
return Failure::kErrored;
}
@@ -1636,7 +1741,7 @@ Maybe<const ast::Statement*> ParserImpl::statement() {
return loop.value;
}
- auto stmt_for = for_stmt();
+ auto stmt_for = for_statement();
if (stmt_for.errored) {
return Failure::kErrored;
}
@@ -1644,8 +1749,16 @@ Maybe<const ast::Statement*> ParserImpl::statement() {
return stmt_for.value;
}
+ auto stmt_while = while_statement();
+ if (stmt_while.errored) {
+ return Failure::kErrored;
+ }
+ if (stmt_while.matched) {
+ return stmt_while.value;
+ }
+
if (peek_is(Token::Type::kBraceLeft)) {
- auto body = expect_body_stmt();
+ auto body = expect_compound_statement();
if (body.errored) {
return Failure::kErrored;
}
@@ -1655,19 +1768,18 @@ Maybe<const ast::Statement*> ParserImpl::statement() {
return Failure::kNoMatch;
}
-// statement (continued)
-// : return_stmt SEMICOLON
-// | func_call_stmt SEMICOLON
-// | variable_stmt SEMICOLON
-// | break_stmt SEMICOLON
-// | continue_stmt SEMICOLON
+// non_block_statement (continued)
+// : return_statement SEMICOLON
+// | func_call_statement SEMICOLON
+// | variable_statement SEMICOLON
+// | break_statement SEMICOLON
+// | continue_statement SEMICOLON
// | DISCARD SEMICOLON
-// | assignment_stmt SEMICOLON
-// | increment_stmt SEMICOLON
-// | decrement_stmt SEMICOLON
+// | variable_updating_statement SEMICOLON
+// | static_assert_statement SEMICOLON
Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
auto stmt = [&]() -> Maybe<const ast::Statement*> {
- auto ret_stmt = return_stmt();
+ auto ret_stmt = return_statement();
if (ret_stmt.errored) {
return Failure::kErrored;
}
@@ -1675,7 +1787,7 @@ Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
return ret_stmt.value;
}
- auto func = func_call_stmt();
+ auto func = func_call_statement();
if (func.errored) {
return Failure::kErrored;
}
@@ -1683,7 +1795,7 @@ Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
return func.value;
}
- auto var = variable_stmt();
+ auto var = variable_statement();
if (var.errored) {
return Failure::kErrored;
}
@@ -1691,7 +1803,7 @@ Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
return var.value;
}
- auto b = break_stmt();
+ auto b = break_statement();
if (b.errored) {
return Failure::kErrored;
}
@@ -1699,7 +1811,7 @@ Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
return b.value;
}
- auto cont = continue_stmt();
+ auto cont = continue_statement();
if (cont.errored) {
return Failure::kErrored;
}
@@ -1707,7 +1819,13 @@ Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
return cont.value;
}
- auto assign = assignment_stmt();
+ Source source;
+ if (match(Token::Type::kDiscard, &source)) {
+ return create<ast::DiscardStatement>(source);
+ }
+
+ // Note, this covers assignment, increment and decrement
+ auto assign = variable_updating_statement();
if (assign.errored) {
return Failure::kErrored;
}
@@ -1715,9 +1833,12 @@ Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
return assign.value;
}
- Source source;
- if (match(Token::Type::kDiscard, &source)) {
- return create<ast::DiscardStatement>(source);
+ auto stmt_static_assert = static_assert_statement();
+ if (stmt_static_assert.errored) {
+ return Failure::kErrored;
+ }
+ if (stmt_static_assert.matched) {
+ return stmt_static_assert.value;
}
return Failure::kNoMatch;
@@ -1726,13 +1847,12 @@ Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
if (stmt.matched && !expect(stmt->Name(), Token::Type::kSemicolon)) {
return Failure::kErrored;
}
-
return stmt;
}
-// return_stmt
-// : RETURN logical_or_expression?
-Maybe<const ast::ReturnStatement*> ParserImpl::return_stmt() {
+// return_statement
+// : RETURN expression?
+Maybe<const ast::ReturnStatement*> ParserImpl::return_statement() {
Source source;
if (!match(Token::Type::kReturn, &source)) {
return Failure::kNoMatch;
@@ -1742,7 +1862,7 @@ Maybe<const ast::ReturnStatement*> ParserImpl::return_stmt() {
return create<ast::ReturnStatement>(source, nullptr);
}
- auto expr = logical_or_expression();
+ auto expr = expression();
if (expr.errored) {
return Failure::kErrored;
}
@@ -1751,44 +1871,67 @@ Maybe<const ast::ReturnStatement*> ParserImpl::return_stmt() {
return create<ast::ReturnStatement>(source, expr.value);
}
-// variable_stmt
+// variable_statement
// : variable_decl
-// | variable_decl EQUAL logical_or_expression
-// | CONST variable_ident_decl EQUAL logical_or_expression
-Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
- if (match(Token::Type::kLet)) {
- auto decl = expect_variable_ident_decl("let declaration",
- /*allow_inferred = */ true);
+// | variable_decl EQUAL expression
+// | LET optionally_typed_ident EQUAL expression
+// | CONST optionally_typed_ident EQUAL expression
+Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_statement() {
+ if (match(Token::Type::kConst)) {
+ auto decl = expect_optionally_typed_ident("'const' declaration");
if (decl.errored) {
return Failure::kErrored;
}
- if (!expect("let declaration", Token::Type::kEqual)) {
+ if (!expect("'const' declaration", Token::Type::kEqual)) {
return Failure::kErrored;
}
- auto constructor = logical_or_expression();
- if (constructor.errored) {
+ auto initializer = expression();
+ if (initializer.errored) {
return Failure::kErrored;
}
- if (!constructor.matched) {
- return add_error(peek(), "missing constructor for let declaration");
+ if (!initializer.matched) {
+ return add_error(peek(), "missing initializer for 'const' declaration");
}
- auto* var = create<ast::Variable>(decl->source, // source
+ auto* const_ = create<ast::Const>(decl->source, // source
builder_.Symbols().Register(decl->name), // symbol
- ast::StorageClass::kNone, // storage class
- ast::Access::kUndefined, // access control
- decl->type, // type
- true, // is_const
- false, // is_overridable
- constructor.value, // constructor
- ast::AttributeList{}); // attributes
+ decl->type, // type
+ initializer.value, // initializer
+ utils::Empty); // attributes
+
+ return create<ast::VariableDeclStatement>(decl->source, const_);
+ }
+
+ if (match(Token::Type::kLet)) {
+ auto decl = expect_optionally_typed_ident("'let' declaration");
+ if (decl.errored) {
+ return Failure::kErrored;
+ }
+
+ if (!expect("'let' declaration", Token::Type::kEqual)) {
+ return Failure::kErrored;
+ }
+
+ auto initializer = expression();
+ if (initializer.errored) {
+ return Failure::kErrored;
+ }
+ if (!initializer.matched) {
+ return add_error(peek(), "missing initializer for 'let' declaration");
+ }
+
+ auto* let = create<ast::Let>(decl->source, // source
+ builder_.Symbols().Register(decl->name), // symbol
+ decl->type, // type
+ initializer.value, // initializer
+ utils::Empty); // attributes
- return create<ast::VariableDeclStatement>(decl->source, var);
+ return create<ast::VariableDeclStatement>(decl->source, let);
}
- auto decl = variable_decl(/*allow_inferred = */ true);
+ auto decl = variable_decl();
if (decl.errored) {
return Failure::kErrored;
}
@@ -1796,38 +1939,36 @@ Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
return Failure::kNoMatch;
}
- const ast::Expression* constructor = nullptr;
+ const ast::Expression* initializer = nullptr;
if (match(Token::Type::kEqual)) {
- auto constructor_expr = logical_or_expression();
- if (constructor_expr.errored) {
+ auto initializer_expr = expression();
+ if (initializer_expr.errored) {
return Failure::kErrored;
}
- if (!constructor_expr.matched) {
- return add_error(peek(), "missing constructor for variable declaration");
+ if (!initializer_expr.matched) {
+ return add_error(peek(), "missing initializer for 'var' declaration");
}
- constructor = constructor_expr.value;
+ initializer = initializer_expr.value;
}
- auto* var = create<ast::Variable>(decl->source, // source
- builder_.Symbols().Register(decl->name), // symbol
- decl->storage_class, // storage class
- decl->access, // access control
- decl->type, // type
- false, // is_const
- false, // is_overridable
- constructor, // constructor
- ast::AttributeList{}); // attributes
+ auto* var = create<ast::Var>(decl->source, // source
+ builder_.Symbols().Register(decl->name), // symbol
+ decl->type, // type
+ decl->storage_class, // storage class
+ decl->access, // access control
+ initializer, // initializer
+ utils::Empty); // attributes
return create<ast::VariableDeclStatement>(var->source, var);
}
-// if_stmt
+// if_statement
// : IF expression compound_stmt ( ELSE else_stmt ) ?
// else_stmt
-// : body_stmt
-// | if_stmt
-Maybe<const ast::IfStatement*> ParserImpl::if_stmt() {
+// : compound_statement
+// | if_statement
+Maybe<const ast::IfStatement*> ParserImpl::if_statement() {
// Parse if-else chains iteratively instead of recursively, to avoid
// stack-overflow for long chains of if-else statements.
@@ -1844,7 +1985,7 @@ Maybe<const ast::IfStatement*> ParserImpl::if_stmt() {
return Failure::kNoMatch;
}
- auto condition = logical_or_expression();
+ auto condition = expression();
if (condition.errored) {
return Failure::kErrored;
}
@@ -1852,7 +1993,7 @@ Maybe<const ast::IfStatement*> ParserImpl::if_stmt() {
return add_error(peek(), "unable to parse condition expression");
}
- auto body = expect_body_stmt();
+ auto body = expect_compound_statement();
if (body.errored) {
return Failure::kErrored;
}
@@ -1888,7 +2029,7 @@ Maybe<const ast::IfStatement*> ParserImpl::if_stmt() {
}
// If it wasn't an "else if", it must just be an "else".
- auto else_body = expect_body_stmt();
+ auto else_body = expect_compound_statement();
if (else_body.errored) {
return Failure::kErrored;
}
@@ -1904,15 +2045,15 @@ Maybe<const ast::IfStatement*> ParserImpl::if_stmt() {
return last_stmt->As<ast::IfStatement>();
}
-// switch_stmt
-// : SWITCH paren_rhs_stmt BRACKET_LEFT switch_body+ BRACKET_RIGHT
-Maybe<const ast::SwitchStatement*> ParserImpl::switch_stmt() {
+// switch_statement
+// : SWITCH expression BRACKET_LEFT switch_body+ BRACKET_RIGHT
+Maybe<const ast::SwitchStatement*> ParserImpl::switch_statement() {
Source source;
if (!match(Token::Type::kSwitch, &source)) {
return Failure::kNoMatch;
}
- auto condition = logical_or_expression();
+ auto condition = expression();
if (condition.errored) {
return Failure::kErrored;
}
@@ -1920,9 +2061,9 @@ Maybe<const ast::SwitchStatement*> ParserImpl::switch_stmt() {
return add_error(peek(), "unable to parse selector expression");
}
- auto body = expect_brace_block("switch statement", [&]() -> Expect<ast::CaseStatementList> {
+ auto body = expect_brace_block("switch statement", [&]() -> Expect<CaseStatementList> {
bool errored = false;
- ast::CaseStatementList list;
+ CaseStatementList list;
while (continue_parsing()) {
auto stmt = switch_body();
if (stmt.errored) {
@@ -1932,7 +2073,7 @@ Maybe<const ast::SwitchStatement*> ParserImpl::switch_stmt() {
if (!stmt.matched) {
break;
}
- list.push_back(stmt.value);
+ list.Push(stmt.value);
}
if (errored) {
return Failure::kErrored;
@@ -1955,10 +2096,9 @@ Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
return Failure::kNoMatch;
}
- auto t = next();
- auto source = t.source();
+ auto& t = next();
- ast::CaseSelectorList selector_list;
+ CaseSelectorList selector_list;
if (t.Is(Token::Type::kCase)) {
auto selectors = expect_case_selectors();
if (selectors.errored) {
@@ -1981,13 +2121,13 @@ Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
return add_error(body.source, "expected case body");
}
- return create<ast::CaseStatement>(source, selector_list, body.value);
+ return create<ast::CaseStatement>(t.source(), selector_list, body.value);
}
// case_selectors
// : const_literal (COMMA const_literal)* COMMA?
-Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() {
- ast::CaseSelectorList selectors;
+Expect<ParserImpl::CaseSelectorList> ParserImpl::expect_case_selectors() {
+ CaseSelectorList selectors;
while (continue_parsing()) {
auto cond = const_literal();
@@ -1999,14 +2139,14 @@ Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() {
return add_error(cond.value->source, "invalid case selector must be an integer value");
}
- selectors.push_back(cond.value->As<ast::IntLiteralExpression>());
+ selectors.Push(cond.value->As<ast::IntLiteralExpression>());
if (!match(Token::Type::kComma)) {
break;
}
}
- if (selectors.empty()) {
+ if (selectors.IsEmpty()) {
return add_error(peek(), "unable to parse case selectors");
}
@@ -2018,7 +2158,7 @@ Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() {
// | statement case_body
// | FALLTHROUGH SEMICOLON
Maybe<const ast::BlockStatement*> ParserImpl::case_body() {
- ast::StatementList stmts;
+ StatementList stmts;
while (continue_parsing()) {
Source source;
if (match(Token::Type::kFallthrough, &source)) {
@@ -2026,7 +2166,12 @@ Maybe<const ast::BlockStatement*> ParserImpl::case_body() {
return Failure::kErrored;
}
- stmts.emplace_back(create<ast::FallthroughStatement>(source));
+ deprecated(source,
+ "fallthrough is set to be removed from WGSL. "
+ "Case can accept multiple selectors if the existing case bodies are empty. "
+ "default is not yet supported in a case selector list.");
+
+ stmts.Push(create<ast::FallthroughStatement>(source));
break;
}
@@ -2038,15 +2183,15 @@ Maybe<const ast::BlockStatement*> ParserImpl::case_body() {
break;
}
- stmts.emplace_back(stmt.value);
+ stmts.Push(stmt.value);
}
return create<ast::BlockStatement>(Source{}, stmts);
}
-// loop_stmt
-// : LOOP BRACKET_LEFT statements continuing_stmt? BRACKET_RIGHT
-Maybe<const ast::LoopStatement*> ParserImpl::loop_stmt() {
+// loop_statement
+// : LOOP BRACKET_LEFT statements continuing_statement? BRACKET_RIGHT
+Maybe<const ast::LoopStatement*> ParserImpl::loop_statement() {
Source source;
if (!match(Token::Type::kLoop, &source)) {
return Failure::kNoMatch;
@@ -2058,7 +2203,7 @@ Maybe<const ast::LoopStatement*> ParserImpl::loop_stmt() {
return Failure::kErrored;
}
- auto continuing = continuing_stmt();
+ auto continuing = continuing_statement();
if (continuing.errored) {
return Failure::kErrored;
}
@@ -2075,10 +2220,10 @@ ForHeader::ForHeader(const ast::Statement* init,
ForHeader::~ForHeader() = default;
-// (variable_stmt | increment_stmt | decrement_stmt | assignment_stmt |
-// func_call_stmt)?
+// (variable_statement | variable_updating_statement |
+// func_call_statement)?
Maybe<const ast::Statement*> ParserImpl::for_header_initializer() {
- auto call = func_call_stmt();
+ auto call = func_call_statement();
if (call.errored) {
return Failure::kErrored;
}
@@ -2086,7 +2231,7 @@ Maybe<const ast::Statement*> ParserImpl::for_header_initializer() {
return call.value;
}
- auto var = variable_stmt();
+ auto var = variable_statement();
if (var.errored) {
return Failure::kErrored;
}
@@ -2094,7 +2239,7 @@ Maybe<const ast::Statement*> ParserImpl::for_header_initializer() {
return var.value;
}
- auto assign = assignment_stmt();
+ auto assign = variable_updating_statement();
if (assign.errored) {
return Failure::kErrored;
}
@@ -2105,9 +2250,9 @@ Maybe<const ast::Statement*> ParserImpl::for_header_initializer() {
return Failure::kNoMatch;
}
-// (increment_stmt | decrement_stmt | assignment_stmt | func_call_stmt)?
+// (variable_updating_statement | func_call_statement)?
Maybe<const ast::Statement*> ParserImpl::for_header_continuing() {
- auto call_stmt = func_call_stmt();
+ auto call_stmt = func_call_statement();
if (call_stmt.errored) {
return Failure::kErrored;
}
@@ -2115,7 +2260,7 @@ Maybe<const ast::Statement*> ParserImpl::for_header_continuing() {
return call_stmt.value;
}
- auto assign = assignment_stmt();
+ auto assign = variable_updating_statement();
if (assign.errored) {
return Failure::kErrored;
}
@@ -2127,10 +2272,10 @@ Maybe<const ast::Statement*> ParserImpl::for_header_continuing() {
}
// for_header
-// : (variable_stmt | assignment_stmt | func_call_stmt)?
+// : (variable_statement | variable_updating_statement | func_call_statement)?
// SEMICOLON
-// logical_or_expression? SEMICOLON
-// (assignment_stmt | func_call_stmt)?
+// expression? SEMICOLON
+// (variable_updating_statement | func_call_statement)?
Expect<std::unique_ptr<ForHeader>> ParserImpl::expect_for_header() {
auto initializer = for_header_initializer();
if (initializer.errored) {
@@ -2141,7 +2286,7 @@ Expect<std::unique_ptr<ForHeader>> ParserImpl::expect_for_header() {
return Failure::kErrored;
}
- auto condition = logical_or_expression();
+ auto condition = expression();
if (condition.errored) {
return Failure::kErrored;
}
@@ -2160,7 +2305,7 @@ Expect<std::unique_ptr<ForHeader>> ParserImpl::expect_for_header() {
// for_statement
// : FOR PAREN_LEFT for_header PAREN_RIGHT BRACE_LEFT statements BRACE_RIGHT
-Maybe<const ast::ForLoopStatement*> ParserImpl::for_stmt() {
+Maybe<const ast::ForLoopStatement*> ParserImpl::for_statement() {
Source source;
if (!match(Token::Type::kFor, &source)) {
return Failure::kNoMatch;
@@ -2181,35 +2326,57 @@ Maybe<const ast::ForLoopStatement*> ParserImpl::for_stmt() {
create<ast::BlockStatement>(stmts.value));
}
-// func_call_stmt
+// while_statement
+// : WHILE expression compound_statement
+Maybe<const ast::WhileStatement*> ParserImpl::while_statement() {
+ Source source;
+ if (!match(Token::Type::kWhile, &source)) {
+ return Failure::kNoMatch;
+ }
+
+ auto condition = expression();
+ if (condition.errored) {
+ return Failure::kErrored;
+ }
+ if (!condition.matched) {
+ return add_error(peek(), "unable to parse while condition expression");
+ }
+
+ auto body = expect_compound_statement();
+ if (body.errored) {
+ return Failure::kErrored;
+ }
+
+ return create<ast::WhileStatement>(source, condition.value, body.value);
+}
+
+// func_call_statement
// : IDENT argument_expression_list
-Maybe<const ast::CallStatement*> ParserImpl::func_call_stmt() {
- auto t = peek();
- auto t2 = peek(1);
+Maybe<const ast::CallStatement*> ParserImpl::func_call_statement() {
+ auto& t = peek();
+ auto& t2 = peek(1);
if (!t.IsIdentifier() || !t2.Is(Token::Type::kParenLeft)) {
return Failure::kNoMatch;
}
next(); // Consume the first peek
- auto source = t.source();
- auto name = t.to_str();
-
auto params = expect_argument_expression_list("function call");
if (params.errored) {
return Failure::kErrored;
}
return create<ast::CallStatement>(
- source,
+ t.source(),
create<ast::CallExpression>(
- source, create<ast::IdentifierExpression>(source, builder_.Symbols().Register(name)),
+ t.source(),
+ create<ast::IdentifierExpression>(t.source(), builder_.Symbols().Register(t.to_str())),
std::move(params.value)));
}
-// break_stmt
+// break_statement
// : BREAK
-Maybe<const ast::BreakStatement*> ParserImpl::break_stmt() {
+Maybe<const ast::BreakStatement*> ParserImpl::break_statement() {
Source source;
if (!match(Token::Type::kBreak, &source)) {
return Failure::kNoMatch;
@@ -2218,9 +2385,9 @@ Maybe<const ast::BreakStatement*> ParserImpl::break_stmt() {
return create<ast::BreakStatement>(source);
}
-// continue_stmt
+// continue_statement
// : CONTINUE
-Maybe<const ast::ContinueStatement*> ParserImpl::continue_stmt() {
+Maybe<const ast::ContinueStatement*> ParserImpl::continue_statement() {
Source source;
if (!match(Token::Type::kContinue, &source)) {
return Failure::kNoMatch;
@@ -2229,25 +2396,52 @@ Maybe<const ast::ContinueStatement*> ParserImpl::continue_stmt() {
return create<ast::ContinueStatement>(source);
}
-// continuing_stmt
-// : CONTINUING body_stmt
-Maybe<const ast::BlockStatement*> ParserImpl::continuing_stmt() {
+// break_if_statement:
+// 'break' 'if' expression semicolon
+Maybe<const ast::Statement*> ParserImpl::break_if_statement() {
+ // TODO(crbug.com/tint/1451): Add support for break-if
+ return Failure::kNoMatch;
+}
+
+// continuing_compound_statement:
+// brace_left statement* break_if_statement? brace_right
+Maybe<const ast::BlockStatement*> ParserImpl::continuing_compound_statement() {
+ return expect_brace_block("", [&]() -> Expect<ast::BlockStatement*> {
+ auto stmts = expect_statements();
+ if (stmts.errored) {
+ return Failure::kErrored;
+ }
+
+ auto break_if = break_if_statement();
+ if (break_if.errored) {
+ return Failure::kErrored;
+ }
+ if (break_if.matched) {
+ stmts.value.Push(break_if.value);
+ }
+
+ return create<ast::BlockStatement>(Source{}, stmts.value);
+ });
+}
+
+// continuing_statement
+// : CONTINUING continuing_compound_statement
+Maybe<const ast::BlockStatement*> ParserImpl::continuing_statement() {
if (!match(Token::Type::kContinuing)) {
- return create<ast::BlockStatement>(Source{}, ast::StatementList{});
+ return create<ast::BlockStatement>(Source{}, utils::Empty);
}
- return expect_body_stmt();
+ return continuing_compound_statement();
}
// primary_expression
// : IDENT argument_expression_list?
// | type_decl argument_expression_list
// | const_literal
-// | paren_rhs_stmt
-// | BITCAST LESS_THAN type_decl GREATER_THAN paren_rhs_stmt
+// | paren_expression
+// | BITCAST LESS_THAN type_decl GREATER_THAN paren_expression
Maybe<const ast::Expression*> ParserImpl::primary_expression() {
- auto t = peek();
- auto source = t.source();
+ auto& t = peek();
auto lit = const_literal();
if (lit.errored) {
@@ -2258,7 +2452,7 @@ Maybe<const ast::Expression*> ParserImpl::primary_expression() {
}
if (t.Is(Token::Type::kParenLeft)) {
- auto paren = expect_paren_rhs_stmt();
+ auto paren = expect_paren_expression();
if (paren.errored) {
return Failure::kErrored;
}
@@ -2274,12 +2468,12 @@ Maybe<const ast::Expression*> ParserImpl::primary_expression() {
return Failure::kErrored;
}
- auto params = expect_paren_rhs_stmt();
+ auto params = expect_paren_expression();
if (params.errored) {
return Failure::kErrored;
}
- return create<ast::BitcastExpression>(source, type.value, params.value);
+ return create<ast::BitcastExpression>(t.source(), type.value, params.value);
}
if (t.IsIdentifier()) {
@@ -2294,7 +2488,7 @@ Maybe<const ast::Expression*> ParserImpl::primary_expression() {
return Failure::kErrored;
}
- return create<ast::CallExpression>(source, ident, std::move(params.value));
+ return create<ast::CallExpression>(t.source(), ident, std::move(params.value));
}
return ident;
@@ -2310,7 +2504,7 @@ Maybe<const ast::Expression*> ParserImpl::primary_expression() {
return Failure::kErrored;
}
- return builder_.Construct(source, type.value, std::move(params.value));
+ return builder_.Construct(t.source(), type.value, std::move(params.value));
}
return Failure::kNoMatch;
@@ -2318,15 +2512,16 @@ Maybe<const ast::Expression*> ParserImpl::primary_expression() {
// postfix_expression
// :
-// | BRACE_LEFT logical_or_expression BRACE_RIGHT postfix_expr
-// | PERIOD IDENTIFIER postfix_expr
+// | BRACE_LEFT expression BRACE_RIGHT postfix_expression?
+// | PERIOD member_ident postfix_expression?
+// | PERIOD swizzle_name postfix_expression?
Maybe<const ast::Expression*> ParserImpl::postfix_expression(const ast::Expression* prefix) {
Source source;
while (continue_parsing()) {
if (match(Token::Type::kBracketLeft, &source)) {
auto res = sync(Token::Type::kBracketRight, [&]() -> Maybe<const ast::Expression*> {
- auto param = logical_or_expression();
+ auto param = expression();
if (param.errored) {
return Failure::kErrored;
}
@@ -2382,19 +2577,19 @@ Maybe<const ast::Expression*> ParserImpl::singular_expression() {
}
// argument_expression_list
-// : PAREN_LEFT ((logical_or_expression COMMA)* logical_or_expression COMMA?)?
-// PAREN_RIGHT
-Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(std::string_view use) {
- return expect_paren_block(use, [&]() -> Expect<ast::ExpressionList> {
- ast::ExpressionList ret;
+// : PAREN_LEFT ((expression COMMA)* expression COMMA?)? PAREN_RIGHT
+Expect<ParserImpl::ExpressionList> ParserImpl::expect_argument_expression_list(
+ std::string_view use) {
+ return expect_paren_block(use, [&]() -> Expect<ExpressionList> {
+ ExpressionList ret;
while (continue_parsing()) {
- auto arg = logical_or_expression();
+ auto arg = expression();
if (arg.errored) {
return Failure::kErrored;
} else if (!arg.matched) {
break;
}
- ret.push_back(arg.value);
+ ret.Push(arg.value);
if (!match(Token::Type::kComma)) {
break;
@@ -2404,6 +2599,64 @@ Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(std::str
});
}
+// bitwise_expression.post.unary_expression
+// : AND unary_expression (AND unary_expression)*
+// | OR unary_expression (OR unary_expression)*
+// | XOR unary_expression (XOR unary_expression)*
+Maybe<const ast::Expression*> ParserImpl::bitwise_expression_post_unary_expression(
+ const ast::Expression* lhs) {
+ auto& t = peek();
+ if (!t.Is(Token::Type::kAnd) && !t.Is(Token::Type::kOr) && !t.Is(Token::Type::kXor)) {
+ return Failure::kNoMatch;
+ }
+
+ ast::BinaryOp op = ast::BinaryOp::kXor;
+ if (t.Is(Token::Type::kAnd)) {
+ op = ast::BinaryOp::kAnd;
+ } else if (t.Is(Token::Type::kOr)) {
+ op = ast::BinaryOp::kOr;
+ }
+
+ while (continue_parsing()) {
+ auto& n = peek();
+ // Handle the case of `a & b &&c` where `&c` is a unary_expression
+ bool split = false;
+ if (op == ast::BinaryOp::kAnd && n.Is(Token::Type::kAndAnd)) {
+ next();
+ split_token(Token::Type::kAnd, Token::Type::kAnd);
+ split = true;
+ }
+
+ if (!n.Is(t.type())) {
+ if (n.Is(Token::Type::kAnd) || n.Is(Token::Type::kOr) || n.Is(Token::Type::kXor)) {
+ return add_error(n.source(), std::string("mixing '") + std::string(t.to_name()) +
+ "' and '" + std::string(n.to_name()) +
+ "' requires parenthesis");
+ }
+
+ return lhs;
+ }
+ // If forced to split an `&&` then we've already done the `next` above which consumes
+ // the `&`. The type check above will always fail because we only split if already consuming
+ // a `&` operator.
+ if (!split) {
+ next();
+ }
+
+ auto rhs = unary_expression();
+ if (rhs.errored) {
+ return Failure::kErrored;
+ }
+ if (!rhs.matched) {
+ return add_error(peek(), std::string("unable to parse right side of ") +
+ std::string(t.to_name()) + " expression");
+ }
+
+ lhs = create<ast::BinaryExpression>(t.source(), op, lhs, rhs.value);
+ }
+ return Failure::kErrored;
+}
+
// unary_expression
// : singular_expression
// | MINUS unary_expression
@@ -2412,7 +2665,7 @@ Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(std::str
// | STAR unary_expression
// | AND unary_expression
Maybe<const ast::Expression*> ParserImpl::unary_expression() {
- auto t = peek();
+ auto& t = peek();
if (match(Token::Type::kPlusPlus) || match(Token::Type::kMinusMinus)) {
add_error(t.source(),
@@ -2477,20 +2730,18 @@ Expect<const ast::Expression*> ParserImpl::expect_multiplicative_expr(const ast:
return lhs;
}
- auto t = next();
- auto source = t.source();
- auto name = t.to_name();
+ auto& t = next();
auto rhs = unary_expression();
if (rhs.errored) {
return Failure::kErrored;
}
if (!rhs.matched) {
- return add_error(peek(),
- "unable to parse right side of " + std::string(name) + " expression");
+ return add_error(peek(), "unable to parse right side of " + std::string(t.to_name()) +
+ " expression");
}
- lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+ lhs = create<ast::BinaryExpression>(t.source(), op, lhs, rhs.value);
}
return Failure::kErrored;
}
@@ -2524,8 +2775,7 @@ Expect<const ast::Expression*> ParserImpl::expect_additive_expr(const ast::Expre
return lhs;
}
- auto t = next();
- auto source = t.source();
+ auto& t = next();
auto rhs = multiplicative_expression();
if (rhs.errored) {
@@ -2535,7 +2785,7 @@ Expect<const ast::Expression*> ParserImpl::expect_additive_expr(const ast::Expre
return add_error(peek(), "unable to parse right side of + expression");
}
- lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+ lhs = create<ast::BinaryExpression>(t.source(), op, lhs, rhs.value);
}
return Failure::kErrored;
}
@@ -2572,8 +2822,7 @@ Expect<const ast::Expression*> ParserImpl::expect_shift_expr(const ast::Expressi
return lhs;
}
- auto t = next();
- auto source = t.source();
+ auto& t = next();
auto rhs = additive_expression();
if (rhs.errored) {
return Failure::kErrored;
@@ -2583,7 +2832,7 @@ Expect<const ast::Expression*> ParserImpl::expect_shift_expr(const ast::Expressi
std::string("unable to parse right side of ") + name + " expression");
}
- return lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+ return lhs = create<ast::BinaryExpression>(t.source(), op, lhs, rhs.value);
}
return Failure::kErrored;
}
@@ -2623,20 +2872,18 @@ Expect<const ast::Expression*> ParserImpl::expect_relational_expr(const ast::Exp
return lhs;
}
- auto t = next();
- auto source = t.source();
- auto name = t.to_name();
+ auto& t = next();
auto rhs = shift_expression();
if (rhs.errored) {
return Failure::kErrored;
}
if (!rhs.matched) {
- return add_error(peek(),
- "unable to parse right side of " + std::string(name) + " expression");
+ return add_error(peek(), "unable to parse right side of " + std::string(t.to_name()) +
+ " expression");
}
- lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+ lhs = create<ast::BinaryExpression>(t.source(), op, lhs, rhs.value);
}
return Failure::kErrored;
}
@@ -2670,20 +2917,18 @@ Expect<const ast::Expression*> ParserImpl::expect_equality_expr(const ast::Expre
return lhs;
}
- auto t = next();
- auto source = t.source();
- auto name = t.to_name();
+ auto& t = next();
auto rhs = relational_expression();
if (rhs.errored) {
return Failure::kErrored;
}
if (!rhs.matched) {
- return add_error(peek(),
- "unable to parse right side of " + std::string(name) + " expression");
+ return add_error(peek(), "unable to parse right side of " + std::string(t.to_name()) +
+ " expression");
}
- lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+ lhs = create<ast::BinaryExpression>(t.source(), op, lhs, rhs.value);
}
return Failure::kErrored;
}
@@ -2711,8 +2956,7 @@ Expect<const ast::Expression*> ParserImpl::expect_and_expr(const ast::Expression
return lhs;
}
- auto t = next();
- auto source = t.source();
+ auto& t = next();
auto rhs = equality_expression();
if (rhs.errored) {
@@ -2722,7 +2966,7 @@ Expect<const ast::Expression*> ParserImpl::expect_and_expr(const ast::Expression
return add_error(peek(), "unable to parse right side of & expression");
}
- lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kAnd, lhs, rhs.value);
+ lhs = create<ast::BinaryExpression>(t.source(), ast::BinaryOp::kAnd, lhs, rhs.value);
}
return Failure::kErrored;
}
@@ -2824,8 +3068,7 @@ Expect<const ast::Expression*> ParserImpl::expect_logical_and_expr(const ast::Ex
return lhs;
}
- auto t = next();
- auto source = t.source();
+ auto& t = next();
auto rhs = inclusive_or_expression();
if (rhs.errored) {
@@ -2835,7 +3078,7 @@ Expect<const ast::Expression*> ParserImpl::expect_logical_and_expr(const ast::Ex
return add_error(peek(), "unable to parse right side of && expression");
}
- lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalAnd, lhs, rhs.value);
+ lhs = create<ast::BinaryExpression>(t.source(), ast::BinaryOp::kLogicalAnd, lhs, rhs.value);
}
return Failure::kErrored;
}
@@ -2891,15 +3134,26 @@ Maybe<const ast::Expression*> ParserImpl::logical_or_expression() {
return expect_logical_or_expr(lhs.value);
}
-// compound_assignment_operator:
-// | plus_equal
-// | minus_equal
-// | times_equal
-// | division_equal
-// | modulo_equal
-// | and_equal
-// | or_equal
-// | xor_equal
+// expression:
+// : relational_expression
+// | short_circuit_or_expression or_or relational_expression
+// | short_circuit_and_expression and_and relational_expression
+// | bitwise_expression
+Maybe<const ast::Expression*> ParserImpl::expression() {
+ return logical_or_expression();
+}
+
+// compound_assignment_operator
+// : plus_equal
+// | minus_equal
+// | times_equal
+// | division_equal
+// | modulo_equal
+// | and_equal
+// | or_equal
+// | xor_equal
+// | shift_right_equal
+// | shift_left_equal
Maybe<ast::BinaryOp> ParserImpl::compound_assignment_operator() {
ast::BinaryOp compound_op = ast::BinaryOp::kNone;
if (peek_is(Token::Type::kPlusEqual)) {
@@ -2918,6 +3172,10 @@ Maybe<ast::BinaryOp> ParserImpl::compound_assignment_operator() {
compound_op = ast::BinaryOp::kOr;
} else if (peek_is(Token::Type::kXorEqual)) {
compound_op = ast::BinaryOp::kXor;
+ } else if (peek_is(Token::Type::kShiftLeftEqual)) {
+ compound_op = ast::BinaryOp::kShiftLeft;
+ } else if (peek_is(Token::Type::kShiftRightEqual)) {
+ compound_op = ast::BinaryOp::kShiftRight;
}
if (compound_op != ast::BinaryOp::kNone) {
next();
@@ -2926,56 +3184,140 @@ Maybe<ast::BinaryOp> ParserImpl::compound_assignment_operator() {
return Failure::kNoMatch;
}
-// assignment_stmt
-// | lhs_expression ( equal | compound_assignment_operator ) expression
-// | underscore equal expression
-// increment_stmt
-// | lhs_expression PLUS_PLUS
-// decrement_stmt
-// | lhs_expression MINUS_MINUS
-Maybe<const ast::Statement*> ParserImpl::assignment_stmt() {
- auto t = peek();
- auto source = t.source();
+// core_lhs_expression
+// : ident
+// | PAREN_LEFT lhs_expression PAREN_RIGHT
+Maybe<const ast::Expression*> ParserImpl::core_lhs_expression() {
+ auto& t = peek();
+ if (t.IsIdentifier()) {
+ next();
- // tint:295 - Test for `ident COLON` - this is invalid grammar, and without
- // special casing will error as "missing = for assignment", which is less
- // helpful than this error message:
- if (peek_is(Token::Type::kIdentifier) && peek_is(Token::Type::kColon, 1)) {
- return add_error(peek(0).source(), "expected 'var' for variable declaration");
+ return create<ast::IdentifierExpression>(t.source(),
+ builder_.Symbols().Register(t.to_str()));
}
- auto lhs = unary_expression();
- if (lhs.errored) {
- return Failure::kErrored;
+ if (peek_is(Token::Type::kParenLeft)) {
+ return expect_paren_block("", [&]() -> Expect<const ast::Expression*> {
+ auto expr = lhs_expression();
+ if (expr.errored) {
+ return Failure::kErrored;
+ }
+ if (!expr.matched) {
+ return add_error(t, "invalid expression");
+ }
+ return expr.value;
+ });
}
- if (!lhs.matched) {
- if (!match(Token::Type::kUnderscore, &source)) {
+
+ return Failure::kNoMatch;
+}
+
+// lhs_expression
+// : ( STAR | AND )* core_lhs_expression postfix_expression?
+Maybe<const ast::Expression*> ParserImpl::lhs_expression() {
+ std::vector<const Token*> prefixes;
+ while (peek_is(Token::Type::kStar) || peek_is(Token::Type::kAnd) ||
+ peek_is(Token::Type::kAndAnd)) {
+ auto& t = next();
+
+ // If an '&&' is provided split into '&' and '&'
+ if (t.Is(Token::Type::kAndAnd)) {
+ split_token(Token::Type::kAnd, Token::Type::kAnd);
+ }
+
+ prefixes.push_back(&t);
+ }
+
+ auto core_expr = core_lhs_expression();
+ if (core_expr.errored) {
+ return Failure::kErrored;
+ } else if (!core_expr.matched) {
+ if (prefixes.empty()) {
return Failure::kNoMatch;
}
- lhs = create<ast::PhonyExpression>(source);
+
+ return add_error(peek(), "missing expression");
}
- // Handle increment and decrement statements.
- // We do this here because the parsing of the LHS expression overlaps with
- // the assignment statement, and we cannot tell which we are parsing until we
- // hit the ++/--/= token.
- if (match(Token::Type::kPlusPlus)) {
- return create<ast::IncrementDecrementStatement>(source, lhs.value, true);
- } else if (match(Token::Type::kMinusMinus)) {
- return create<ast::IncrementDecrementStatement>(source, lhs.value, false);
+ const auto* expr = core_expr.value;
+ for (auto it = prefixes.rbegin(); it != prefixes.rend(); ++it) {
+ auto& t = **it;
+ ast::UnaryOp op = ast::UnaryOp::kAddressOf;
+ if (t.Is(Token::Type::kStar)) {
+ op = ast::UnaryOp::kIndirection;
+ }
+ expr = create<ast::UnaryOpExpression>(t.source(), op, expr);
}
- auto compound_op = compound_assignment_operator();
- if (compound_op.errored) {
+ auto e = postfix_expression(expr);
+ if (e.errored) {
return Failure::kErrored;
}
- if (!compound_op.matched) {
+ return e.value;
+}
+
+// variable_updating_statement
+// : lhs_expression ( EQUAL | compound_assignment_operator ) expression
+// | lhs_expression MINUS_MINUS
+// | lhs_expression PLUS_PLUS
+// | UNDERSCORE EQUAL expression
+//
+// Note, this is a simplification of the recursive grammar statement with the `lhs_expression`
+// substituted back into the expression.
+Maybe<const ast::Statement*> ParserImpl::variable_updating_statement() {
+ auto& t = peek();
+
+ // tint:295 - Test for `ident COLON` - this is invalid grammar, and without
+ // special casing will error as "missing = for assignment", which is less
+ // helpful than this error message:
+ if (peek_is(Token::Type::kIdentifier) && peek_is(Token::Type::kColon, 1)) {
+ return add_error(peek(0).source(), "expected 'var' for variable declaration");
+ }
+
+ const ast::Expression* lhs = nullptr;
+ ast::BinaryOp compound_op = ast::BinaryOp::kNone;
+ if (peek_is(Token::Type::kUnderscore)) {
+ next(); // Consume the peek.
+
if (!expect("assignment", Token::Type::kEqual)) {
return Failure::kErrored;
}
+
+ lhs = create<ast::PhonyExpression>(t.source());
+
+ } else {
+ auto lhs_result = lhs_expression();
+ if (lhs_result.errored) {
+ return Failure::kErrored;
+ }
+ if (!lhs_result.matched) {
+ return Failure::kNoMatch;
+ }
+
+ lhs = lhs_result.value;
+
+ // Handle increment and decrement statements.
+ if (match(Token::Type::kPlusPlus)) {
+ return create<ast::IncrementDecrementStatement>(t.source(), lhs, true);
+ }
+ if (match(Token::Type::kMinusMinus)) {
+ return create<ast::IncrementDecrementStatement>(t.source(), lhs, false);
+ }
+
+ auto compound_op_result = compound_assignment_operator();
+ if (compound_op_result.errored) {
+ return Failure::kErrored;
+ }
+ if (compound_op_result.matched) {
+ compound_op = compound_op_result.value;
+ } else {
+ if (!expect("assignment", Token::Type::kEqual)) {
+ return Failure::kErrored;
+ }
+ }
}
- auto rhs = logical_or_expression();
+ auto rhs = expression();
if (rhs.errored) {
return Failure::kErrored;
}
@@ -2983,21 +3325,22 @@ Maybe<const ast::Statement*> ParserImpl::assignment_stmt() {
return add_error(peek(), "unable to parse right side of assignment");
}
- if (compound_op.value != ast::BinaryOp::kNone) {
- return create<ast::CompoundAssignmentStatement>(source, lhs.value, rhs.value,
- compound_op.value);
- } else {
- return create<ast::AssignmentStatement>(source, lhs.value, rhs.value);
+ if (compound_op != ast::BinaryOp::kNone) {
+ return create<ast::CompoundAssignmentStatement>(t.source(), lhs, rhs.value, compound_op);
}
+ return create<ast::AssignmentStatement>(t.source(), lhs, rhs.value);
}
// const_literal
// : INT_LITERAL
// | FLOAT_LITERAL
-// | TRUE
+// | bool_literal
+//
+// bool_literal
+// : TRUE
// | FALSE
Maybe<const ast::LiteralExpression*> ParserImpl::const_literal() {
- auto t = peek();
+ auto& t = peek();
if (match(Token::Type::kIntLiteral)) {
return create<ast::IntLiteralExpression>(t.source(), t.to_i64(),
ast::IntLiteralExpression::Suffix::kNone);
@@ -3018,6 +3361,10 @@ Maybe<const ast::LiteralExpression*> ParserImpl::const_literal() {
return create<ast::FloatLiteralExpression>(t.source(), t.to_f64(),
ast::FloatLiteralExpression::Suffix::kF);
}
+ if (match(Token::Type::kFloatLiteral_H)) {
+ return create<ast::FloatLiteralExpression>(t.source(), t.to_f64(),
+ ast::FloatLiteralExpression::Suffix::kH);
+ }
if (match(Token::Type::kTrue)) {
return create<ast::BoolLiteralExpression>(t.source(), true);
}
@@ -3030,68 +3377,16 @@ Maybe<const ast::LiteralExpression*> ParserImpl::const_literal() {
return Failure::kNoMatch;
}
-// const_expr
-// : type_decl PAREN_LEFT ((const_expr COMMA)? const_expr COMMA?)? PAREN_RIGHT
-// | const_literal
-Expect<const ast::Expression*> ParserImpl::expect_const_expr() {
- auto t = peek();
- auto source = t.source();
- if (t.IsLiteral()) {
- auto lit = const_literal();
- if (lit.errored) {
- return Failure::kErrored;
- }
- if (!lit.matched) {
- return add_error(peek(), "unable to parse constant literal");
- }
- return lit.value;
- }
-
- if (peek_is(Token::Type::kParenLeft, 1) || peek_is(Token::Type::kLessThan, 1)) {
- auto type = expect_type("const_expr");
- if (type.errored) {
- return Failure::kErrored;
- }
-
- auto params = expect_paren_block("type constructor", [&]() -> Expect<ast::ExpressionList> {
- ast::ExpressionList list;
- while (continue_parsing()) {
- if (peek_is(Token::Type::kParenRight)) {
- break;
- }
-
- auto arg = expect_const_expr();
- if (arg.errored) {
- return Failure::kErrored;
- }
- list.emplace_back(arg.value);
-
- if (!match(Token::Type::kComma)) {
- break;
- }
- }
- return list;
- });
-
- if (params.errored) {
- return Failure::kErrored;
- }
-
- return builder_.Construct(source, type.value, params.value);
- }
- return add_error(peek(), "unable to parse const_expr");
-}
-
-Maybe<ast::AttributeList> ParserImpl::attribute_list() {
+Maybe<ParserImpl::AttributeList> ParserImpl::attribute_list() {
bool errored = false;
- ast::AttributeList attrs;
+ AttributeList attrs;
while (continue_parsing()) {
if (match(Token::Type::kAttr)) {
if (auto attr = expect_attribute(); attr.errored) {
errored = true;
} else {
- attrs.emplace_back(attr.value);
+ attrs.Push(attr.value);
}
} else {
break;
@@ -3102,7 +3397,7 @@ Maybe<ast::AttributeList> ParserImpl::attribute_list() {
return Failure::kErrored;
}
- if (attrs.empty()) {
+ if (attrs.IsEmpty()) {
return Failure::kNoMatch;
}
@@ -3110,7 +3405,7 @@ Maybe<ast::AttributeList> ParserImpl::attribute_list() {
}
Expect<const ast::Attribute*> ParserImpl::expect_attribute() {
- auto t = peek();
+ auto& t = peek();
auto attr = attribute();
if (attr.errored) {
return Failure::kErrored;
@@ -3121,217 +3416,245 @@ Expect<const ast::Attribute*> ParserImpl::expect_attribute() {
return add_error(t, "expected attribute");
}
+// attribute
+// : ATTR 'align' PAREN_LEFT expression attrib_end
+// | ATTR 'binding' PAREN_LEFT expression attrib_end
+// | ATTR 'builtin' PAREN_LEFT builtin_value_name attrib_end
+// | ATTR 'const'
+// | ATTR 'group' PAREN_LEFT expression attrib_end
+// | ATTR 'id' PAREN_LEFT expression attrib_end
+// | ATTR 'interpolate' PAREN_LEFT interpolation_type_name attrib_end
+// | ATTR 'interpolate' PAREN_LEFT interpolation_type_name COMMA
+// interpolation_sample_name attrib_end
+// | ATTR 'invariant'
+// | ATTR 'location' PAREN_LEFT expression attrib_end
+// | ATTR 'size' PAREN_LEFT expression attrib_end
+// | ATTR 'workgroup_size' PAREN_LEFT expression attrib_end
+// | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression attrib_end
+// | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression COMMA expression attrib_end
+// | ATTR 'vertex'
+// | ATTR 'fragment'
+// | ATTR 'compute'
+//
+// attrib_end
+// : COMMA? PAREN_RIGHT
+//
Maybe<const ast::Attribute*> ParserImpl::attribute() {
using Result = Maybe<const ast::Attribute*>;
- auto t = next();
+ auto& t = next();
if (!t.IsIdentifier()) {
return Failure::kNoMatch;
}
- if (t == kLocationAttribute) {
- const char* use = "location attribute";
+ if (t == "align") {
+ const char* use = "align attribute";
return expect_paren_block(use, [&]() -> Result {
auto val = expect_positive_sint(use);
if (val.errored) {
return Failure::kErrored;
}
+ match(Token::Type::kComma);
- return create<ast::LocationAttribute>(t.source(), val.value);
+ return create<ast::StructMemberAlignAttribute>(t.source(), val.value);
});
}
- if (t == kBindingAttribute) {
+ if (t == "binding") {
const char* use = "binding attribute";
return expect_paren_block(use, [&]() -> Result {
auto val = expect_positive_sint(use);
if (val.errored) {
return Failure::kErrored;
}
+ match(Token::Type::kComma);
return create<ast::BindingAttribute>(t.source(), val.value);
});
}
- if (t == kGroupAttribute) {
- const char* use = "group attribute";
- return expect_paren_block(use, [&]() -> Result {
- auto val = expect_positive_sint(use);
- if (val.errored) {
+ if (t == "builtin") {
+ return expect_paren_block("builtin attribute", [&]() -> Result {
+ auto builtin = expect_builtin();
+ if (builtin.errored) {
return Failure::kErrored;
}
+ match(Token::Type::kComma);
- return create<ast::GroupAttribute>(t.source(), val.value);
+ return create<ast::BuiltinAttribute>(t.source(), builtin.value);
});
}
- if (t == kInterpolateAttribute) {
- return expect_paren_block("interpolate attribute", [&]() -> Result {
- ast::InterpolationType type;
- ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
+ if (t == "compute") {
+ return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
+ }
- auto type_tok = next();
- if (type_tok == "perspective") {
- type = ast::InterpolationType::kPerspective;
- } else if (type_tok == "linear") {
- type = ast::InterpolationType::kLinear;
- } else if (type_tok == "flat") {
- type = ast::InterpolationType::kFlat;
- } else {
- return add_error(type_tok, "invalid interpolation type");
- }
+ // Note, `const` is not valid in a WGSL source file, it's internal only
- if (match(Token::Type::kComma)) {
- auto sampling_tok = next();
- if (sampling_tok == "center") {
- sampling = ast::InterpolationSampling::kCenter;
- } else if (sampling_tok == "centroid") {
- sampling = ast::InterpolationSampling::kCentroid;
- } else if (sampling_tok == "sample") {
- sampling = ast::InterpolationSampling::kSample;
- } else {
- return add_error(sampling_tok, "invalid interpolation sampling");
- }
+ if (t == "fragment") {
+ return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kFragment);
+ }
+
+ if (t == "group") {
+ const char* use = "group attribute";
+ return expect_paren_block(use, [&]() -> Result {
+ auto val = expect_positive_sint(use);
+ if (val.errored) {
+ return Failure::kErrored;
}
+ match(Token::Type::kComma);
- return create<ast::InterpolateAttribute>(t.source(), type, sampling);
+ return create<ast::GroupAttribute>(t.source(), val.value);
});
}
- if (t == kInvariantAttribute) {
- return create<ast::InvariantAttribute>(t.source());
- }
-
- if (t == kBuiltinAttribute) {
- return expect_paren_block("builtin attribute", [&]() -> Result {
- auto builtin = expect_builtin();
- if (builtin.errored) {
+ if (t == "id") {
+ const char* use = "id attribute";
+ return expect_paren_block(use, [&]() -> Result {
+ auto val = expect_positive_sint(use);
+ if (val.errored) {
return Failure::kErrored;
}
+ match(Token::Type::kComma);
- return create<ast::BuiltinAttribute>(t.source(), builtin.value);
+ return create<ast::IdAttribute>(t.source(), val.value);
});
}
- if (t == kWorkgroupSizeAttribute) {
- return expect_paren_block("workgroup_size attribute", [&]() -> Result {
- const ast::Expression* x = nullptr;
- const ast::Expression* y = nullptr;
- const ast::Expression* z = nullptr;
-
- auto expr = primary_expression();
- if (expr.errored) {
+ if (t == "interpolate") {
+ return expect_paren_block("interpolate attribute", [&]() -> Result {
+ auto type = expect_interpolation_type_name();
+ if (type.errored) {
return Failure::kErrored;
- } else if (!expr.matched) {
- return add_error(peek(), "expected workgroup_size x parameter");
}
- x = std::move(expr.value);
+ ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
if (match(Token::Type::kComma)) {
- expr = primary_expression();
- if (expr.errored) {
- return Failure::kErrored;
- } else if (!expr.matched) {
- return add_error(peek(), "expected workgroup_size y parameter");
- }
- y = std::move(expr.value);
-
- if (match(Token::Type::kComma)) {
- expr = primary_expression();
- if (expr.errored) {
+ if (!peek_is(Token::Type::kParenRight)) {
+ auto sample = expect_interpolation_sample_name();
+ if (sample.errored) {
return Failure::kErrored;
- } else if (!expr.matched) {
- return add_error(peek(), "expected workgroup_size z parameter");
}
- z = std::move(expr.value);
+
+ sampling = sample.value;
+ match(Token::Type::kComma);
}
}
- return create<ast::WorkgroupAttribute>(t.source(), x, y, z);
+ return create<ast::InterpolateAttribute>(t.source(), type.value, sampling);
});
}
- if (t == kStageAttribute) {
- return expect_paren_block("stage attribute", [&]() -> Result {
- auto stage = expect_pipeline_stage();
- if (stage.errored) {
+ if (t == "invariant") {
+ return create<ast::InvariantAttribute>(t.source());
+ }
+
+ if (t == "location") {
+ const char* use = "location attribute";
+ return expect_paren_block(use, [&]() -> Result {
+ auto val = expect_positive_sint(use);
+ if (val.errored) {
return Failure::kErrored;
}
+ match(Token::Type::kComma);
- // TODO(crbug.com/tint/1503): Enable this once all the Dawn and CTS
- // tests are updated to use the new format so we can avoid spamming
- // the log files.
- if ((false)) {
- std::string warning = "stage should use @";
- switch (stage.value) {
- case ast::PipelineStage::kVertex:
- warning += "vertex";
- break;
- case ast::PipelineStage::kFragment:
- warning += "fragment";
- break;
- case ast::PipelineStage::kCompute:
- warning += "compute";
- break;
- case ast::PipelineStage::kNone:
- break;
- }
- deprecated(t.source(), warning);
- }
- return create<ast::StageAttribute>(t.source(), stage.value);
+ return create<ast::LocationAttribute>(t.source(), val.value);
});
}
- if (t == kComputeStage) {
- return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
- }
- if (t == kVertexStage) {
- return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
- }
- if (t == kFragmentStage) {
- return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kFragment);
- }
- if (t == kSizeAttribute) {
+ if (t == "size") {
const char* use = "size attribute";
return expect_paren_block(use, [&]() -> Result {
auto val = expect_positive_sint(use);
if (val.errored) {
return Failure::kErrored;
}
+ match(Token::Type::kComma);
return create<ast::StructMemberSizeAttribute>(t.source(), val.value);
});
}
- if (t == kAlignAttribute) {
- const char* use = "align attribute";
- return expect_paren_block(use, [&]() -> Result {
- auto val = expect_positive_sint(use);
- if (val.errored) {
+ // TODO(crbug.com/tint/1503): Remove when deprecation period is over.
+ if (t == "stage") {
+ return expect_paren_block("stage attribute", [&]() -> Result {
+ auto stage = expect_pipeline_stage();
+ if (stage.errored) {
return Failure::kErrored;
}
- return create<ast::StructMemberAlignAttribute>(t.source(), val.value);
+ std::string warning = "remove stage and use @";
+ switch (stage.value) {
+ case ast::PipelineStage::kVertex:
+ warning += "vertex";
+ break;
+ case ast::PipelineStage::kFragment:
+ warning += "fragment";
+ break;
+ case ast::PipelineStage::kCompute:
+ warning += "compute";
+ break;
+ case ast::PipelineStage::kNone:
+ break;
+ }
+ deprecated(t.source(), warning);
+
+ return create<ast::StageAttribute>(t.source(), stage.value);
});
}
- if (t == kIdAttribute) {
- const char* use = "id attribute";
- return expect_paren_block(use, [&]() -> Result {
- auto val = expect_positive_sint(use);
- if (val.errored) {
+ if (t == "vertex") {
+ return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
+ }
+
+ if (t == "workgroup_size") {
+ return expect_paren_block("workgroup_size attribute", [&]() -> Result {
+ const ast::Expression* x = nullptr;
+ const ast::Expression* y = nullptr;
+ const ast::Expression* z = nullptr;
+
+ auto expr = primary_expression();
+ if (expr.errored) {
return Failure::kErrored;
+ } else if (!expr.matched) {
+ return add_error(peek(), "expected workgroup_size x parameter");
}
+ x = std::move(expr.value);
- return create<ast::IdAttribute>(t.source(), val.value);
+ if (match(Token::Type::kComma)) {
+ if (!peek_is(Token::Type::kParenRight)) {
+ expr = primary_expression();
+ if (expr.errored) {
+ return Failure::kErrored;
+ } else if (!expr.matched) {
+ return add_error(peek(), "expected workgroup_size y parameter");
+ }
+ y = std::move(expr.value);
+
+ if (match(Token::Type::kComma)) {
+ if (!peek_is(Token::Type::kParenRight)) {
+ expr = primary_expression();
+ if (expr.errored) {
+ return Failure::kErrored;
+ } else if (!expr.matched) {
+ return add_error(peek(), "expected workgroup_size z parameter");
+ }
+ z = std::move(expr.value);
+
+ match(Token::Type::kComma);
+ }
+ }
+ }
+ }
+
+ return create<ast::WorkgroupAttribute>(t.source(), x, y, z);
});
}
-
return Failure::kNoMatch;
}
-bool ParserImpl::expect_attributes_consumed(ast::AttributeList& in) {
- if (in.empty()) {
+bool ParserImpl::expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> in) {
+ if (in.IsEmpty()) {
return true;
}
add_error(in[0]->source, "unexpected attributes");
@@ -3339,7 +3662,7 @@ bool ParserImpl::expect_attributes_consumed(ast::AttributeList& in) {
}
bool ParserImpl::match(Token::Type tok, Source* source /*= nullptr*/) {
- auto t = peek();
+ auto& t = peek();
if (source != nullptr) {
*source = t.source();
@@ -3353,7 +3676,7 @@ bool ParserImpl::match(Token::Type tok, Source* source /*= nullptr*/) {
}
bool ParserImpl::expect(std::string_view use, Token::Type tok) {
- auto t = peek();
+ auto& t = peek();
if (t.Is(tok)) {
next();
synchronized_ = true;
@@ -3366,12 +3689,10 @@ bool ParserImpl::expect(std::string_view use, Token::Type tok) {
next();
// Push the second character to the token queue.
- auto source = t.source();
- source.range.begin.column++;
if (t.Is(Token::Type::kShiftRight)) {
- token_queue_.push_front(Token(Token::Type::kGreaterThan, source));
+ split_token(Token::Type::kGreaterThan, Token::Type::kGreaterThan);
} else if (t.Is(Token::Type::kGreaterThanEqual)) {
- token_queue_.push_front(Token(Token::Type::kEqual, source));
+ split_token(Token::Type::kGreaterThan, Token::Type::kEqual);
}
synchronized_ = true;
@@ -3394,7 +3715,7 @@ bool ParserImpl::expect(std::string_view use, Token::Type tok) {
}
Expect<int32_t> ParserImpl::expect_sint(std::string_view use) {
- auto t = peek();
+ auto& t = peek();
if (!t.Is(Token::Type::kIntLiteral) && !t.Is(Token::Type::kIntLiteral_I)) {
return add_error(t.source(), "expected signed integer literal", use);
}
@@ -3437,13 +3758,13 @@ Expect<uint32_t> ParserImpl::expect_nonzero_positive_sint(std::string_view use)
}
Expect<std::string> ParserImpl::expect_ident(std::string_view use) {
- auto t = peek();
+ auto& t = peek();
if (t.IsIdentifier()) {
synchronized_ = true;
next();
if (is_reserved(t)) {
- return add_error(t.source(), "'" + t.to_str() + "' is a reserved keyword");
+ deprecated(t.source(), "'" + t.to_str() + "' is a reserved keyword");
}
return {t.to_str(), t.source()};
@@ -3533,7 +3854,7 @@ bool ParserImpl::sync_to(Token::Type tok, bool consume) {
BlockCounters counters;
for (size_t i = 0; i < kMaxResynchronizeLookahead; i++) {
- auto t = peek(i);
+ auto& t = peek(i);
if (counters.consume(t) > 0) {
continue; // Nested block
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.h b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.h
index 67d000437e8..1bde5a45271 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.h
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl.h
@@ -15,7 +15,6 @@
#ifndef SRC_TINT_READER_WGSL_PARSER_IMPL_H_
#define SRC_TINT_READER_WGSL_PARSER_IMPL_H_
-#include <deque>
#include <memory>
#include <string>
#include <string_view>
@@ -72,6 +71,21 @@ class ParserImpl {
};
public:
+ /// Pre-determined small vector sizes for AST pointers
+ //! @cond Doxygen_Suppress
+ using AttributeList = utils::Vector<const ast::Attribute*, 4>;
+ using CaseSelectorList = utils::Vector<const ast::IntLiteralExpression*, 4>;
+ using CaseStatementList = utils::Vector<const ast::CaseStatement*, 4>;
+ using ExpressionList = utils::Vector<const ast::Expression*, 8>;
+ using ParameterList = utils::Vector<const ast::Parameter*, 8>;
+ using StatementList = utils::Vector<const ast::Statement*, 8>;
+ using StructMemberList = utils::Vector<const ast::StructMember*, 8>;
+ //! @endcond
+
+ /// Empty structure used by functions that do not return a value, but need to signal success /
+ /// error with Expect<Void> or Maybe<NoError>.
+ struct Void {};
+
/// Expect is the return type of the parser methods that are expected to
/// return a parsed value of type T, unless there was an parse error.
/// In the case of a parse error the called method will have called
@@ -232,9 +246,9 @@ class ParserImpl {
/// @param ret_attrs return type attributes
FunctionHeader(Source src,
std::string n,
- ast::VariableList p,
+ utils::VectorRef<const ast::Parameter*> p,
const ast::Type* ret_ty,
- ast::AttributeList ret_attrs);
+ utils::VectorRef<const ast::Attribute*> ret_attrs);
/// Destructor
~FunctionHeader();
/// Assignment operator
@@ -247,11 +261,11 @@ class ParserImpl {
/// Function name
std::string name;
/// Function parameters
- ast::VariableList params;
+ utils::Vector<const ast::Parameter*, 8> params;
/// Function return type
const ast::Type* return_type = nullptr;
/// Function return type attributes
- ast::AttributeList return_type_attributes;
+ AttributeList return_type_attributes;
};
/// VarDeclInfo contains the parsed information for variable declaration.
@@ -300,6 +314,10 @@ class ParserImpl {
explicit ParserImpl(Source::File const* file);
~ParserImpl();
+ /// Reads tokens from the source file. This will be called automatically
+ /// by |parse|.
+ void InitializeLex();
+
/// Run the parser
/// @returns true if the parse was successful, false otherwise.
bool Parse();
@@ -330,19 +348,19 @@ class ParserImpl {
ProgramBuilder& builder() { return builder_; }
/// @returns the next token
- Token next();
+ const Token& next();
/// Peeks ahead and returns the token at `idx` ahead of the current position
/// @param idx the index of the token to return
/// @returns the token `idx` positions ahead without advancing
- Token peek(size_t idx = 0);
+ const Token& peek(size_t idx = 0);
/// Peeks ahead and returns true if the token at `idx` ahead of the current
/// position is |tok|
/// @param idx the index of the token to return
/// @param tok the token to look for
/// @returns true if the token `idx` positions ahead is |tok|
bool peek_is(Token::Type tok, size_t idx = 0);
- /// @returns the last token that was returned by `next()`
- Token last_token() const;
+ /// @returns the last source location that was returned by `next()`
+ Source last_source() const;
/// Appends an error at `t` with the message `msg`
/// @param t the token to associate the error with
/// @param msg the error message
@@ -371,82 +389,94 @@ class ParserImpl {
void deprecated(const Source& source, const std::string& msg);
/// Parses the `translation_unit` grammar element
void translation_unit();
+ /// Parses the `global_directive` grammar element, erroring on parse failure.
+ /// @param has_parsed_decl flag indicating if the parser has consumed a global declaration.
+ /// @return true on parse success, otherwise an error or no-match.
+ Maybe<Void> global_directive(bool has_parsed_decl);
/// Parses the `enable_directive` grammar element, erroring on parse failure.
/// @return true on parse success, otherwise an error or no-match.
- Maybe<bool> enable_directive();
+ Maybe<Void> enable_directive();
/// Parses the `global_decl` grammar element, erroring on parse failure.
/// @return true on parse success, otherwise an error or no-match.
- Maybe<bool> global_decl();
+ Maybe<Void> global_decl();
/// Parses a `global_variable_decl` grammar element with the initial
/// `variable_attribute_list*` provided as `attrs`
/// @returns the variable parsed or nullptr
- /// @param attrs the list of attributes for the variable declaration.
- Maybe<const ast::Variable*> global_variable_decl(ast::AttributeList& attrs);
+ /// @param attrs the list of attributes for the variable declaration. If attributes are consumed
+ /// by the declaration, then this vector is cleared before returning.
+ Maybe<const ast::Variable*> global_variable_decl(AttributeList& attrs);
/// Parses a `global_constant_decl` grammar element with the initial
/// `variable_attribute_list*` provided as `attrs`
/// @returns the const object or nullptr
- /// @param attrs the list of attributes for the constant declaration.
- Maybe<const ast::Variable*> global_constant_decl(ast::AttributeList& attrs);
+ /// @param attrs the list of attributes for the constant declaration. If attributes are consumed
+ /// by the declaration, then this vector is cleared before returning.
+ Maybe<const ast::Variable*> global_constant_decl(AttributeList& attrs);
/// Parses a `variable_decl` grammar element
- /// @param allow_inferred if true, do not fail if variable decl does not
- /// specify type
/// @returns the parsed variable declaration info
- Maybe<VarDeclInfo> variable_decl(bool allow_inferred = false);
- /// Parses a `variable_ident_decl` grammar element, erroring on parse
- /// failure.
+ Maybe<VarDeclInfo> variable_decl();
+ /// Helper for parsing ident with an optional type declaration. Should not be called directly,
+ /// use the specific version below.
+ /// @param use a description of what was being parsed if an error was raised.
+ /// @param allow_inferred allow the identifier to be parsed without a type
+ /// @returns the parsed identifier, and possibly type, or empty otherwise
+ Expect<TypedIdentifier> expect_ident_with_optional_type_decl(std::string_view use,
+ bool allow_inferred);
+ /// Parses a `ident` or a `variable_ident_decl` grammar element, erroring on parse failure.
+ /// @param use a description of what was being parsed if an error was raised.
+ /// @returns the identifier or empty otherwise.
+ Expect<TypedIdentifier> expect_optionally_typed_ident(std::string_view use);
+ /// Parses a `variable_ident_decl` grammar element, erroring on parse failure.
/// @param use a description of what was being parsed if an error was raised.
- /// @param allow_inferred if true, do not fail if variable decl does not
- /// specify type
/// @returns the identifier and type parsed or empty otherwise
- Expect<TypedIdentifier> expect_variable_ident_decl(std::string_view use,
- bool allow_inferred = false);
+ Expect<TypedIdentifier> expect_ident_with_type_decl(std::string_view use);
/// Parses a `variable_qualifier` grammar element
/// @returns the variable qualifier information
Maybe<VariableQualifier> variable_qualifier();
- /// Parses a `type_alias` grammar element
+ /// Parses a `type_alias_decl` grammar element
/// @returns the type alias or nullptr on error
- Maybe<const ast::Alias*> type_alias();
+ Maybe<const ast::Alias*> type_alias_decl();
/// Parses a `type_decl` grammar element
/// @returns the parsed Type or nullptr if none matched.
Maybe<const ast::Type*> type_decl();
- /// Parses a `storage_class` grammar element, erroring on parse failure.
+ /// Parses an `address_space` grammar element, erroring on parse failure.
/// @param use a description of what was being parsed if an error was raised.
- /// @returns the storage class or StorageClass::kNone if none matched
- Expect<ast::StorageClass> expect_storage_class(std::string_view use);
+ /// @returns the address space or StorageClass::kNone if none matched
+ Expect<ast::StorageClass> expect_address_space(std::string_view use);
/// Parses a `struct_decl` grammar element.
/// @returns the struct type or nullptr on error
Maybe<const ast::Struct*> struct_decl();
/// Parses a `struct_body_decl` grammar element, erroring on parse failure.
/// @returns the struct members
- Expect<ast::StructMemberList> expect_struct_body_decl();
+ Expect<StructMemberList> expect_struct_body_decl();
/// Parses a `struct_member` grammar element, erroring on parse failure.
/// @returns the struct member or nullptr
Expect<ast::StructMember*> expect_struct_member();
/// Parses a `function_decl` grammar element with the initial
/// `function_attribute_decl*` provided as `attrs`.
- /// @param attrs the list of attributes for the function declaration.
+ /// @param attrs the list of attributes for the function declaration. If attributes are consumed
+ /// by the declaration, then this vector is cleared before returning.
/// @returns the parsed function, nullptr otherwise
- Maybe<const ast::Function*> function_decl(ast::AttributeList& attrs);
- /// Parses a `texture_samplers` grammar element
+ Maybe<const ast::Function*> function_decl(AttributeList& attrs);
+ /// Parses a `texture_and_sampler_types` grammar element
/// @returns the parsed Type or nullptr if none matched.
- Maybe<const ast::Type*> texture_samplers();
- /// Parses a `sampler` grammar element
+ Maybe<const ast::Type*> texture_and_sampler_types();
+ /// Parses a `sampler_type` grammar element
/// @returns the parsed Type or nullptr if none matched.
- Maybe<const ast::Type*> sampler();
- /// Parses a `multisampled_texture` grammar element
+ Maybe<const ast::Type*> sampler_type();
+ /// Parses a `multisampled_texture_type` grammar element
/// @returns returns the multisample texture dimension or kNone if none
/// matched.
- Maybe<const ast::TextureDimension> multisampled_texture();
- /// Parses a `sampled_texture` grammar element
+ Maybe<const ast::TextureDimension> multisampled_texture_type();
+ /// Parses a `sampled_texture_type` grammar element
/// @returns returns the sample texture dimension or kNone if none matched.
- Maybe<const ast::TextureDimension> sampled_texture();
- /// Parses a `storage_texture` grammar element
+ Maybe<const ast::TextureDimension> sampled_texture_type();
+ /// Parses a `storage_texture_type` grammar element
/// @returns returns the storage texture dimension.
/// Returns kNone if none matched.
- Maybe<const ast::TextureDimension> storage_texture();
- /// Parses a `depth_texture` grammar element
+ Maybe<const ast::TextureDimension> storage_texture_type();
+ /// Parses a `depth_texture_type` grammar element
/// @returns the parsed Type or nullptr if none matched.
- Maybe<const ast::Type*> depth_texture();
+ Maybe<const ast::Type*> depth_texture_type();
/// Parses a 'texture_external_type' grammar element
/// @returns the parsed Type or nullptr if none matched
Maybe<const ast::Type*> external_texture();
@@ -454,15 +484,18 @@ class ParserImpl {
/// @param use a description of what was being parsed if an error was raised
/// @returns returns the texel format or kNone if none matched.
Expect<ast::TexelFormat> expect_texel_format(std::string_view use);
+ /// Parses a `static_assert_statement` grammar element
+ /// @returns returns the static assert, if it matched.
+ Maybe<const ast::StaticAssert*> static_assert_statement();
/// Parses a `function_header` grammar element
/// @returns the parsed function header
Maybe<FunctionHeader> function_header();
/// Parses a `param_list` grammar element, erroring on parse failure.
/// @returns the parsed variables
- Expect<ast::VariableList> expect_param_list();
+ Expect<ParameterList> expect_param_list();
/// Parses a `param` grammar element, erroring on parse failure.
/// @returns the parsed variable
- Expect<ast::Variable*> expect_param();
+ Expect<ast::Parameter*> expect_param();
/// Parses a `pipeline_stage` grammar element, erroring if the next token does
/// not match a stage name.
/// @returns the pipeline stage.
@@ -471,71 +504,85 @@ class ParserImpl {
/// match a valid access control.
/// @param use a description of what was being parsed if an error was raised
/// @returns the parsed access control.
- Expect<ast::Access> expect_access(std::string_view use);
+ Expect<ast::Access> expect_access_mode(std::string_view use);
+ /// Parses an interpolation sample name identifier, erroring if the next token does not match a
+ /// valid sample name.
+ /// @returns the parsed sample name.
+ Expect<ast::InterpolationSampling> expect_interpolation_sample_name();
+ /// Parses an interpolation type name identifier, erroring if the next token does not match a
+ /// value type name.
+ /// @returns the parsed type name
+ Expect<ast::InterpolationType> expect_interpolation_type_name();
/// Parses a builtin identifier, erroring if the next token does not match a
/// valid builtin name.
/// @returns the parsed builtin.
- Expect<ast::Builtin> expect_builtin();
- /// Parses a `body_stmt` grammar element, erroring on parse failure.
+ Expect<ast::BuiltinValue> expect_builtin();
+ /// Parses a `compound_statement` grammar element, erroring on parse failure.
/// @returns the parsed statements
- Expect<ast::BlockStatement*> expect_body_stmt();
- /// Parses a `paren_rhs_stmt` grammar element, erroring on parse failure.
+ Expect<ast::BlockStatement*> expect_compound_statement();
+ /// Parses a `paren_expression` grammar element, erroring on parse failure.
/// @returns the parsed element or nullptr
- Expect<const ast::Expression*> expect_paren_rhs_stmt();
+ Expect<const ast::Expression*> expect_paren_expression();
/// Parses a `statements` grammar element
/// @returns the statements parsed
- Expect<ast::StatementList> expect_statements();
+ Expect<StatementList> expect_statements();
/// Parses a `statement` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::Statement*> statement();
- /// Parses a `break_stmt` grammar element
+ /// Parses a `break_statement` grammar element
/// @returns the parsed statement or nullptr
- Maybe<const ast::BreakStatement*> break_stmt();
- /// Parses a `return_stmt` grammar element
+ Maybe<const ast::BreakStatement*> break_statement();
+ /// Parses a `return_statement` grammar element
/// @returns the parsed statement or nullptr
- Maybe<const ast::ReturnStatement*> return_stmt();
- /// Parses a `continue_stmt` grammar element
+ Maybe<const ast::ReturnStatement*> return_statement();
+ /// Parses a `continue_statement` grammar element
/// @returns the parsed statement or nullptr
- Maybe<const ast::ContinueStatement*> continue_stmt();
- /// Parses a `variable_stmt` grammar element
+ Maybe<const ast::ContinueStatement*> continue_statement();
+ /// Parses a `variable_statement` grammar element
/// @returns the parsed variable or nullptr
- Maybe<const ast::VariableDeclStatement*> variable_stmt();
- /// Parses a `if_stmt` grammar element
+ Maybe<const ast::VariableDeclStatement*> variable_statement();
+ /// Parses a `if_statement` grammar element
/// @returns the parsed statement or nullptr
- Maybe<const ast::IfStatement*> if_stmt();
- /// Parses a `switch_stmt` grammar element
+ Maybe<const ast::IfStatement*> if_statement();
+ /// Parses a `switch_statement` grammar element
/// @returns the parsed statement or nullptr
- Maybe<const ast::SwitchStatement*> switch_stmt();
+ Maybe<const ast::SwitchStatement*> switch_statement();
/// Parses a `switch_body` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::CaseStatement*> switch_body();
/// Parses a `case_selectors` grammar element
/// @returns the list of literals
- Expect<ast::CaseSelectorList> expect_case_selectors();
+ Expect<CaseSelectorList> expect_case_selectors();
/// Parses a `case_body` grammar element
/// @returns the parsed statements
Maybe<const ast::BlockStatement*> case_body();
- /// Parses a `func_call_stmt` grammar element
+ /// Parses a `func_call_statement` grammar element
/// @returns the parsed function call or nullptr
- Maybe<const ast::CallStatement*> func_call_stmt();
- /// Parses a `loop_stmt` grammar element
+ Maybe<const ast::CallStatement*> func_call_statement();
+ /// Parses a `loop_statement` grammar element
/// @returns the parsed loop or nullptr
- Maybe<const ast::LoopStatement*> loop_stmt();
+ Maybe<const ast::LoopStatement*> loop_statement();
/// Parses a `for_header` grammar element, erroring on parse failure.
/// @returns the parsed for header or nullptr
Expect<std::unique_ptr<ForHeader>> expect_for_header();
- /// Parses a `for_stmt` grammar element
+ /// Parses a `for_statement` grammar element
/// @returns the parsed for loop or nullptr
- Maybe<const ast::ForLoopStatement*> for_stmt();
- /// Parses a `continuing_stmt` grammar element
+ Maybe<const ast::ForLoopStatement*> for_statement();
+ /// Parses a `while_statement` grammar element
+ /// @returns the parsed while loop or nullptr
+ Maybe<const ast::WhileStatement*> while_statement();
+ /// Parses a `break_if_statement` grammar element
+ /// @returns the parsed statement or nullptr
+ Maybe<const ast::Statement*> break_if_statement();
+ /// Parses a `continuing_compound_statement` grammar element
+ /// @returns the parsed statements
+ Maybe<const ast::BlockStatement*> continuing_compound_statement();
+ /// Parses a `continuing_statement` grammar element
/// @returns the parsed statements
- Maybe<const ast::BlockStatement*> continuing_stmt();
+ Maybe<const ast::BlockStatement*> continuing_statement();
/// Parses a `const_literal` grammar element
/// @returns the const literal parsed or nullptr if none found
Maybe<const ast::LiteralExpression*> const_literal();
- /// Parses a `const_expr` grammar element, erroring on parse failure.
- /// @returns the parsed constructor expression or nullptr on error
- Expect<const ast::Expression*> expect_const_expr();
/// Parses a `primary_expression` grammar element
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> primary_expression();
@@ -543,7 +590,7 @@ class ParserImpl {
/// failure.
/// @param use a description of what was being parsed if an error was raised
/// @returns the list of arguments
- Expect<ast::ExpressionList> expect_argument_expression_list(std::string_view use);
+ Expect<ExpressionList> expect_argument_expression_list(std::string_view use);
/// Parses the recursive portion of the postfix_expression
/// @param prefix the left side of the expression
/// @returns the parsed expression or nullptr
@@ -594,6 +641,11 @@ class ParserImpl {
/// Parses the `equality_expression` grammar element
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> equality_expression();
+ /// Parses the `bitwise_expression.post.unary_expression` grammar element
+ /// @param lhs the left side of the expression
+ /// @returns the parsed expression or nullptr
+ Maybe<const ast::Expression*> bitwise_expression_post_unary_expression(
+ const ast::Expression* lhs);
/// Parses the recursive part of the `and_expression`, erroring on parse
/// failure.
/// @param lhs the left side of the expression
@@ -634,15 +686,24 @@ class ParserImpl {
/// Parses a `logical_or_expression` grammar element
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> logical_or_expression();
+ /// Parses an `expression` grammar element
+ /// @returns the parsed expression or nullptr
+ Maybe<const ast::Expression*> expression();
/// Parses a `compound_assignment_operator` grammar element
/// @returns the parsed compound assignment operator
Maybe<ast::BinaryOp> compound_assignment_operator();
- /// Parses a `assignment_stmt` grammar element
+ /// Parses a `core_lhs_expression` grammar element
+ /// @returns the parsed expression or a non-kMatched failure
+ Maybe<const ast::Expression*> core_lhs_expression();
+ /// Parses a `lhs_expression` grammar element
+ /// @returns the parsed expression or a non-kMatched failure
+ Maybe<const ast::Expression*> lhs_expression();
+ /// Parses a `variable_updating_statement` grammar element
/// @returns the parsed assignment or nullptr
- Maybe<const ast::Statement*> assignment_stmt();
+ Maybe<const ast::Statement*> variable_updating_statement();
/// Parses one or more attribute lists.
/// @return the parsed attribute list, or an empty list on error.
- Maybe<ast::AttributeList> attribute_list();
+ Maybe<AttributeList> attribute_list();
/// Parses a single attribute of the following types:
/// * `struct_attribute`
/// * `struct_member_attribute`
@@ -813,13 +874,13 @@ class ParserImpl {
/// Reports an error if the attribute list `list` is not empty.
/// Used to ensure that all attributes are consumed.
- bool expect_attributes_consumed(ast::AttributeList& list);
+ bool expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> list);
- Expect<const ast::Type*> expect_type_decl_pointer(Token t);
- Expect<const ast::Type*> expect_type_decl_atomic(Token t);
- Expect<const ast::Type*> expect_type_decl_vector(Token t);
- Expect<const ast::Type*> expect_type_decl_array(Token t);
- Expect<const ast::Type*> expect_type_decl_matrix(Token t);
+ Expect<const ast::Type*> expect_type_decl_pointer(const Token& t);
+ Expect<const ast::Type*> expect_type_decl_atomic(const Token& t);
+ Expect<const ast::Type*> expect_type_decl_vector(const Token& t);
+ Expect<const ast::Type*> expect_type_decl_array(const Token& t);
+ Expect<const ast::Type*> expect_type_decl_matrix(const Token& t);
Expect<const ast::Type*> expect_type(std::string_view use);
@@ -827,6 +888,8 @@ class ParserImpl {
Maybe<const ast::Statement*> for_header_initializer();
Maybe<const ast::Statement*> for_header_continuing();
+ void split_token(Token::Type lhs, Token::Type rhs);
+
class MultiTokenSource;
MultiTokenSource make_source_range();
MultiTokenSource make_source_range_from(const Source& start);
@@ -840,9 +903,10 @@ class ParserImpl {
return builder_.create<T>(std::forward<ARGS>(args)...);
}
- std::unique_ptr<Lexer> lexer_;
- std::deque<Token> token_queue_;
- Token last_token_;
+ Source::File const* const file_;
+ std::vector<Token> tokens_;
+ size_t next_token_idx_ = 0;
+ size_t last_source_idx_ = 0;
bool synchronized_ = true;
uint32_t parse_depth_ = 0;
std::vector<Token::Type> sync_tokens_;
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc
index 3042c201df8..7f1132ced7d 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc
@@ -23,7 +23,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_Parses) {
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- ASSERT_EQ(e.value.size(), 1u);
+ ASSERT_EQ(e.value.Length(), 1u);
ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
}
@@ -33,7 +33,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_ParsesEmptyList) {
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- ASSERT_EQ(e.value.size(), 0u);
+ ASSERT_EQ(e.value.Length(), 0u);
}
TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
@@ -42,7 +42,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- ASSERT_EQ(e.value.size(), 3u);
+ ASSERT_EQ(e.value.Length(), 3u);
ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
ASSERT_TRUE(e.value[2]->Is<ast::BinaryExpression>());
@@ -54,7 +54,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_TrailingComma) {
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- ASSERT_EQ(e.value.size(), 2u);
+ ASSERT_EQ(e.value.Length(), 2u);
ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc
index 4fd23ce08fa..1f2b19166d2 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
auto p = parser("a = 123");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -42,7 +42,7 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
auto p = parser("a.b.c[2].d = 123");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -92,7 +92,7 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToPhony) {
auto p = parser("_ = 123i");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -111,9 +111,47 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToPhony) {
ASSERT_TRUE(a->lhs->Is<ast::PhonyExpression>());
}
-TEST_F(ParserImplTest, AssignmentStmt_Parses_CompoundOp) {
- auto p = parser("a += 123u");
- auto e = p->assignment_stmt();
+TEST_F(ParserImplTest, AssignmentStmt_Phony_CompoundOpFails) {
+ auto p = parser("_ += 123i");
+ auto e = p->variable_updating_statement();
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:3: expected '=' for assignment");
+}
+
+TEST_F(ParserImplTest, AssignmentStmt_Phony_IncrementFails) {
+ auto p = parser("_ ++");
+ auto e = p->variable_updating_statement();
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:3: expected '=' for assignment");
+}
+
+TEST_F(ParserImplTest, AssignmentStmt_Phony_EqualIncrementFails) {
+ auto p = parser("_ = ++");
+ auto e = p->variable_updating_statement();
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_EQ(
+ p->error(),
+ "1:5: prefix increment and decrement operators are reserved for a future WGSL version");
+}
+
+struct CompoundData {
+ std::string str;
+ ast::BinaryOp op;
+};
+using CompoundOpTest = ParserImplTestWithParam<CompoundData>;
+TEST_P(CompoundOpTest, CompoundOp) {
+ auto params = GetParam();
+ auto p = parser("a " + params.str + " 123u");
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -123,7 +161,7 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_CompoundOp) {
ASSERT_NE(a, nullptr);
ASSERT_NE(a->lhs, nullptr);
ASSERT_NE(a->rhs, nullptr);
- EXPECT_EQ(a->op, ast::BinaryOp::kAdd);
+ EXPECT_EQ(a->op, params.op);
ASSERT_TRUE(a->lhs->Is<ast::IdentifierExpression>());
auto* ident = a->lhs->As<ast::IdentifierExpression>();
@@ -134,10 +172,22 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_CompoundOp) {
EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->suffix,
ast::IntLiteralExpression::Suffix::kU);
}
+INSTANTIATE_TEST_SUITE_P(ParserImplTest,
+ CompoundOpTest,
+ testing::Values(CompoundData{"+=", ast::BinaryOp::kAdd},
+ CompoundData{"-=", ast::BinaryOp::kSubtract},
+ CompoundData{"*=", ast::BinaryOp::kMultiply},
+ CompoundData{"/=", ast::BinaryOp::kDivide},
+ CompoundData{"%=", ast::BinaryOp::kModulo},
+ CompoundData{"&=", ast::BinaryOp::kAnd},
+ CompoundData{"|=", ast::BinaryOp::kOr},
+ CompoundData{"^=", ast::BinaryOp::kXor},
+ CompoundData{">>=", ast::BinaryOp::kShiftRight},
+ CompoundData{"<<=", ast::BinaryOp::kShiftLeft}));
TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) {
auto p = parser("a.b.c[2].d 123");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
@@ -147,7 +197,7 @@ TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) {
TEST_F(ParserImplTest, AssignmentStmt_Compound_MissingEqual) {
auto p = parser("a + 123");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
@@ -157,7 +207,7 @@ TEST_F(ParserImplTest, AssignmentStmt_Compound_MissingEqual) {
TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) {
auto p = parser("if (true) {} = 123");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_FALSE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -166,7 +216,7 @@ TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) {
TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) {
auto p = parser("a.b.c[2].d = if (true) {}");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -176,7 +226,7 @@ TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) {
TEST_F(ParserImplTest, AssignmentStmt_InvalidCompoundOp) {
auto p = parser("a &&= true");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_bitwise_expression_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_bitwise_expression_test.cc
new file mode 100644
index 00000000000..a5f675ca492
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_bitwise_expression_test.cc
@@ -0,0 +1,345 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, BitwiseExpr_NoOp) {
+ auto p = parser("a true");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_EQ(e.value, nullptr);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Or_Parses) {
+ auto p = parser("a | true");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e.value, nullptr);
+
+ EXPECT_EQ(e->source.range.begin.line, 1u);
+ EXPECT_EQ(e->source.range.begin.column, 3u);
+ EXPECT_EQ(e->source.range.end.line, 1u);
+ EXPECT_EQ(e->source.range.end.column, 4u);
+
+ ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+ auto* rel = e->As<ast::BinaryExpression>();
+ EXPECT_EQ(ast::BinaryOp::kOr, rel->op);
+
+ ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+ auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+
+ ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+ ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Or_Parses_Multiple) {
+ auto p = parser("a | true | b");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e.value, nullptr);
+
+ // lhs: (a | true)
+ // rhs: b
+
+ ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+ auto* rel = e->As<ast::BinaryExpression>();
+ EXPECT_EQ(ast::BinaryOp::kOr, rel->op);
+
+ ASSERT_TRUE(rel->rhs->Is<ast::IdentifierExpression>());
+ auto* ident = rel->rhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b"));
+
+ ASSERT_TRUE(rel->lhs->Is<ast::BinaryExpression>());
+
+ // lhs: a
+ // rhs: true
+ rel = rel->lhs->As<ast::BinaryExpression>();
+
+ ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+ ident = rel->lhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+
+ ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+ ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Or_MixedWithAnd_Invalid) {
+ auto p = parser("a | b & c");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: mixing '|' and '&' requires parenthesis");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Or_MixedWithXor_Invalid) {
+ auto p = parser("a | b ^ c");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: mixing '|' and '^' requires parenthesis");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Or_InvalidRHS) {
+ auto p = parser("true | if (a) {}");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:8: unable to parse right side of | expression");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Xor_Parses) {
+ auto p = parser("a ^ true");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e.value, nullptr);
+
+ EXPECT_EQ(e->source.range.begin.line, 1u);
+ EXPECT_EQ(e->source.range.begin.column, 3u);
+ EXPECT_EQ(e->source.range.end.line, 1u);
+ EXPECT_EQ(e->source.range.end.column, 4u);
+
+ ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+ auto* rel = e->As<ast::BinaryExpression>();
+ EXPECT_EQ(ast::BinaryOp::kXor, rel->op);
+
+ ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+ auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+
+ ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+ ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Xor_Parses_Multiple) {
+ auto p = parser("a ^ true ^ b");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e.value, nullptr);
+
+ // lhs: (a ^ true)
+ // rhs: b
+ ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+ auto* rel = e->As<ast::BinaryExpression>();
+ EXPECT_EQ(ast::BinaryOp::kXor, rel->op);
+
+ ASSERT_TRUE(rel->rhs->Is<ast::IdentifierExpression>());
+ auto* ident = rel->rhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b"));
+
+ ASSERT_TRUE(rel->lhs->Is<ast::BinaryExpression>());
+
+ // lhs: a
+ // rhs: true
+ rel = rel->lhs->As<ast::BinaryExpression>();
+
+ ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+ ident = rel->lhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+
+ ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+ ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Xor_MixedWithOr_Invalid) {
+ auto p = parser("a ^ b | c");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: mixing '^' and '|' requires parenthesis");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Xor_MixedWithAnd_Invalid) {
+ auto p = parser("a ^ b & c");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: mixing '^' and '&' requires parenthesis");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_Xor_InvalidRHS) {
+ auto p = parser("true ^ if (a) {}");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:8: unable to parse right side of ^ expression");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_And_Parses) {
+ auto p = parser("a & true");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e.value, nullptr);
+
+ EXPECT_EQ(e->source.range.begin.line, 1u);
+ EXPECT_EQ(e->source.range.begin.column, 3u);
+ EXPECT_EQ(e->source.range.end.line, 1u);
+ EXPECT_EQ(e->source.range.end.column, 4u);
+
+ ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+ auto* rel = e->As<ast::BinaryExpression>();
+ EXPECT_EQ(ast::BinaryOp::kAnd, rel->op);
+
+ ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+ auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+
+ ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+ ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_And_Parses_Multiple) {
+ auto p = parser("a & true & b");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e.value, nullptr);
+
+ // lhs: (a & true)
+ // rhs: b
+ ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+ auto* rel = e->As<ast::BinaryExpression>();
+ EXPECT_EQ(ast::BinaryOp::kAnd, rel->op);
+
+ ASSERT_TRUE(rel->rhs->Is<ast::IdentifierExpression>());
+ auto* ident = rel->rhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("b"));
+
+ ASSERT_TRUE(rel->lhs->Is<ast::BinaryExpression>());
+
+ // lhs: a
+ // rhs: true
+ rel = rel->lhs->As<ast::BinaryExpression>();
+
+ ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+ ident = rel->lhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+
+ ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+ ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_And_Parses_AndAnd) {
+ auto p = parser("a & true &&b");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e.value, nullptr);
+
+ // lhs: (a & true)
+ // rhs: &b
+ ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+ auto* rel = e->As<ast::BinaryExpression>();
+ EXPECT_EQ(ast::BinaryOp::kAnd, rel->op);
+
+ ASSERT_TRUE(rel->rhs->Is<ast::UnaryOpExpression>());
+ auto* unary = rel->rhs->As<ast::UnaryOpExpression>();
+ EXPECT_EQ(ast::UnaryOp::kAddressOf, unary->op);
+
+ ASSERT_TRUE(unary->expr->Is<ast::IdentifierExpression>());
+ auto* ident = unary->expr->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("b"));
+
+ ASSERT_TRUE(rel->lhs->Is<ast::BinaryExpression>());
+
+ // lhs: a
+ // rhs: true
+ rel = rel->lhs->As<ast::BinaryExpression>();
+
+ ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+ ident = rel->lhs->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+
+ ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+ ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_And_MixedWithOr_Invalid) {
+ auto p = parser("a & b | c");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: mixing '&' and '|' requires parenthesis");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_And_MixedWithXor_Invalid) {
+ auto p = parser("a & b ^ c");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: mixing '&' and '^' requires parenthesis");
+}
+
+TEST_F(ParserImplTest, BitwiseExpr_And_InvalidRHS) {
+ auto p = parser("true & if (a) {}");
+ auto lhs = p->unary_expression();
+ auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:8: unable to parse right side of & expression");
+}
+
+} // namespace
+} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc
index ca8802a3711..21c526767a5 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc
@@ -20,7 +20,7 @@ namespace {
TEST_F(ParserImplTest, BreakStmt) {
auto p = parser("break");
- auto e = p->break_stmt();
+ auto e = p->break_statement();
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc
index d044f8da00e..59aeb3cb570 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc
@@ -36,7 +36,7 @@ TEST_F(ParserImplTest, Statement_Call) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
- EXPECT_EQ(c->args.size(), 0u);
+ EXPECT_EQ(c->args.Length(), 0u);
}
TEST_F(ParserImplTest, Statement_Call_WithParams) {
@@ -52,7 +52,7 @@ TEST_F(ParserImplTest, Statement_Call_WithParams) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
- EXPECT_EQ(c->args.size(), 3u);
+ EXPECT_EQ(c->args.Length(), 3u);
EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
@@ -71,7 +71,7 @@ TEST_F(ParserImplTest, Statement_Call_WithParams_TrailingComma) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
- EXPECT_EQ(c->args.size(), 2u);
+ EXPECT_EQ(c->args.Length(), 2u);
EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_case_body_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_case_body_test.cc
index f8c07a329ec..c162be33106 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_case_body_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_case_body_test.cc
@@ -24,7 +24,7 @@ TEST_F(ParserImplTest, CaseBody_Empty) {
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(e.errored);
EXPECT_TRUE(e.matched);
- EXPECT_EQ(e->statements.size(), 0u);
+ EXPECT_EQ(e->statements.Length(), 0u);
}
TEST_F(ParserImplTest, CaseBody_Statements) {
@@ -36,7 +36,7 @@ TEST_F(ParserImplTest, CaseBody_Statements) {
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(e.errored);
EXPECT_TRUE(e.matched);
- ASSERT_EQ(e->statements.size(), 2u);
+ ASSERT_EQ(e->statements.Length(), 2u);
EXPECT_TRUE(e->statements[0]->Is<ast::VariableDeclStatement>());
EXPECT_TRUE(e->statements[1]->Is<ast::AssignmentStatement>());
}
@@ -56,7 +56,7 @@ TEST_F(ParserImplTest, CaseBody_Fallthrough) {
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(e.errored);
EXPECT_TRUE(e.matched);
- ASSERT_EQ(e->statements.size(), 1u);
+ ASSERT_EQ(e->statements.Length(), 1u);
EXPECT_TRUE(e->statements[0]->Is<ast::FallthroughStatement>());
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_body_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc
index f84a5ba6c37..947cb481c7f 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_body_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc
@@ -18,38 +18,38 @@
namespace tint::reader::wgsl {
namespace {
-TEST_F(ParserImplTest, BodyStmt) {
+TEST_F(ParserImplTest, CompoundStmt) {
auto p = parser(R"({
discard;
return 1 + b / 2;
})");
- auto e = p->expect_body_stmt();
+ auto e = p->expect_compound_statement();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- ASSERT_EQ(e->statements.size(), 2u);
+ ASSERT_EQ(e->statements.Length(), 2u);
EXPECT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
EXPECT_TRUE(e->statements[1]->Is<ast::ReturnStatement>());
}
-TEST_F(ParserImplTest, BodyStmt_Empty) {
+TEST_F(ParserImplTest, CompoundStmt_Empty) {
auto p = parser("{}");
- auto e = p->expect_body_stmt();
+ auto e = p->expect_compound_statement();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- EXPECT_EQ(e->statements.size(), 0u);
+ EXPECT_EQ(e->statements.Length(), 0u);
}
-TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {
+TEST_F(ParserImplTest, CompoundStmt_InvalidStmt) {
auto p = parser("{fn main() {}}");
- auto e = p->expect_body_stmt();
+ auto e = p->expect_compound_statement();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:2: expected '}'");
}
-TEST_F(ParserImplTest, BodyStmt_MissingRightParen) {
+TEST_F(ParserImplTest, CompoundStmt_MissingRightParen) {
auto p = parser("{return;");
- auto e = p->expect_body_stmt();
+ auto e = p->expect_compound_statement();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:9: expected '}'");
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_expr_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_expr_test.cc
deleted file mode 100644
index 80536bd6e6a..00000000000
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_expr_test.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
- auto p = parser("vec2<f32>(1., 2.)");
- auto e = p->expect_const_expr();
- ASSERT_FALSE(p->has_error()) << p->error();
- ASSERT_FALSE(e.errored);
- ASSERT_TRUE(e->Is<ast::CallExpression>());
-
- auto* t = e->As<ast::CallExpression>();
- ASSERT_TRUE(t->target.type->Is<ast::Vector>());
- EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
-
- ASSERT_EQ(t->args.size(), 2u);
-
- ASSERT_TRUE(t->args[0]->Is<ast::FloatLiteralExpression>());
- EXPECT_DOUBLE_EQ(t->args[0]->As<ast::FloatLiteralExpression>()->value, 1.);
- EXPECT_EQ(t->args[0]->As<ast::FloatLiteralExpression>()->suffix,
- ast::FloatLiteralExpression::Suffix::kNone);
-
- ASSERT_TRUE(t->args[1]->Is<ast::FloatLiteralExpression>());
- EXPECT_DOUBLE_EQ(t->args[1]->As<ast::FloatLiteralExpression>()->value, 2.);
- EXPECT_EQ(t->args[1]->As<ast::FloatLiteralExpression>()->suffix,
- ast::FloatLiteralExpression::Suffix::kNone);
-}
-
-TEST_F(ParserImplTest, ConstExpr_TypeDecl_Empty) {
- auto p = parser("vec2<f32>()");
- auto e = p->expect_const_expr();
- ASSERT_FALSE(p->has_error()) << p->error();
- ASSERT_FALSE(e.errored);
- ASSERT_TRUE(e->Is<ast::CallExpression>());
-
- auto* t = e->As<ast::CallExpression>();
- ASSERT_TRUE(t->target.type->Is<ast::Vector>());
- EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
-
- ASSERT_EQ(t->args.size(), 0u);
-}
-
-TEST_F(ParserImplTest, ConstExpr_TypeDecl_TrailingComma) {
- auto p = parser("vec2<f32>(1., 2.,)");
- auto e = p->expect_const_expr();
- ASSERT_FALSE(p->has_error()) << p->error();
- ASSERT_FALSE(e.errored);
- ASSERT_TRUE(e->Is<ast::CallExpression>());
-
- auto* t = e->As<ast::CallExpression>();
- ASSERT_TRUE(t->target.type->Is<ast::Vector>());
- EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
-
- ASSERT_EQ(t->args.size(), 2u);
- ASSERT_TRUE(t->args[0]->Is<ast::LiteralExpression>());
- ASSERT_TRUE(t->args[1]->Is<ast::LiteralExpression>());
-}
-
-TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) {
- auto p = parser("vec2<f32>(1., 2.");
- auto e = p->expect_const_expr();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(e.errored);
- ASSERT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:17: expected ')' for type constructor");
-}
-
-TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingLeftParen) {
- auto p = parser("vec2<f32> 1., 2.)");
- auto e = p->expect_const_expr();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(e.errored);
- ASSERT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
-}
-
-TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) {
- auto p = parser("vec2<f32>(1. 2.");
- auto e = p->expect_const_expr();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(e.errored);
- ASSERT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:14: expected ')' for type constructor");
-}
-
-TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
- auto p = parser("vec2<f32>(1., if(a) {})");
- auto e = p->expect_const_expr();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(e.errored);
- ASSERT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
-}
-
-TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
- auto p = parser("true");
- auto e = p->expect_const_expr();
- ASSERT_FALSE(p->has_error()) << p->error();
- ASSERT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
- ASSERT_TRUE(e.value->Is<ast::BoolLiteralExpression>());
- EXPECT_TRUE(e.value->As<ast::BoolLiteralExpression>()->value);
-}
-
-TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
- auto p = parser("invalid");
- auto e = p->expect_const_expr();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(e.errored);
- ASSERT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:1: unable to parse const_expr");
-}
-
-TEST_F(ParserImplTest, ConstExpr_TypeConstructor) {
- auto p = parser("S(0)");
-
- auto e = p->expect_const_expr();
- ASSERT_FALSE(e.errored);
- ASSERT_TRUE(e->Is<ast::CallExpression>());
- ASSERT_NE(e->As<ast::CallExpression>()->target.type, nullptr);
- ASSERT_TRUE(e->As<ast::CallExpression>()->target.type->Is<ast::TypeName>());
- EXPECT_EQ(e->As<ast::CallExpression>()->target.type->As<ast::TypeName>()->name,
- p->builder().Symbols().Get("S"));
-}
-
-TEST_F(ParserImplTest, ConstExpr_Recursion) {
- std::stringstream out;
- for (size_t i = 0; i < 200; i++) {
- out << "f32(";
- }
- out << "1.0";
- for (size_t i = 0; i < 200; i++) {
- out << ")";
- }
- auto p = parser(out.str());
- auto e = p->expect_const_expr();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(e.errored);
- ASSERT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:517: maximum parser recursive depth reached");
-}
-
-TEST_F(ParserImplTest, UnaryOp_Recursion) {
- std::stringstream out;
- for (size_t i = 0; i < 200; i++) {
- out << "!";
- }
- out << "1.0";
- auto p = parser(out.str());
- auto e = p->unary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(e.errored);
- ASSERT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:130: maximum parser recursive depth reached");
-}
-
-} // namespace
-} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_literal_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
index b07ec1b66a5..16861e407eb 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
@@ -151,13 +151,18 @@ TEST_P(ParserImplFloatLiteralTest, Parse) {
ASSERT_NE(c.value, nullptr);
auto* literal = c->As<ast::FloatLiteralExpression>();
ASSERT_NE(literal, nullptr);
- EXPECT_DOUBLE_EQ(literal->value, params.expected)
+ // Use EXPECT_EQ instead of EXPECT_DOUBLE_EQ here, because EXPECT_DOUBLE_EQ use AlmostEquals(),
+ // which allows an error up to 4 ULPs.
+ EXPECT_EQ(literal->value, params.expected)
<< "\n"
<< "got: " << std::hexfloat << literal->value << "\n"
<< "expected: " << std::hexfloat << params.expected;
if (params.input.back() == 'f') {
EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
ast::FloatLiteralExpression::Suffix::kF);
+ } else if (params.input.back() == 'h') {
+ EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
+ ast::FloatLiteralExpression::Suffix::kH);
} else {
EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
ast::FloatLiteralExpression::Suffix::kNone);
@@ -181,6 +186,7 @@ INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_Float,
{"234.e12", 234.e12},
{"234.e12f", static_cast<double>(234.e12f)},
+ {"234.e2h", static_cast<double>(f16::Quantize(234.e2))},
// Tiny cases
{"1e-5000", 0.0},
@@ -189,6 +195,12 @@ INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_Float,
{"-1e-5000f", 0.0},
{"1e-50f", 0.0},
{"-1e-50f", 0.0},
+ {"1e-5000h", 0.0},
+ {"-1e-5000h", 0.0},
+ {"1e-50h", 0.0},
+ {"-1e-50h", 0.0},
+ {"1e-8h", 0.0}, // The smallest positive subnormal f16 is 5.96e-8
+ {"-1e-8h", 0.0},
// Nearly overflow
{"1.e308", 1.e308},
@@ -209,6 +221,16 @@ INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_Float,
{"-3.5e37f", static_cast<double>(-3.5e37f)},
{"3.403e37f", static_cast<double>(3.403e37f)},
{"-3.403e37f", static_cast<double>(-3.403e37f)},
+
+ // Nearly overflow
+ {"6e4h", 6e4},
+ {"-6e4h", -6e4},
+ {"8.0e3h", 8.0e3},
+ {"-8.0e3h", -8.0e3},
+ {"3.5e3h", 3.5e3},
+ {"-3.5e3h", -3.5e3},
+ {"3.403e3h", 3.402e3}, // Quantized
+ {"-3.403e3h", -3.402e3}, // Quantized
}));
const double NegInf = MakeDouble(1, 0x7FF, 0);
@@ -229,6 +251,10 @@ FloatLiteralTestCaseList HexFloatCases() {
{"-0x1p-1", -0x1p-1},
{"-0x1p-2", -0x1p-2},
{"-0x1.8p-1", -0x1.8p-1},
+ {"0x0.4p+1", 0x0.4p+1},
+ {"0x0.02p+3", 0x0.02p+3},
+ {"0x4.4p+1", 0x4.4p+1},
+ {"0x8c.02p+3", 0x8c.02p+3},
// Large numbers
{"0x1p+9", 0x1p+9},
@@ -257,6 +283,11 @@ FloatLiteralTestCaseList HexFloatCases() {
{"-0x1p-124f", -0x1p-124},
{"-0x1p-125f", -0x1p-125},
+ {"0x1p-12h", 0x1p-12},
+ {"0x1p-13h", 0x1p-13},
+ {"-0x1p-12h", -0x1p-12},
+ {"-0x1p-13h", -0x1p-13},
+
// Lowest non-denorm
{"0x1p-1022", 0x1p-1022},
{"-0x1p-1022", -0x1p-1022},
@@ -264,9 +295,14 @@ FloatLiteralTestCaseList HexFloatCases() {
{"0x1p-126f", 0x1p-126},
{"-0x1p-126f", -0x1p-126},
+ {"0x1p-14h", 0x1p-14},
+ {"-0x1p-14h", -0x1p-14},
+
// Denormalized values
{"0x1p-1023", 0x1p-1023},
+ {"0x0.8p-1022", 0x0.8p-1022},
{"0x1p-1024", 0x1p-1024},
+ {"0x0.2p-1021", 0x0.2p-1021},
{"0x1p-1025", 0x1p-1025},
{"0x1p-1026", 0x1p-1026},
{"-0x1p-1023", -0x1p-1023},
@@ -277,7 +313,9 @@ FloatLiteralTestCaseList HexFloatCases() {
{"0x1.8p-1024", 0x1.8p-1024},
{"0x1p-127f", 0x1p-127},
+ {"0x0.8p-126f", 0x0.8p-126},
{"0x1p-128f", 0x1p-128},
+ {"0x0.2p-125f", 0x0.2p-125},
{"0x1p-129f", 0x1p-129},
{"0x1p-130f", 0x1p-130},
{"-0x1p-127f", -0x1p-127},
@@ -287,13 +325,28 @@ FloatLiteralTestCaseList HexFloatCases() {
{"0x1.8p-127f", 0x1.8p-127},
{"0x1.8p-128f", 0x1.8p-128},
+ {"0x1p-15h", 0x1p-15},
+ {"0x0.8p-14h", 0x0.8p-14},
+ {"0x1p-16h", 0x1p-16},
+ {"0x0.2p-13h", 0x0.2p-13},
+ {"0x1p-17h", 0x1p-17},
+ {"0x1p-18h", 0x1p-18},
+ {"-0x1p-15h", -0x1p-15},
+ {"-0x1p-16h", -0x1p-16},
+ {"-0x1p-17h", -0x1p-17},
+ {"-0x1p-18h", -0x1p-18},
+ {"0x1.8p-15h", 0x1.8p-15},
+ {"0x1.8p-16h", 0x1.8p-16},
+
// F64 extremities
- {"0x1p-1074", 0x1p-1074}, // +SmallestDenormal
- {"0x1p-1073", 0x1p-1073}, // +BiggerDenormal
- {"0x1.ffffffffffffp-1027", 0x1.ffffffffffffp-1027}, // +LargestDenormal
- {"-0x1p-1074", -0x1p-1074}, // -SmallestDenormal
- {"-0x1p-1073", -0x1p-1073}, // -BiggerDenormal
- {"-0x1.ffffffffffffp-1027", -0x1.ffffffffffffp-1027}, // -LargestDenormal
+ {"0x1p-1074", 0x1p-1074}, // +SmallestDenormal
+ {"0x1p-1073", 0x1p-1073}, // +BiggerDenormal
+ {"0x1.ffffffffffffep-1023", 0x1.ffffffffffffep-1023}, // +LargestDenormal
+ {"0x0.fffffffffffffp-1022", 0x0.fffffffffffffp-1022}, // +LargestDenormal
+ {"-0x1p-1074", -0x1p-1074}, // -SmallestDenormal
+ {"-0x1p-1073", -0x1p-1073}, // -BiggerDenormal
+ {"-0x1.ffffffffffffep-1023", -0x1.ffffffffffffep-1023}, // -LargestDenormal
+ {"-0x0.fffffffffffffp-1022", -0x0.fffffffffffffp-1022}, // -LargestDenormal
{"0x0.cafebeeff000dp-1022", 0x0.cafebeeff000dp-1022}, // +Subnormal
{"-0x0.cafebeeff000dp-1022", -0x0.cafebeeff000dp-1022}, // -Subnormal
@@ -301,21 +354,29 @@ FloatLiteralTestCaseList HexFloatCases() {
{"-0x1.2bfaf8p-1052", -0x1.2bfaf8p-1052}, // +Subnormal
{"0x1.55554p-1055", 0x1.55554p-1055}, // +Subnormal
{"-0x1.55554p-1055", -0x1.55554p-1055}, // -Subnormal
+ {"0x1.fffffffffffp-1027", 0x1.fffffffffffp-1027}, // +Subnormal, = 0x0.0fffffffffff8p-1022
+ {"-0x1.fffffffffffp-1027", -0x1.fffffffffffp-1027}, // -Subnormal
// F32 extremities
- {"0x1p-149", 0x1p-149}, // +SmallestDenormal
- {"0x1p-148", 0x1p-148}, // +BiggerDenormal
- {"0x1.fffffcp-127", 0x1.fffffcp-127}, // +LargestDenormal
- {"-0x1p-149", -0x1p-149}, // -SmallestDenormal
- {"-0x1p-148", -0x1p-148}, // -BiggerDenormal
- {"-0x1.fffffcp-127", -0x1.fffffcp-127}, // -LargestDenormal
-
- {"0x0.cafebp-129", 0x0.cafebp-129}, // +Subnormal
- {"-0x0.cafebp-129", -0x0.cafebp-129}, // -Subnormal
- {"0x1.2bfaf8p-127", 0x1.2bfaf8p-127}, // +Subnormal
- {"-0x1.2bfaf8p-127", -0x1.2bfaf8p-127}, // -Subnormal
- {"0x1.55554p-130", 0x1.55554p-130}, // +Subnormal
- {"-0x1.55554p-130", -0x1.55554p-130}, // -Subnormal
+ {"0x1p-149f", 0x1p-149}, // +SmallestDenormal
+ {"0x1p-148f", 0x1p-148}, // +BiggerDenormal
+ {"0x1.fffffcp-127f", 0x1.fffffcp-127}, // +LargestDenormal
+ {"0x0.fffffep-126f", 0x0.fffffep-126}, // +LargestDenormal
+ {"0x1.0p-126f", 0x1.0p-126}, // +SmallestNormal
+ {"0x8.0p-129f", 0x8.0p-129}, // +SmallestNormal
+ {"-0x1p-149f", -0x1p-149}, // -SmallestDenormal
+ {"-0x1p-148f", -0x1p-148}, // -BiggerDenormal
+ {"-0x1.fffffcp-127f", -0x1.fffffcp-127}, // -LargestDenormal
+ {"-0x0.fffffep-126f", -0x0.fffffep-126}, // -LargestDenormal
+ {"-0x1.0p-126f", -0x1.0p-126}, // -SmallestNormal
+ {"-0x8.0p-129f", -0x8.0p-129}, // -SmallestNormal
+
+ {"0x0.cafebp-129f", 0x0.cafebp-129}, // +Subnormal
+ {"-0x0.cafebp-129f", -0x0.cafebp-129}, // -Subnormal
+ {"0x1.2bfaf8p-127f", 0x1.2bfaf8p-127}, // +Subnormal
+ {"-0x1.2bfaf8p-127f", -0x1.2bfaf8p-127}, // -Subnormal
+ {"0x1.55554p-130f", 0x1.55554p-130}, // +Subnormal
+ {"-0x1.55554p-130f", -0x1.55554p-130}, // -Subnormal
// F32 exactly representable
{"0x1.000002p+0f", 0x1.000002p+0},
@@ -324,10 +385,47 @@ FloatLiteralTestCaseList HexFloatCases() {
{"0x8.00003p+0f", 0x8.00003p+0},
{"0x2.123p+0f", 0x2.123p+0},
{"0x2.cafefp+0f", 0x2.cafefp+0},
+ {"0x0.0000fep-126f", 0x0.0000fep-126}, // Subnormal
+ {"-0x0.0000fep-126f", -0x0.0000fep-126}, // Subnormal
+ {"0x3.f8p-144f", 0x3.f8p-144}, // Subnormal
+ {"-0x3.f8p-144f", -0x3.f8p-144}, // Subnormal
+
+ // F16 extremities
+ {"0x1p-24h", 0x1p-24}, // +SmallestDenormal
+ {"0x1p-23h", 0x1p-23}, // +BiggerDenormal
+ {"0x1.ff8p-15h", 0x1.ff8p-15}, // +LargestDenormal
+ {"0x0.ffcp-14h", 0x0.ffcp-14}, // +LargestDenormal
+ {"0x1.0p-14h", 0x1.0p-14}, // +SmallestNormal
+ {"0x8.0p-17h", 0x8.0p-17}, // +SmallestNormal
+ {"-0x1p-24h", -0x1p-24}, // -SmallestDenormal
+ {"-0x1p-23h", -0x1p-23}, // -BiggerDenormal
+ {"-0x1.ff8p-15h", -0x1.ff8p-15}, // -LargestDenormal
+ {"-0x0.ffcp-14h", -0x0.ffcp-14}, // -LargestDenormal
+ {"-0x1.0p-14h", -0x1.0p-14}, // -SmallestNormal
+ {"-0x8.0p-17h", -0x8.0p-17}, // -SmallestNormal
+
+ {"0x0.a8p-19h", 0x0.a8p-19}, // +Subnormal
+ {"-0x0.a8p-19h", -0x0.a8p-19}, // -Subnormal
+ {"0x1.7ap-17h", 0x1.7ap-17}, // +Subnormal
+ {"-0x1.7ap-17h", -0x1.7ap-17}, // -Subnormal
+ {"0x1.dp-20h", 0x1.dp-20}, // +Subnormal
+ {"-0x1.dp-20h", -0x1.dp-20}, // -Subnormal
+
+ // F16 exactly representable
+ {"0x1.004p+0h", 0x1.004p+0},
+ {"0x8.02p+0h", 0x8.02p+0},
+ {"0x8.fep+0h", 0x8.fep+0},
+ {"0x8.06p+0h", 0x8.06p+0},
+ {"0x2.128p+0h", 0x2.128p+0},
+ {"0x2.ca8p+0h", 0x2.ca8p+0},
+ {"0x0.0fcp-14h", 0x0.0fcp-14}, // Subnormal
+ {"-0x0.0fcp-14h", -0x0.0fcp-14}, // Subnormal
+ {"0x3.f00p-20h", 0x3.f00p-20}, // Subnormal
+ {"-0x3.f00p-20h", -0x3.f00p-20}, // Subnormal
// Underflow -> Zero
- {"0x1p-1074", 0.0}, // Exponent underflows
- {"-0x1p-1074", 0.0},
+ {"0x1p-1075", 0.0}, // Exponent underflows
+ {"-0x1p-1075", 0.0},
{"0x1p-5000", 0.0},
{"-0x1p-5000", 0.0},
{"0x0.00000000000000000000001p-1022", 0.0}, // Fraction causes underflow
@@ -399,6 +497,16 @@ FloatLiteralTestCaseList HexFloatCases() {
{"-0x.8p2f", -2.0},
{"-0x1.8p-1f", -0.75},
{"-0x2p-2f", -0.5}, // No binary point
+
+ // Examples with a binary exponent and a 'h' suffix.
+ {"0x1.p0h", 1.0},
+ {"0x.8p2h", 2.0},
+ {"0x1.8p-1h", 0.75},
+ {"0x2p-2h", 0.5}, // No binary point
+ {"-0x1.p0h", -1.0},
+ {"-0x.8p2h", -2.0},
+ {"-0x1.8p-1h", -0.75},
+ {"-0x2p-2h", -0.5}, // No binary point
};
}
INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_HexFloat,
@@ -542,6 +650,23 @@ INSTANTIATE_TEST_SUITE_P(
})));
INSTANTIATE_TEST_SUITE_P(
+ HexNaNF16,
+ ParserImplInvalidLiteralTest,
+ testing::Combine(testing::Values("1:1: value cannot be represented as 'f16'"),
+ testing::ValuesIn(std::vector<const char*>{
+ "0x1.8p+16h",
+ "0x1.004p+16h",
+ "0x1.018p+16h",
+ "0x1.1ep+16h",
+ "0x1.ffcp+16h",
+ "-0x1.8p+16h",
+ "-0x1.004p+16h",
+ "-0x1.018p+16h",
+ "-0x1.1ep+16h",
+ "-0x1.ffcp+16h",
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
HexOverflowAFloat,
ParserImplInvalidLiteralTest,
testing::Combine(testing::Values("1:1: value cannot be represented as 'abstract-float'"),
@@ -578,17 +703,94 @@ INSTANTIATE_TEST_SUITE_P(
})));
INSTANTIATE_TEST_SUITE_P(
+ HexOverflowF16,
+ ParserImplInvalidLiteralTest,
+ testing::Combine(testing::Values("1:1: value cannot be represented as 'f16'"),
+ testing::ValuesIn(std::vector<const char*>{
+ "0x1p+16h",
+ "-0x1p+16h",
+ "0x1.1p+16h",
+ "-0x1.1p+16h",
+ "0x1p+17h",
+ "-0x1p+17h",
+ "0x32p+15h",
+ "-0x32p+15h",
+ "0x32p+500h",
+ "-0x32p+500h",
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
HexNotExactlyRepresentableF32,
ParserImplInvalidLiteralTest,
testing::Combine(testing::Values("1:1: value cannot be exactly represented as 'f32'"),
testing::ValuesIn(std::vector<const char*>{
- "0x1.000001p+0f", // Quantizes to 0x1.0p+0
- "0x8.0000f8p+0f", // Quantizes to 0x8.0000fp+0
- "0x8.000038p+0f", // Quantizes to 0x8.00003p+0
- "0x2.cafef00dp+0f", // Quantizes to 0x2.cafefp+0
+ "0x1.000001p+0f", // Quantizes to 0x1.0p+0
+ "0x1.0000008p+0f", // Quantizes to 0x1.0p+0
+ "0x1.0000000000001p+0f", // Quantizes to 0x1.0p+0
+ "0x8.0000f8p+0f", // Quantizes to 0x8.0000fp+0
+ "0x8.000038p+0f", // Quantizes to 0x8.00003p+0
+ "0x2.cafef00dp+0f", // Quantizes to 0x2.cafefp+0
+ "0x0.0000ffp-126f", // Subnormal, quantizes to 0x0.0000fep-126
+ "0x3.fcp-144f", // Subnormal, quantizes to 0x3.f8p-144
+ "-0x0.0000ffp-126f", // Subnormal, quantizes to -0x0.0000fep-126
+ "-0x3.fcp-144f", // Subnormal, quantizes to -0x3.f8p-144
+ "0x0.ffffffp-126f", // Subnormal, quantizes to 0x0.fffffep-144
+ "0x0.fffffe0000001p-126f", // Subnormal, quantizes to 0x0.fffffep-144
+ "-0x0.ffffffp-126f", // Subnormal, quantizes to -0x0.fffffep-144
+ "-0x0.fffffe0000001p-126f", // Subnormal, quantizes to -0x0.fffffep-144
+ "0x1.8p-149f", // Subnormal, quantizes to 0x1.0p-149f
+ "0x1.4p-149f", // Subnormal, quantizes to 0x1.0p-149f
+ "0x1.000002p-149f", // Subnormal, quantizes to 0x1.0p-149f
+ "0x1.0000000000001p-149f", // Subnormal, quantizes to 0x1.0p-149f
+ "-0x1.8p-149f", // Subnormal, quantizes to -0x1.0p-149f
+ "-0x1.4p-149f", // Subnormal, quantizes to -0x1.0p-149f
+ "-0x1.000002p-149f", // Subnormal, quantizes to -0x1.0p-149f
+ "-0x1.0000000000001p-149f", // Subnormal, quantizes to -0x1.0p-149f
+ "0x1.0p-150f", // Smaller than the smallest subnormal, quantizes to 0.0
+ "0x1.8p-150f", // Smaller than the smallest subnormal, quantizes to 0.0
+ "-0x1.0p-150f", // Smaller than the smallest subnormal, quantizes to -0.0
+ "-0x1.8p-150f", // Smaller than the smallest subnormal, quantizes to -0.0
})));
INSTANTIATE_TEST_SUITE_P(
+ HexNotExactlyRepresentableF16,
+ ParserImplInvalidLiteralTest,
+ testing::Combine(
+ testing::Values("1:1: value cannot be exactly represented as 'f16'"),
+ testing::ValuesIn(std::vector<const char*>{
+ "0x1.002p+0h", // Quantizes to 0x1.0p+0, has 11 mantissa bits rather than 10
+ "0x1.001p+0h", // Quantizes to 0x1.0p+0, has 12 mantissa bits rather than 10
+ "0x1.0000000000001p+0h", // Quantizes to 0x1.0p+0, has 52 mantissa bits rather than 10
+ "0x8.0fp+0h", // Quantizes to 0x8.0ep+0
+ "0x8.31p+0h", // Quantizes to 0x8.30p+0
+ "0x2.ca80dp+0h", // Quantizes to 0x2.ca8p+0
+ "0x4.ba8p+0h", // Quantizes to 0x4.bap+0
+ "0x4.011p+0h", // Quantizes to 0x4.01p+0
+ "0x0.0fep-14h", // Subnormal, quantizes to 0x0.0fcp-14
+ "0x3.f8p-20h", // Subnormal, quantizes to 0x3.f0p-20
+ "-0x0.0fep-14h", // Subnormal, quantizes to -0x0.0fcp-14
+ "-0x3.f8p-20h", // Subnormal, quantizes to -0x3.f0p-20
+ "0x0.ffep-14h", // Subnormal, quantizes to 0x0.ffcp-14
+ "0x0.ffe0000000001p-14h", // Subnormal, quantizes to 0x0.ffcp-14
+ "0x0.fffffffffffffp-14h", // Subnormal, quantizes to 0x0.ffcp-14
+ "-0x0.ffep-14h", // Subnormal, quantizes to -0x0.ffcp-14
+ "-0x0.ffe0000000001p-14h", // Subnormal, quantizes to -0x0.ffcp-14
+ "-0x0.fffffffffffffp-14h", // Subnormal, quantizes to -0x0.ffcp-14
+ "0x1.8p-24h", // Subnormal, quantizes to 0x1.0p-24f
+ "0x1.4p-24h", // Subnormal, quantizes to 0x1.0p-24f
+ "0x1.004p-24h", // Subnormal, quantizes to 0x1.0p-24f
+ "0x1.0000000000001p-24h", // Subnormal, quantizes to 0x1.0p-24f
+ "-0x1.8p-24h", // Subnormal, quantizes to -0x1.0p-24f
+ "-0x1.4p-24h", // Subnormal, quantizes to -0x1.0p-24f
+ "-0x1.004p-24h", // Subnormal, quantizes to -0x1.0p-24f
+ "-0x1.0000000000001p-24h", // Subnormal, quantizes to -0x1.0p-24f
+ "0x1.0p-25h", // Smaller than the smallest subnormal, quantizes to 0.0
+ "0x1.8p-25h", // Smaller than the smallest subnormal, quantizes to 0.0
+ "-0x1.0p-25h", // Smaller than the smallest subnormal, quantizes to -0.0
+ "-0x1.8p-25h", // Smaller than the smallest subnormal, quantizes to -0.0
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
DecOverflowAFloat,
ParserImplInvalidLiteralTest,
testing::Combine(testing::Values("1:1: value cannot be represented as 'abstract-float'"),
@@ -622,6 +824,25 @@ INSTANTIATE_TEST_SUITE_P(
"-1.2e+256f",
})));
+INSTANTIATE_TEST_SUITE_P(
+ DecOverflowF16,
+ ParserImplInvalidLiteralTest,
+ testing::Combine(testing::Values("1:1: value cannot be represented as 'f16'"),
+ testing::ValuesIn(std::vector<const char*>{
+ "1.0e5h",
+ "-1.0e5h",
+ "7.0e4h",
+ "-7.0e4h",
+ "6.6e4h",
+ "-6.6e4h",
+ "6.56e4h",
+ "-6.56e4h",
+ "6.554e4h",
+ "-6.554e4h",
+ "1.2e+32h",
+ "-1.2e+32h",
+ })));
+
TEST_F(ParserImplTest, ConstLiteral_FloatHighest) {
const auto highest = std::numeric_limits<float>::max();
const auto expected_highest = 340282346638528859811704183484516925440.0f;
@@ -636,8 +857,7 @@ TEST_F(ParserImplTest, ConstLiteral_FloatHighest) {
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(c.value, nullptr);
ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
- EXPECT_DOUBLE_EQ(c->As<ast::FloatLiteralExpression>()->value,
- std::numeric_limits<float>::max());
+ EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->value, std::numeric_limits<float>::max());
EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
ast::FloatLiteralExpression::Suffix::kNone);
EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 42u}}));
@@ -660,8 +880,7 @@ TEST_F(ParserImplTest, ConstLiteral_FloatLowest) {
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(c.value, nullptr);
ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
- EXPECT_DOUBLE_EQ(c->As<ast::FloatLiteralExpression>()->value,
- std::numeric_limits<float>::lowest());
+ EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->value, std::numeric_limits<float>::lowest());
EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
ast::FloatLiteralExpression::Suffix::kNone);
EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 43u}}));
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc
index 002f638c37c..349bf5ebdb5 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc
@@ -20,7 +20,7 @@ namespace {
TEST_F(ParserImplTest, ContinueStmt) {
auto p = parser("continue");
- auto e = p->continue_stmt();
+ auto e = p->continue_statement();
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc
index d7a5779ff71..d2113af72e5 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc
@@ -20,17 +20,17 @@ namespace {
TEST_F(ParserImplTest, ContinuingStmt) {
auto p = parser("continuing { discard; }");
- auto e = p->continuing_stmt();
+ auto e = p->continuing_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
- ASSERT_EQ(e->statements.size(), 1u);
+ ASSERT_EQ(e->statements.Length(), 1u);
ASSERT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
}
TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) {
auto p = parser("continuing { discard }");
- auto e = p->continuing_stmt();
+ auto e = p->continuing_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_core_lhs_expression_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_core_lhs_expression_test.cc
new file mode 100644
index 00000000000..81984eb41f3
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_core_lhs_expression_test.cc
@@ -0,0 +1,93 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, CoreLHS_NoMatch) {
+ auto p = parser("123");
+ auto e = p->core_lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_FALSE(e.matched);
+}
+
+TEST_F(ParserImplTest, CoreLHS_Ident) {
+ auto p = parser("identifier");
+ auto e = p->core_lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ ASSERT_NE(e.value, nullptr);
+ ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+
+ auto* ident = e->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("identifier"));
+}
+
+TEST_F(ParserImplTest, CoreLHS_ParenStmt) {
+ auto p = parser("(a)");
+ auto e = p->core_lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ ASSERT_NE(e.value, nullptr);
+ ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+
+ auto* ident = e->As<ast::IdentifierExpression>();
+ EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+}
+
+TEST_F(ParserImplTest, CoreLHS_MissingRightParen) {
+ auto p = parser("(a");
+ auto e = p->core_lhs_expression();
+ ASSERT_TRUE(p->has_error());
+ ASSERT_TRUE(e.errored);
+ EXPECT_FALSE(e.matched);
+ ASSERT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:3: expected ')'");
+}
+
+TEST_F(ParserImplTest, CoreLHS_InvalidLHSExpression) {
+ auto p = parser("(if (a() {})");
+ auto e = p->core_lhs_expression();
+ ASSERT_TRUE(p->has_error());
+ ASSERT_TRUE(e.errored);
+ EXPECT_FALSE(e.matched);
+ ASSERT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:1: invalid expression");
+}
+
+TEST_F(ParserImplTest, CoreLHS_MissingLHSExpression) {
+ auto p = parser("()");
+ auto e = p->core_lhs_expression();
+ ASSERT_TRUE(p->has_error());
+ ASSERT_TRUE(e.errored);
+ EXPECT_FALSE(e.matched);
+ ASSERT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:1: invalid expression");
+}
+
+TEST_F(ParserImplTest, CoreLHS_Invalid) {
+ auto p = parser("1234");
+ auto e = p->core_lhs_expression();
+ ASSERT_FALSE(p->has_error());
+ ASSERT_FALSE(e.errored);
+ EXPECT_FALSE(e.matched);
+}
+
+} // namespace
+} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc
index 6c70bd3a661..78c4b8dfec2 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc
@@ -20,7 +20,7 @@ namespace {
TEST_F(ParserImplTest, DepthTextureType_Invalid) {
auto p = parser("1234");
- auto t = p->depth_texture();
+ auto t = p->depth_texture_type();
EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_FALSE(p->has_error());
@@ -28,7 +28,7 @@ TEST_F(ParserImplTest, DepthTextureType_Invalid) {
TEST_F(ParserImplTest, DepthTextureType_2d) {
auto p = parser("texture_depth_2d");
- auto t = p->depth_texture();
+ auto t = p->depth_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
@@ -41,7 +41,7 @@ TEST_F(ParserImplTest, DepthTextureType_2d) {
TEST_F(ParserImplTest, DepthTextureType_2dArray) {
auto p = parser("texture_depth_2d_array");
- auto t = p->depth_texture();
+ auto t = p->depth_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
@@ -54,7 +54,7 @@ TEST_F(ParserImplTest, DepthTextureType_2dArray) {
TEST_F(ParserImplTest, DepthTextureType_Cube) {
auto p = parser("texture_depth_cube");
- auto t = p->depth_texture();
+ auto t = p->depth_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
@@ -67,7 +67,7 @@ TEST_F(ParserImplTest, DepthTextureType_Cube) {
TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
auto p = parser("texture_depth_cube_array");
- auto t = p->depth_texture();
+ auto t = p->depth_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
@@ -80,7 +80,7 @@ TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
TEST_F(ParserImplTest, DepthTextureType_Multisampled2d) {
auto p = parser("texture_depth_multisampled_2d");
- auto t = p->depth_texture();
+ auto t = p->depth_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
index bdf7eebd12c..ed57be8d28d 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
@@ -28,10 +28,10 @@ TEST_F(EnableDirectiveTest, Valid) {
EXPECT_FALSE(p->has_error()) << p->error();
auto program = p->program();
auto& ast = program.AST();
- ASSERT_EQ(ast.Enables().size(), 1u);
+ ASSERT_EQ(ast.Enables().Length(), 1u);
auto* enable = ast.Enables()[0];
EXPECT_EQ(enable->extension, ast::Extension::kF16);
- ASSERT_EQ(ast.GlobalDeclarations().size(), 1u);
+ ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
}
@@ -45,12 +45,12 @@ enable f16;
EXPECT_FALSE(p->has_error()) << p->error();
auto program = p->program();
auto& ast = program.AST();
- ASSERT_EQ(ast.Enables().size(), 2u);
+ ASSERT_EQ(ast.Enables().Length(), 2u);
auto* enable_a = ast.Enables()[0];
auto* enable_b = ast.Enables()[1];
EXPECT_EQ(enable_a->extension, ast::Extension::kF16);
EXPECT_EQ(enable_b->extension, ast::Extension::kF16);
- ASSERT_EQ(ast.GlobalDeclarations().size(), 2u);
+ ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
EXPECT_EQ(ast.GlobalDeclarations()[0], enable_a);
EXPECT_EQ(ast.GlobalDeclarations()[1], enable_b);
}
@@ -64,8 +64,8 @@ TEST_F(EnableDirectiveTest, InvalidIdentifier) {
EXPECT_EQ(p->error(), "1:8: unsupported extension: 'NotAValidExtensionName'");
auto program = p->program();
auto& ast = program.AST();
- EXPECT_EQ(ast.Enables().size(), 0u);
- EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+ EXPECT_EQ(ast.Enables().Length(), 0u);
+ EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
}
// Test an enable directive missing ending semicolon.
@@ -76,8 +76,20 @@ TEST_F(EnableDirectiveTest, MissingEndingSemicolon) {
EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive");
auto program = p->program();
auto& ast = program.AST();
- EXPECT_EQ(ast.Enables().size(), 0u);
- EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+ EXPECT_EQ(ast.Enables().Length(), 0u);
+ EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
+}
+
+// Test the special error message when enable are used with parenthesis.
+TEST_F(EnableDirectiveTest, ParenthesisSpecialCase) {
+ auto p = parser("enable(f16);");
+ p->translation_unit();
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: enable directives don't take parenthesis");
+ auto program = p->program();
+ auto& ast = program.AST();
+ EXPECT_EQ(ast.Enables().Length(), 0u);
+ EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
}
// Test using invalid tokens in an enable directive.
@@ -89,8 +101,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive");
auto program = p->program();
auto& ast = program.AST();
- EXPECT_EQ(ast.Enables().size(), 0u);
- EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+ EXPECT_EQ(ast.Enables().Length(), 0u);
+ EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
}
{
auto p = parser("enable <f16;");
@@ -99,8 +111,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:8: invalid extension name");
auto program = p->program();
auto& ast = program.AST();
- EXPECT_EQ(ast.Enables().size(), 0u);
- EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+ EXPECT_EQ(ast.Enables().Length(), 0u);
+ EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
}
{
auto p = parser("enable =;");
@@ -109,8 +121,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:8: invalid extension name");
auto program = p->program();
auto& ast = program.AST();
- EXPECT_EQ(ast.Enables().size(), 0u);
- EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+ EXPECT_EQ(ast.Enables().Length(), 0u);
+ EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
}
{
auto p = parser("enable vec4;");
@@ -119,8 +131,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:8: invalid extension name");
auto program = p->program();
auto& ast = program.AST();
- EXPECT_EQ(ast.Enables().size(), 0u);
- EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+ EXPECT_EQ(ast.Enables().Length(), 0u);
+ EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
}
}
@@ -136,10 +148,10 @@ enable f16;
auto program = p->program();
auto& ast = program.AST();
// Accept the enable directive although it caused an error
- ASSERT_EQ(ast.Enables().size(), 1u);
+ ASSERT_EQ(ast.Enables().Length(), 1u);
auto* enable = ast.Enables()[0];
EXPECT_EQ(enable->extension, ast::Extension::kF16);
- ASSERT_EQ(ast.GlobalDeclarations().size(), 2u);
+ ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
EXPECT_EQ(ast.GlobalDeclarations()[1], enable);
}
@@ -156,10 +168,10 @@ enable f16;
auto program = p->program();
auto& ast = program.AST();
// Accept the enable directive although it cause an error
- ASSERT_EQ(ast.Enables().size(), 1u);
+ ASSERT_EQ(ast.Enables().Length(), 1u);
auto* enable = ast.Enables()[0];
EXPECT_EQ(enable->extension, ast::Extension::kF16);
- ASSERT_EQ(ast.GlobalDeclarations().size(), 1u);
+ ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
index ab97d94128a..85e888dffb0 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -204,7 +204,7 @@ fn f() { x = vec2<u32>(1,2; }
TEST_F(ParserImplErrorTest, ConstVarStmtInvalid) {
EXPECT("fn f() { let >; }",
- R"(test.wgsl:1:14 error: expected identifier for let declaration
+ R"(test.wgsl:1:14 error: expected identifier for 'let' declaration
fn f() { let >; }
^
)");
@@ -212,7 +212,7 @@ fn f() { let >; }
TEST_F(ParserImplErrorTest, ConstVarStmtMissingAssignment) {
EXPECT("fn f() { let a : i32; }",
- R"(test.wgsl:1:21 error: expected '=' for let declaration
+ R"(test.wgsl:1:21 error: expected '=' for 'let' declaration
fn f() { let a : i32; }
^
)");
@@ -220,7 +220,7 @@ fn f() { let a : i32; }
TEST_F(ParserImplErrorTest, ConstVarStmtMissingConstructor) {
EXPECT("fn f() { let a : i32 = >; }",
- R"(test.wgsl:1:24 error: missing constructor for let declaration
+ R"(test.wgsl:1:24 error: missing initializer for 'let' declaration
fn f() { let a : i32 = >; }
^
)");
@@ -306,6 +306,51 @@ fn f() { for (var i : i32 = 0; i < 8; i=i+1) {
)");
}
+TEST_F(ParserImplErrorTest, FunctionDeclStaticAssertMissingCondThenEOF) {
+ EXPECT("fn f() { static_assert }", R"(test.wgsl:1:24 error: unable to parse condition expression
+fn f() { static_assert }
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, FunctionDeclStaticAssertMissingCondThenSemicolon) {
+ EXPECT("fn f() { static_assert; }",
+ R"(test.wgsl:1:23 error: unable to parse condition expression
+fn f() { static_assert; }
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, FunctionDeclStaticAssertMissingCondThenLet) {
+ EXPECT("fn f() { static_assert\nlet x = 0; }",
+ R"(test.wgsl:2:1 error: unable to parse condition expression
+let x = 0; }
+^^^
+)");
+}
+
+TEST_F(ParserImplErrorTest, FunctionDeclStaticAssertMissingLParen) {
+ EXPECT("fn f() { static_assert true);", R"(test.wgsl:1:28 error: expected ';' for statement
+fn f() { static_assert true);
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, FunctionDeclStaticAssertMissingRParen) {
+ EXPECT("fn f() { static_assert (true;", R"(test.wgsl:1:29 error: expected ')'
+fn f() { static_assert (true;
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, FunctionDeclStaticAssertMissingSemicolon) {
+ EXPECT("fn f() { static_assert true }",
+ R"(test.wgsl:1:29 error: expected ';' for statement
+fn f() { static_assert true }
+ ^
+)");
+}
+
// TODO(crbug.com/tint/1503): Remove this when @stage is removed
TEST_F(ParserImplErrorTest, FunctionDeclStageMissingLParen) {
EXPECT("@stage vertex) fn f() {}",
@@ -316,8 +361,13 @@ TEST_F(ParserImplErrorTest, FunctionDeclStageMissingLParen) {
}
TEST_F(ParserImplErrorTest, FunctionDeclStageMissingRParen) {
- EXPECT("@stage(vertex fn f() {}",
- R"(test.wgsl:1:15 error: expected ')' for stage attribute
+ EXPECT(
+ "@stage(vertex fn f() {}",
+ R"(test.wgsl:1:2 warning: use of deprecated language feature: remove stage and use @vertex
+@stage(vertex fn f() {}
+ ^^^^^
+
+test.wgsl:1:15 error: expected ')' for stage attribute
@stage(vertex fn f() {}
^^
)");
@@ -352,18 +402,18 @@ TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeXInvalid) {
}
TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeYInvalid) {
- EXPECT("@workgroup_size(1, ) fn f() {}",
+ EXPECT("@workgroup_size(1, fn) fn f() {}",
R"(test.wgsl:1:20 error: expected workgroup_size y parameter
-@workgroup_size(1, ) fn f() {}
- ^
+@workgroup_size(1, fn) fn f() {}
+ ^^
)");
}
TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeZInvalid) {
- EXPECT("@workgroup_size(1, 2, ) fn f() {}",
+ EXPECT("@workgroup_size(1, 2, fn) fn f() {}",
R"(test.wgsl:1:23 error: expected workgroup_size z parameter
-@workgroup_size(1, 2, ) fn f() {}
- ^
+@workgroup_size(1, 2, fn) fn f() {}
+ ^^
)");
}
@@ -451,75 +501,54 @@ fn f(a:i32)->i32{return a;@size(1)}
}
TEST_F(ParserImplErrorTest, FunctionMissingOpenLine) {
- EXPECT(R"(let bar : vec2<f32> = vec2<f32>(1., 2.);
+ EXPECT(
+ R"(const bar : vec2<f32> = vec2<f32>(1., 2.);
var a : f32 = bar[0];
return;
})",
- R"(test.wgsl:2:17 error: unable to parse const_expr
- var a : f32 = bar[0];
- ^^^
-
-test.wgsl:3:3 error: statement found outside of function body
+ R"(test.wgsl:3:3 error: statement found outside of function body
return;
^^^^^^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
- EXPECT("let ^ : i32 = 1;",
- R"(test.wgsl:1:5 error: expected identifier for let declaration
-let ^ : i32 = 1;
- ^
+ EXPECT("const ^ : i32 = 1;",
+ R"(test.wgsl:1:7 error: expected identifier for 'const' declaration
+const ^ : i32 = 1;
+ ^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingSemicolon) {
- EXPECT("let i : i32 = 1",
- R"(test.wgsl:1:16 error: expected ';' for let declaration
-let i : i32 = 1
- ^
+ EXPECT("const i : i32 = 1",
+ R"(test.wgsl:1:18 error: expected ';' for 'const' declaration
+const i : i32 = 1
+ ^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingLParen) {
- EXPECT("let i : vec2<i32> = vec2<i32>;",
- R"(test.wgsl:1:30 error: expected '(' for type constructor
-let i : vec2<i32> = vec2<i32>;
- ^
+ EXPECT("const i : vec2<i32> = vec2<i32>;",
+ R"(test.wgsl:1:32 error: expected '(' for type constructor
+const i : vec2<i32> = vec2<i32>;
+ ^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
- EXPECT("let i : vec2<i32> = vec2<i32>(1., 2.;",
- R"(test.wgsl:1:37 error: expected ')' for type constructor
-let i : vec2<i32> = vec2<i32>(1., 2.;
- ^
+ EXPECT("const i : vec2<i32> = vec2<i32>(1., 2.;",
+ R"(test.wgsl:1:39 error: expected ')' for type constructor
+const i : vec2<i32> = vec2<i32>(1., 2.;
+ ^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
- EXPECT("let i : vec2<i32> = vec2<i32>(!);",
- R"(test.wgsl:1:31 error: unable to parse const_expr
-let i : vec2<i32> = vec2<i32>(!);
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteralSpaceLessThan) {
- EXPECT("let i = 1 < 2;",
- R"(test.wgsl:1:11 error: expected ';' for let declaration
-let i = 1 < 2;
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclConstNotConstExpr) {
- EXPECT(
- "let a = 1;\n"
- "let b = a;",
- R"(test.wgsl:2:9 error: unable to parse const_expr
-let b = a;
- ^
+ EXPECT("const i : vec2<i32> = vec2<i32>(!);",
+ R"(test.wgsl:1:34 error: unable to parse right side of ! expression
+const i : vec2<i32> = vec2<i32>(!);
+ ^
)");
}
@@ -528,8 +557,8 @@ TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
std::stringstream src;
std::stringstream mkr;
- src << "let i : i32 = ";
- mkr << " ";
+ src << "const i : i32 = ";
+ mkr << " ";
for (size_t i = 0; i < kMaxDepth + 8; i++) {
src << "f32(";
if (i < kMaxDepth) {
@@ -544,23 +573,114 @@ TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
}
src << ";";
std::stringstream err;
- err << "test.wgsl:1:527 error: maximum parser recursive depth reached\n"
+ err << "test.wgsl:1:529 error: maximum parser recursive depth reached\n"
<< src.str() << "\n"
<< mkr.str() << "\n";
EXPECT(src.str().c_str(), err.str().c_str());
}
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingLParen) {
- EXPECT("let i : vec2<i32> = vec2<i32> 1, 2);",
- R"(test.wgsl:1:31 error: expected '(' for type constructor
+ EXPECT("const i : vec2<i32> = vec2<i32> 1, 2);",
+ R"(test.wgsl:1:33 error: expected '(' for type constructor
+const i : vec2<i32> = vec2<i32> 1, 2);
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
+ EXPECT("const i : vec2<i32> = vec2<i32>(1, 2;",
+ R"(test.wgsl:1:37 error: expected ')' for type constructor
+const i : vec2<i32> = vec2<i32>(1, 2;
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclLetInvalidIdentifier) {
+ EXPECT(
+ "let ^ : i32 = 1;",
+ R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let ^ : i32 = 1;
+^^^
+
+test.wgsl:1:5 error: expected identifier for 'let' declaration
+let ^ : i32 = 1;
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclLetMissingSemicolon) {
+ EXPECT(
+ "let i : i32 = 1",
+ R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : i32 = 1
+^^^
+
+test.wgsl:1:16 error: expected ';' for 'const' declaration
+let i : i32 = 1
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclLetMissingLParen) {
+ EXPECT(
+ "let i : vec2<i32> = vec2<i32>;",
+ R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>;
+^^^
+
+test.wgsl:1:30 error: expected '(' for type constructor
+let i : vec2<i32> = vec2<i32>;
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclLetMissingRParen) {
+ EXPECT(
+ "let i : vec2<i32> = vec2<i32>(1., 2.;",
+ R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>(1., 2.;
+^^^
+
+test.wgsl:1:37 error: expected ')' for type constructor
+let i : vec2<i32> = vec2<i32>(1., 2.;
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclLetBadConstLiteral) {
+ EXPECT(
+ "let i : vec2<i32> = vec2<i32>(!);",
+ R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>(!);
+^^^
+
+test.wgsl:1:32 error: unable to parse right side of ! expression
+let i : vec2<i32> = vec2<i32>(!);
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingLParen) {
+ EXPECT(
+ "let i : vec2<i32> = vec2<i32> 1, 2);",
+ R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32> 1, 2);
+^^^
+
+test.wgsl:1:31 error: expected '(' for type constructor
let i : vec2<i32> = vec2<i32> 1, 2);
^
)");
}
-TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
- EXPECT("let i : vec2<i32> = vec2<i32>(1, 2;",
- R"(test.wgsl:1:35 error: expected ')' for type constructor
+TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingRParen) {
+ EXPECT(
+ "let i : vec2<i32> = vec2<i32>(1, 2;",
+ R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>(1, 2;
+^^^
+
+test.wgsl:1:35 error: expected ')' for type constructor
let i : vec2<i32> = vec2<i32>(1, 2;
^
)");
@@ -622,6 +742,50 @@ var x : texture_multisampled_2d<1>;
)");
}
+TEST_F(ParserImplErrorTest, GlobalDeclStaticAssertMissingCondThenEOF) {
+ EXPECT("static_assert", R"(test.wgsl:1:14 error: unable to parse condition expression
+static_assert
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclStaticAssertMissingCondThenSemicolon) {
+ EXPECT("static_assert;", R"(test.wgsl:1:14 error: unable to parse condition expression
+static_assert;
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclStaticAssertMissingCondThenAlias) {
+ EXPECT("static_assert\ntype T = i32;",
+ R"(test.wgsl:2:1 error: unable to parse condition expression
+type T = i32;
+^^^^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclStaticAssertMissingLParen) {
+ EXPECT("static_assert true);", R"(test.wgsl:1:19 error: expected ';' for static assertion declaration
+static_assert true);
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclStaticAssertMissingRParen) {
+ EXPECT("static_assert (true;", R"(test.wgsl:1:20 error: expected ')'
+static_assert (true;
+ ^
+)");
+}
+
+TEST_F(ParserImplErrorTest, GlobalDeclStaticAssertMissingSemicolon) {
+ EXPECT("static_assert true static_assert true;",
+ R"(test.wgsl:1:20 error: expected ';' for static assertion declaration
+static_assert true static_assert true;
+ ^^^^^^^^^^^^^
+)");
+}
+
TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingLessThan) {
EXPECT("var x : texture_storage_2d;",
R"(test.wgsl:1:27 error: expected '<' for storage texture type
@@ -747,14 +911,6 @@ type meow = f32
)");
}
-TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingLessThan) {
- EXPECT("var i : array;",
- R"(test.wgsl:1:14 error: expected '<' for array declaration
-var i : array;
- ^
-)");
-}
-
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingGreaterThan) {
EXPECT("var i : array<u32, 3;",
R"(test.wgsl:1:21 error: expected '>' for array declaration
@@ -1210,7 +1366,7 @@ fn f() { var a : u32 }
TEST_F(ParserImplErrorTest, VarStmtInvalidAssignment) {
EXPECT("fn f() { var a : u32 = >; }",
- R"(test.wgsl:1:24 error: missing constructor for variable declaration
+ R"(test.wgsl:1:24 error: missing initializer for 'var' declaration
fn f() { var a : u32 = >; }
^
)");
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc
index 26f3298fd5f..a8d78733bc6 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc
@@ -24,7 +24,7 @@ using ForStmtTest = ParserImplTest;
// Test an empty for loop.
TEST_F(ForStmtTest, Empty) {
auto p = parser("for (;;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -37,27 +37,27 @@ TEST_F(ForStmtTest, Empty) {
// Test a for loop with non-empty body.
TEST_F(ForStmtTest, Body) {
auto p = parser("for (;;) { discard; }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
EXPECT_EQ(fl->initializer, nullptr);
EXPECT_EQ(fl->condition, nullptr);
EXPECT_EQ(fl->continuing, nullptr);
- ASSERT_EQ(fl->body->statements.size(), 1u);
+ ASSERT_EQ(fl->body->statements.Length(), 1u);
EXPECT_TRUE(fl->body->statements[0]->Is<ast::DiscardStatement>());
}
// Test a for loop declaring a variable in the initializer statement.
TEST_F(ForStmtTest, InitializerStatementDecl) {
auto p = parser("for (var i: i32 ;;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
- EXPECT_FALSE(var->is_const);
+ EXPECT_TRUE(var->Is<ast::Var>());
EXPECT_EQ(var->constructor, nullptr);
EXPECT_EQ(fl->condition, nullptr);
EXPECT_EQ(fl->continuing, nullptr);
@@ -68,13 +68,13 @@ TEST_F(ForStmtTest, InitializerStatementDecl) {
// statement.
TEST_F(ForStmtTest, InitializerStatementDeclEqual) {
auto p = parser("for (var i: i32 = 0 ;;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
- EXPECT_FALSE(var->is_const);
+ EXPECT_TRUE(var->Is<ast::Var>());
EXPECT_NE(var->constructor, nullptr);
EXPECT_EQ(fl->condition, nullptr);
EXPECT_EQ(fl->continuing, nullptr);
@@ -84,13 +84,13 @@ TEST_F(ForStmtTest, InitializerStatementDeclEqual) {
// Test a for loop declaring a const variable in the initializer statement.
TEST_F(ForStmtTest, InitializerStatementConstDecl) {
auto p = parser("for (let i: i32 = 0 ;;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
- EXPECT_TRUE(var->is_const);
+ EXPECT_TRUE(var->Is<ast::Let>());
EXPECT_NE(var->constructor, nullptr);
EXPECT_EQ(fl->condition, nullptr);
EXPECT_EQ(fl->continuing, nullptr);
@@ -100,7 +100,7 @@ TEST_F(ForStmtTest, InitializerStatementConstDecl) {
// Test a for loop assigning a variable in the initializer statement.
TEST_F(ForStmtTest, InitializerStatementAssignment) {
auto p = parser("for (i = 0 ;;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -113,7 +113,7 @@ TEST_F(ForStmtTest, InitializerStatementAssignment) {
// Test a for loop incrementing a variable in the initializer statement.
TEST_F(ForStmtTest, InitializerStatementIncrement) {
auto p = parser("for (i++;;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -126,7 +126,7 @@ TEST_F(ForStmtTest, InitializerStatementIncrement) {
// Test a for loop calling a function in the initializer statement.
TEST_F(ForStmtTest, InitializerStatementFuncCall) {
auto p = parser("for (a(b,c) ;;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -139,7 +139,7 @@ TEST_F(ForStmtTest, InitializerStatementFuncCall) {
// Test a for loop with a break condition
TEST_F(ForStmtTest, BreakCondition) {
auto p = parser("for (; 0 == 1;) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -152,7 +152,7 @@ TEST_F(ForStmtTest, BreakCondition) {
// Test a for loop assigning a variable in the continuing statement.
TEST_F(ForStmtTest, ContinuingAssignment) {
auto p = parser("for (;; x = 2) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -165,7 +165,7 @@ TEST_F(ForStmtTest, ContinuingAssignment) {
// Test a for loop with an increment statement as the continuing statement.
TEST_F(ForStmtTest, ContinuingIncrement) {
auto p = parser("for (;; x++) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -178,7 +178,7 @@ TEST_F(ForStmtTest, ContinuingIncrement) {
// Test a for loop calling a function in the continuing statement.
TEST_F(ForStmtTest, ContinuingFuncCall) {
auto p = parser("for (;; a(b,c)) { }");
- auto fl = p->for_stmt();
+ auto fl = p->for_statement();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(fl.errored);
ASSERT_TRUE(fl.matched);
@@ -192,7 +192,7 @@ class ForStmtErrorTest : public ParserImplTest {
public:
void TestForWithError(std::string for_str, std::string error_str) {
auto p_for = parser(for_str);
- auto e_for = p_for->for_stmt();
+ auto e_for = p_for->for_statement();
EXPECT_FALSE(e_for.matched);
EXPECT_TRUE(e_for.errored);
@@ -253,7 +253,7 @@ TEST_F(ForStmtErrorTest, MissingRightBrace) {
// Test a for loop with an invalid initializer statement.
TEST_F(ForStmtErrorTest, InvalidInitializerAsConstDecl) {
std::string for_str = "for (let x: i32;;) { }";
- std::string error_str = "1:16: expected '=' for let declaration";
+ std::string error_str = "1:16: expected '=' for 'let' declaration";
TestForWithError(for_str, error_str);
}
@@ -304,7 +304,7 @@ TEST_F(ForStmtErrorTest, InvalidContinuingMatch) {
// Test a for loop with an invalid body.
TEST_F(ForStmtErrorTest, InvalidBody) {
std::string for_str = "for (;;) { let x: i32; }";
- std::string error_str = "1:22: expected '=' for let declaration";
+ std::string error_str = "1:22: expected '=' for 'let' declaration";
TestForWithError(for_str, error_str);
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
index 0773ffd362e..28b84a9767b 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
@@ -25,7 +25,7 @@ TEST_F(ParserImplTest, AttributeList_Parses_Stage) {
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched);
- ASSERT_EQ(attrs.value.size(), 2u);
+ ASSERT_EQ(attrs.value.Length(), 2u);
auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
@@ -51,7 +51,7 @@ TEST_F(ParserImplTest, AttributeList_Parses) {
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched);
- ASSERT_EQ(attrs.value.size(), 2u);
+ ASSERT_EQ(attrs.value.Length(), 2u);
auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
@@ -77,7 +77,7 @@ TEST_F(ParserImplTest, AttributeList_Invalid) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_TRUE(attrs.value.empty());
+ EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:2: expected attribute");
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
index 44f3d783725..8e56ee79520 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
@@ -41,6 +41,38 @@ TEST_F(ParserImplTest, Attribute_Workgroup) {
EXPECT_EQ(values[2], nullptr);
}
+TEST_F(ParserImplTest, Attribute_Workgroup_1Param_TrailingComma) {
+ auto p = parser("workgroup_size(4,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr) << p->error();
+ ASSERT_FALSE(p->has_error());
+ auto* func_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(func_attr, nullptr);
+ ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
+
+ auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
+
+ ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+ EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 4);
+ EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+ ast::IntLiteralExpression::Suffix::kNone);
+
+ EXPECT_EQ(values[1], nullptr);
+ EXPECT_EQ(values[2], nullptr);
+}
+
+TEST_F(ParserImplTest, Attribute_Workgroup_1Param_TrailingComma_Double) {
+ auto p = parser("workgroup_size(4,,)");
+ auto attr = p->attribute();
+ EXPECT_FALSE(attr.matched);
+ EXPECT_TRUE(attr.errored);
+ EXPECT_EQ(attr.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:18: expected workgroup_size y parameter");
+}
+
TEST_F(ParserImplTest, Attribute_Workgroup_2Param) {
auto p = parser("workgroup_size(4, 5)");
auto attr = p->attribute();
@@ -67,6 +99,42 @@ TEST_F(ParserImplTest, Attribute_Workgroup_2Param) {
EXPECT_EQ(values[2], nullptr);
}
+TEST_F(ParserImplTest, Attribute_Workgroup_2Param_TrailingComma) {
+ auto p = parser("workgroup_size(4, 5,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr) << p->error();
+ ASSERT_FALSE(p->has_error());
+ auto* func_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(func_attr, nullptr) << p->error();
+ ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
+
+ auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
+
+ ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+ EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 4);
+ EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+ ast::IntLiteralExpression::Suffix::kNone);
+
+ ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+ EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 5);
+ EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->suffix,
+ ast::IntLiteralExpression::Suffix::kNone);
+
+ EXPECT_EQ(values[2], nullptr);
+}
+
+TEST_F(ParserImplTest, Attribute_Workgroup21Param_TrailingComma_Double) {
+ auto p = parser("workgroup_size(4,5,,)");
+ auto attr = p->attribute();
+ EXPECT_FALSE(attr.matched);
+ EXPECT_TRUE(attr.errored);
+ EXPECT_EQ(attr.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:20: expected workgroup_size z parameter");
+}
+
TEST_F(ParserImplTest, Attribute_Workgroup_3Param) {
auto p = parser("workgroup_size(4, 5, 6)");
auto attr = p->attribute();
@@ -96,6 +164,35 @@ TEST_F(ParserImplTest, Attribute_Workgroup_3Param) {
ast::IntLiteralExpression::Suffix::kNone);
}
+TEST_F(ParserImplTest, Attribute_Workgroup_3Param_TrailingComma) {
+ auto p = parser("workgroup_size(4, 5, 6,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr) << p->error();
+ ASSERT_FALSE(p->has_error());
+ auto* func_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(func_attr, nullptr);
+ ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
+
+ auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
+
+ ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+ EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 4);
+ EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+ ast::IntLiteralExpression::Suffix::kNone);
+
+ ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+ EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 5);
+ EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->suffix,
+ ast::IntLiteralExpression::Suffix::kNone);
+
+ ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
+ EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->value, 6);
+ EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->suffix,
+ ast::IntLiteralExpression::Suffix::kNone);
+}
+
TEST_F(ParserImplTest, Attribute_Workgroup_WithIdent) {
auto p = parser("workgroup_size(4, height)");
auto attr = p->attribute();
@@ -129,7 +226,7 @@ TEST_F(ParserImplTest, Attribute_Workgroup_TooManyValues) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size attribute");
+ EXPECT_EQ(p->error(), "1:25: expected ')' for workgroup_size attribute");
}
TEST_F(ParserImplTest, Attribute_Workgroup_MissingLeftParam) {
@@ -202,16 +299,6 @@ TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Z_Comma) {
EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size attribute");
}
-TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Z_Value) {
- auto p = parser("workgroup_size(1, 2, )");
- auto attr = p->attribute();
- EXPECT_FALSE(attr.matched);
- EXPECT_TRUE(attr.errored);
- EXPECT_EQ(attr.value, nullptr);
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:22: expected workgroup_size z parameter");
-}
-
// TODO(crbug.com/tint/1503): Remove when @stage is removed
TEST_F(ParserImplTest, Attribute_Stage) {
auto p = parser("stage(compute)");
@@ -263,7 +350,8 @@ TEST_F(ParserImplTest, Attribute_Stage_MissingRightParen) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:14: expected ')' for stage attribute");
+ EXPECT_EQ(p->error(), R"(1:1: use of deprecated language feature: remove stage and use @compute
+1:14: expected ')' for stage attribute)");
}
TEST_F(ParserImplTest, Attribute_Compute) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
index 4d7857b0407..cba4a7d6c59 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
@@ -35,7 +35,7 @@ TEST_F(ParserImplTest, FunctionDecl) {
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
- ASSERT_EQ(f->params.size(), 2u);
+ ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
@@ -43,7 +43,7 @@ TEST_F(ParserImplTest, FunctionDecl) {
EXPECT_TRUE(f->return_type->Is<ast::Void>());
auto* body = f->body;
- ASSERT_EQ(body->statements.size(), 1u);
+ ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
}
@@ -80,7 +80,7 @@ TEST_F(ParserImplTest, FunctionDecl_Unicode) {
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
- ASSERT_EQ(f->params.size(), 2u);
+ ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get(param_a_ident));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get(param_b_ident));
@@ -88,7 +88,7 @@ TEST_F(ParserImplTest, FunctionDecl_Unicode) {
EXPECT_TRUE(f->return_type->Is<ast::Void>());
auto* body = f->body;
- ASSERT_EQ(body->statements.size(), 1u);
+ ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
}
@@ -107,10 +107,10 @@ TEST_F(ParserImplTest, FunctionDecl_AttributeList) {
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
- ASSERT_EQ(f->params.size(), 0u);
+ ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes;
- ASSERT_EQ(attributes.size(), 1u);
+ ASSERT_EQ(attributes.Length(), 1u);
ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
@@ -131,7 +131,7 @@ TEST_F(ParserImplTest, FunctionDecl_AttributeList) {
ast::IntLiteralExpression::Suffix::kNone);
auto* body = f->body;
- ASSERT_EQ(body->statements.size(), 1u);
+ ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
}
@@ -152,10 +152,10 @@ fn main() { return; })");
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
- ASSERT_EQ(f->params.size(), 0u);
+ ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes;
- ASSERT_EQ(attributes.size(), 2u);
+ ASSERT_EQ(attributes.Length(), 2u);
ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
@@ -179,7 +179,7 @@ fn main() { return; })");
EXPECT_EQ(attributes[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
auto* body = f->body;
- ASSERT_EQ(body->statements.size(), 1u);
+ ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
}
@@ -201,10 +201,10 @@ fn main() { return; })");
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
- ASSERT_EQ(f->params.size(), 0u);
+ ASSERT_EQ(f->params.Length(), 0u);
auto& attrs = f->attributes;
- ASSERT_EQ(attrs.size(), 2u);
+ ASSERT_EQ(attrs.Length(), 2u);
ASSERT_TRUE(attrs[0]->Is<ast::WorkgroupAttribute>());
auto values = attrs[0]->As<ast::WorkgroupAttribute>()->Values();
@@ -228,7 +228,7 @@ fn main() { return; })");
EXPECT_EQ(attrs[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
auto* body = f->body;
- ASSERT_EQ(body->statements.size(), 1u);
+ ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
}
@@ -247,19 +247,19 @@ TEST_F(ParserImplTest, FunctionDecl_ReturnTypeAttributeList) {
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::F32>());
- ASSERT_EQ(f->params.size(), 0u);
+ ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes;
- EXPECT_EQ(attributes.size(), 0u);
+ EXPECT_EQ(attributes.Length(), 0u);
auto& ret_type_attributes = f->return_type_attributes;
- ASSERT_EQ(ret_type_attributes.size(), 1u);
+ ASSERT_EQ(ret_type_attributes.Length(), 1u);
auto* loc = ret_type_attributes[0]->As<ast::LocationAttribute>();
ASSERT_TRUE(loc != nullptr);
EXPECT_EQ(loc->value, 1u);
auto* body = f->body;
- ASSERT_EQ(body->statements.size(), 1u);
+ ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_header_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_header_test.cc
index 6f2e6cbf976..1a8704e523a 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_header_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_function_header_test.cc
@@ -25,7 +25,7 @@ TEST_F(ParserImplTest, FunctionHeader) {
EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main");
- ASSERT_EQ(f->params.size(), 2u);
+ ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
EXPECT_TRUE(f->return_type->Is<ast::Void>());
@@ -38,7 +38,7 @@ TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main");
- ASSERT_EQ(f->params.size(), 1u);
+ ASSERT_EQ(f->params.Length(), 1u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_TRUE(f->return_type->Is<ast::Void>());
}
@@ -51,9 +51,9 @@ TEST_F(ParserImplTest, FunctionHeader_AttributeReturnType) {
EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main");
- EXPECT_EQ(f->params.size(), 0u);
+ EXPECT_EQ(f->params.Length(), 0u);
EXPECT_TRUE(f->return_type->Is<ast::F32>());
- ASSERT_EQ(f->return_type_attributes.size(), 1u);
+ ASSERT_EQ(f->return_type_attributes.Length(), 1u);
auto* loc = f->return_type_attributes[0]->As<ast::LocationAttribute>();
ASSERT_TRUE(loc != nullptr);
EXPECT_EQ(loc->value, 1u);
@@ -67,9 +67,9 @@ TEST_F(ParserImplTest, FunctionHeader_InvariantReturnType) {
EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main");
- EXPECT_EQ(f->params.size(), 0u);
+ EXPECT_EQ(f->params.Length(), 0u);
EXPECT_TRUE(f->return_type->Is<ast::F32>());
- ASSERT_EQ(f->return_type_attributes.size(), 1u);
+ ASSERT_EQ(f->return_type_attributes.Length(), 1u);
EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>());
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
index 7a5bb452d75..46bfa345286 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -18,7 +18,7 @@
namespace tint::reader::wgsl {
namespace {
-TEST_F(ParserImplTest, GlobalConstantDecl) {
+TEST_F(ParserImplTest, GlobalLetDecl) {
auto p = parser("let a : f32 = 1.");
auto attrs = p->attribute_list();
EXPECT_FALSE(attrs.errored);
@@ -27,24 +27,23 @@ TEST_F(ParserImplTest, GlobalConstantDecl) {
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* const_ = e.value->As<ast::Const>();
+ ASSERT_NE(const_, nullptr);
- EXPECT_TRUE(e->is_const);
- EXPECT_FALSE(e->is_overridable);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- ASSERT_NE(e->type, nullptr);
- EXPECT_TRUE(e->type->Is<ast::F32>());
+ EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
+ ASSERT_NE(const_->type, nullptr);
+ EXPECT_TRUE(const_->type->Is<ast::F32>());
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 5u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 6u);
+ EXPECT_EQ(const_->source.range.begin.line, 1u);
+ EXPECT_EQ(const_->source.range.begin.column, 5u);
+ EXPECT_EQ(const_->source.range.end.line, 1u);
+ EXPECT_EQ(const_->source.range.end.column, 6u);
- ASSERT_NE(e->constructor, nullptr);
- EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+ ASSERT_NE(const_->constructor, nullptr);
+ EXPECT_TRUE(const_->constructor->Is<ast::LiteralExpression>());
}
-TEST_F(ParserImplTest, GlobalConstantDecl_Inferred) {
+TEST_F(ParserImplTest, GlobalLetDecl_Inferred) {
auto p = parser("let a = 1.");
auto attrs = p->attribute_list();
EXPECT_FALSE(attrs.errored);
@@ -53,23 +52,22 @@ TEST_F(ParserImplTest, GlobalConstantDecl_Inferred) {
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* const_ = e.value->As<ast::Const>();
+ ASSERT_NE(const_, nullptr);
- EXPECT_TRUE(e->is_const);
- EXPECT_FALSE(e->is_overridable);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- EXPECT_EQ(e->type, nullptr);
+ EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
+ EXPECT_EQ(const_->type, nullptr);
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 5u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 6u);
+ EXPECT_EQ(const_->source.range.begin.line, 1u);
+ EXPECT_EQ(const_->source.range.begin.column, 5u);
+ EXPECT_EQ(const_->source.range.end.line, 1u);
+ EXPECT_EQ(const_->source.range.end.column, 6u);
- ASSERT_NE(e->constructor, nullptr);
- EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+ ASSERT_NE(const_->constructor, nullptr);
+ EXPECT_TRUE(const_->constructor->Is<ast::LiteralExpression>());
}
-TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
+TEST_F(ParserImplTest, GlobalLetDecl_InvalidExpression) {
auto p = parser("let a : f32 = if (a) {}");
auto attrs = p->attribute_list();
EXPECT_FALSE(attrs.errored);
@@ -79,10 +77,13 @@ TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
+ EXPECT_EQ(
+ p->error(),
+ R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:15: missing initializer for 'let' declaration)");
}
-TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
+TEST_F(ParserImplTest, GlobalLetDecl_MissingExpression) {
auto p = parser("let a : f32 =");
auto attrs = p->attribute_list();
EXPECT_FALSE(attrs.errored);
@@ -92,10 +93,88 @@ TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:14: unable to parse const_expr");
+ EXPECT_EQ(
+ p->error(),
+ R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:14: missing initializer for 'let' declaration)");
}
-TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {
+TEST_F(ParserImplTest, GlobalConstDecl) {
+ auto p = parser("const a : f32 = 1.");
+ auto attrs = p->attribute_list();
+ EXPECT_FALSE(attrs.errored);
+ EXPECT_FALSE(attrs.matched);
+ auto e = p->global_constant_decl(attrs.value);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ auto* c = e.value->As<ast::Const>();
+ ASSERT_NE(c, nullptr);
+
+ EXPECT_EQ(c->symbol, p->builder().Symbols().Get("a"));
+ ASSERT_NE(c->type, nullptr);
+ EXPECT_TRUE(c->type->Is<ast::F32>());
+
+ EXPECT_EQ(c->source.range.begin.line, 1u);
+ EXPECT_EQ(c->source.range.begin.column, 7u);
+ EXPECT_EQ(c->source.range.end.line, 1u);
+ EXPECT_EQ(c->source.range.end.column, 8u);
+
+ ASSERT_NE(c->constructor, nullptr);
+ EXPECT_TRUE(c->constructor->Is<ast::LiteralExpression>());
+}
+
+TEST_F(ParserImplTest, GlobalConstDecl_Inferred) {
+ auto p = parser("const a = 1.");
+ auto attrs = p->attribute_list();
+ EXPECT_FALSE(attrs.errored);
+ EXPECT_FALSE(attrs.matched);
+ auto e = p->global_constant_decl(attrs.value);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ auto* c = e.value->As<ast::Const>();
+ ASSERT_NE(c, nullptr);
+
+ EXPECT_EQ(c->symbol, p->builder().Symbols().Get("a"));
+ EXPECT_EQ(c->type, nullptr);
+
+ EXPECT_EQ(c->source.range.begin.line, 1u);
+ EXPECT_EQ(c->source.range.begin.column, 7u);
+ EXPECT_EQ(c->source.range.end.line, 1u);
+ EXPECT_EQ(c->source.range.end.column, 8u);
+
+ ASSERT_NE(c->constructor, nullptr);
+ EXPECT_TRUE(c->constructor->Is<ast::LiteralExpression>());
+}
+
+TEST_F(ParserImplTest, GlobalConstDecl_InvalidExpression) {
+ auto p = parser("const a : f32 = if (a) {}");
+ auto attrs = p->attribute_list();
+ EXPECT_FALSE(attrs.errored);
+ EXPECT_FALSE(attrs.matched);
+ auto e = p->global_constant_decl(attrs.value);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_TRUE(e.errored);
+ EXPECT_FALSE(e.matched);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:17: missing initializer for 'const' declaration");
+}
+
+TEST_F(ParserImplTest, GlobalConstDecl_MissingExpression) {
+ auto p = parser("const a : f32 =");
+ auto attrs = p->attribute_list();
+ EXPECT_FALSE(attrs.errored);
+ EXPECT_FALSE(attrs.matched);
+ auto e = p->global_constant_decl(attrs.value);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_TRUE(e.errored);
+ EXPECT_FALSE(e.matched);
+ EXPECT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:16: missing initializer for 'const' declaration");
+}
+
+TEST_F(ParserImplTest, GlobalOverrideDecl_WithId) {
auto p = parser("@id(7) override a : f32 = 1.");
auto attrs = p->attribute_list();
EXPECT_FALSE(attrs.errored);
@@ -105,28 +184,57 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* override = e.value->As<ast::Override>();
+ ASSERT_NE(override, nullptr);
+
+ EXPECT_EQ(override->symbol, p->builder().Symbols().Get("a"));
+ ASSERT_NE(override->type, nullptr);
+ EXPECT_TRUE(override->type->Is<ast::F32>());
+
+ EXPECT_EQ(override->source.range.begin.line, 1u);
+ EXPECT_EQ(override->source.range.begin.column, 17u);
+ EXPECT_EQ(override->source.range.end.line, 1u);
+ EXPECT_EQ(override->source.range.end.column, 18u);
+
+ ASSERT_NE(override->constructor, nullptr);
+ EXPECT_TRUE(override->constructor->Is<ast::LiteralExpression>());
+
+ auto* override_attr = ast::GetAttribute<ast::IdAttribute>(override->attributes);
+ ASSERT_NE(override_attr, nullptr);
+ EXPECT_EQ(override_attr->value, 7u);
+}
+
+TEST_F(ParserImplTest, GlobalOverrideDecl_WithId_TrailingComma) {
+ auto p = parser("@id(7,) override a : f32 = 1.");
+ auto attrs = p->attribute_list();
+ EXPECT_FALSE(attrs.errored);
+ EXPECT_TRUE(attrs.matched);
+
+ auto e = p->global_constant_decl(attrs.value);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+ auto* override = e.value->As<ast::Override>();
+ ASSERT_NE(override, nullptr);
- EXPECT_TRUE(e->is_const);
- EXPECT_TRUE(e->is_overridable);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- ASSERT_NE(e->type, nullptr);
- EXPECT_TRUE(e->type->Is<ast::F32>());
+ EXPECT_EQ(override->symbol, p->builder().Symbols().Get("a"));
+ ASSERT_NE(override->type, nullptr);
+ EXPECT_TRUE(override->type->Is<ast::F32>());
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 17u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 18u);
+ EXPECT_EQ(override->source.range.begin.line, 1u);
+ EXPECT_EQ(override->source.range.begin.column, 18u);
+ EXPECT_EQ(override->source.range.end.line, 1u);
+ EXPECT_EQ(override->source.range.end.column, 19u);
- ASSERT_NE(e->constructor, nullptr);
- EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+ ASSERT_NE(override->constructor, nullptr);
+ EXPECT_TRUE(override->constructor->Is<ast::LiteralExpression>());
- auto* override_attr = ast::GetAttribute<ast::IdAttribute>(e.value->attributes);
+ auto* override_attr = ast::GetAttribute<ast::IdAttribute>(override->attributes);
ASSERT_NE(override_attr, nullptr);
EXPECT_EQ(override_attr->value, 7u);
}
-TEST_F(ParserImplTest, GlobalConstantDec_Override_WithoutId) {
+TEST_F(ParserImplTest, GlobalOverrideDecl_WithoutId) {
auto p = parser("override a : f32 = 1.");
auto attrs = p->attribute_list();
EXPECT_FALSE(attrs.errored);
@@ -136,27 +244,26 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_WithoutId) {
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* override = e.value->As<ast::Override>();
+ ASSERT_NE(override, nullptr);
- EXPECT_TRUE(e->is_const);
- EXPECT_TRUE(e->is_overridable);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- ASSERT_NE(e->type, nullptr);
- EXPECT_TRUE(e->type->Is<ast::F32>());
+ EXPECT_EQ(override->symbol, p->builder().Symbols().Get("a"));
+ ASSERT_NE(override->type, nullptr);
+ EXPECT_TRUE(override->type->Is<ast::F32>());
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 10u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 11u);
+ EXPECT_EQ(override->source.range.begin.line, 1u);
+ EXPECT_EQ(override->source.range.begin.column, 10u);
+ EXPECT_EQ(override->source.range.end.line, 1u);
+ EXPECT_EQ(override->source.range.end.column, 11u);
- ASSERT_NE(e->constructor, nullptr);
- EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+ ASSERT_NE(override->constructor, nullptr);
+ EXPECT_TRUE(override->constructor->Is<ast::LiteralExpression>());
- auto* id_attr = ast::GetAttribute<ast::IdAttribute>(e.value->attributes);
+ auto* id_attr = ast::GetAttribute<ast::IdAttribute>(override->attributes);
ASSERT_EQ(id_attr, nullptr);
}
-TEST_F(ParserImplTest, GlobalConstantDec_Override_MissingId) {
+TEST_F(ParserImplTest, GlobalOverrideDecl_MissingId) {
auto p = parser("@id() override a : f32 = 1.");
auto attrs = p->attribute_list();
EXPECT_TRUE(attrs.errored);
@@ -165,13 +272,14 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_MissingId) {
auto e = p->global_constant_decl(attrs.value);
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* override = e.value->As<ast::Override>();
+ ASSERT_NE(override, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:5: expected signed integer literal for id attribute");
}
-TEST_F(ParserImplTest, GlobalConstantDec_Override_InvalidId) {
+TEST_F(ParserImplTest, GlobalOverrideDecl_InvalidId) {
auto p = parser("@id(-7) override a : f32 = 1.");
auto attrs = p->attribute_list();
EXPECT_TRUE(attrs.errored);
@@ -180,7 +288,8 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_InvalidId) {
auto e = p->global_constant_decl(attrs.value);
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* override = e.value->As<ast::Override>();
+ ASSERT_NE(override, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:5: id attribute must be positive");
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
index e2c7d7ad6d6..6c943c84de6 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
@@ -29,17 +29,24 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) {
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
- ASSERT_EQ(program.AST().GlobalVariables().size(), 1u);
+ ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
auto* v = program.AST().GlobalVariables()[0];
EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
+ EXPECT_TRUE(Is<ast::Vector>(v->type));
}
-TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_Inferred_Invalid) {
+TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_Inferred) {
auto p = parser("var<private> a = vec2<i32>(1, 2);");
p->global_decl();
- ASSERT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:16: expected ':' for variable declaration");
+ ASSERT_FALSE(p->has_error()) << p->error();
+
+ auto program = p->program();
+ ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
+
+ auto* v = program.AST().GlobalVariables()[0];
+ EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
+ EXPECT_EQ(v->type, nullptr);
}
TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) {
@@ -49,30 +56,79 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) {
EXPECT_EQ(p->error(), "1:27: expected ';' for variable declaration");
}
-TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
+TEST_F(ParserImplTest, GlobalDecl_GlobalLet) {
auto p = parser("let a : i32 = 2;");
p->global_decl();
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
- ASSERT_EQ(program.AST().GlobalVariables().size(), 1u);
+ ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
auto* v = program.AST().GlobalVariables()[0];
EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
}
-TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_Invalid) {
+TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingInitializer) {
+ auto p = parser("let a : vec2<i32>;");
+ p->global_decl();
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(
+ p->error(),
+ R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:18: expected '=' for 'let' declaration)");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_GlobalLet_Invalid) {
auto p = parser("let a : vec2<i32> 1.0;");
p->global_decl();
ASSERT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:19: expected ';' for let declaration");
+ EXPECT_EQ(
+ p->error(),
+ R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:19: expected '=' for 'let' declaration)");
}
-TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) {
+TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingSemicolon) {
auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
p->global_decl();
ASSERT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:36: expected ';' for let declaration");
+ EXPECT_EQ(
+ p->error(),
+ R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:36: expected ';' for 'const' declaration)");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_GlobalConst) {
+ auto p = parser("const a : i32 = 2;");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error()) << p->error();
+
+ auto program = p->program();
+ ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
+
+ auto* v = program.AST().GlobalVariables()[0];
+ EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
+}
+
+TEST_F(ParserImplTest, GlobalDecl_GlobalConst_MissingInitializer) {
+ auto p = parser("const a : vec2<i32>;");
+ p->global_decl();
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:20: expected '=' for 'const' declaration");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_GlobalConst_Invalid) {
+ auto p = parser("const a : vec2<i32> 1.0;");
+ p->global_decl();
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:21: expected '=' for 'const' declaration");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_GlobalConst_MissingSemicolon) {
+ auto p = parser("const a : vec2<i32> = vec2<i32>(1, 2)");
+ p->global_decl();
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:38: expected ';' for 'const' declaration");
}
TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
@@ -81,7 +137,7 @@ TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
- ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
+ ASSERT_EQ(program.AST().TypeDecls().Length(), 1u);
ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>());
EXPECT_EQ(program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name), "A");
}
@@ -96,7 +152,7 @@ type B = A;)");
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
- ASSERT_EQ(program.AST().TypeDecls().size(), 2u);
+ ASSERT_EQ(program.AST().TypeDecls().Length(), 2u);
ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>());
auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>();
EXPECT_EQ(str->name, program.Symbols().Get("A"));
@@ -122,7 +178,7 @@ TEST_F(ParserImplTest, GlobalDecl_Function) {
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
- ASSERT_EQ(program.AST().Functions().size(), 1u);
+ ASSERT_EQ(program.AST().Functions().Length(), 1u);
EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main");
}
@@ -132,7 +188,7 @@ TEST_F(ParserImplTest, GlobalDecl_Function_WithAttribute) {
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
- ASSERT_EQ(program.AST().Functions().size(), 1u);
+ ASSERT_EQ(program.AST().Functions().Length(), 1u);
EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main");
}
@@ -149,7 +205,7 @@ TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
- ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
+ ASSERT_EQ(program.AST().TypeDecls().Length(), 1u);
auto* t = program.AST().TypeDecls()[0];
ASSERT_NE(t, nullptr);
@@ -157,7 +213,7 @@ TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
auto* str = t->As<ast::Struct>();
EXPECT_EQ(str->name, program.Symbols().Get("A"));
- EXPECT_EQ(str->members.size(), 2u);
+ EXPECT_EQ(str->members.Length(), 2u);
}
TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) {
@@ -177,5 +233,58 @@ TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) {
}
}
+TEST_F(ParserImplTest, GlobalDecl_Struct_UnexpectedAttribute) {
+ auto p = parser("@vertex struct S { i : i32 }");
+
+ auto s = p->global_decl();
+ EXPECT_TRUE(s.errored);
+ EXPECT_FALSE(s.matched);
+
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:2: unexpected attributes");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_StaticAssert_WithParen) {
+ auto p = parser("static_assert(true);");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error()) << p->error();
+
+ auto program = p->program();
+ ASSERT_EQ(program.AST().StaticAsserts().Length(), 1u);
+ auto* sa = program.AST().StaticAsserts()[0];
+ EXPECT_EQ(sa->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->source.range.begin.column, 1u);
+ EXPECT_EQ(sa->source.range.end.line, 1u);
+ EXPECT_EQ(sa->source.range.end.column, 20u);
+
+ EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
+ EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.begin.column, 15u);
+ EXPECT_EQ(sa->condition->source.range.end.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.end.column, 19u);
+}
+
+TEST_F(ParserImplTest, GlobalDecl_StaticAssert_WithoutParen) {
+ auto p = parser("static_assert true;");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error()) << p->error();
+
+ auto program = p->program();
+ ASSERT_EQ(program.AST().StaticAsserts().Length(), 1u);
+ auto* sa = program.AST().StaticAsserts()[0];
+ EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
+
+ EXPECT_EQ(sa->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->source.range.begin.column, 1u);
+ EXPECT_EQ(sa->source.range.end.line, 1u);
+ EXPECT_EQ(sa->source.range.end.column, 20u);
+
+ EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
+ EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.begin.column, 16u);
+ EXPECT_EQ(sa->condition->source.range.end.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.end.column, 20u);
+}
+
} // namespace
} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
index 57f90b95734..85f4702d8bd 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -26,18 +26,19 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) {
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* var = e.value->As<ast::Var>();
+ ASSERT_NE(var, nullptr);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- EXPECT_TRUE(e->type->Is<ast::F32>());
- EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kPrivate);
+ EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
+ EXPECT_TRUE(var->type->Is<ast::F32>());
+ EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kPrivate);
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 14u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 15u);
+ EXPECT_EQ(var->source.range.begin.line, 1u);
+ EXPECT_EQ(var->source.range.begin.column, 14u);
+ EXPECT_EQ(var->source.range.end.line, 1u);
+ EXPECT_EQ(var->source.range.end.column, 15u);
- ASSERT_EQ(e->constructor, nullptr);
+ ASSERT_EQ(var->constructor, nullptr);
}
TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
@@ -49,19 +50,20 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* var = e.value->As<ast::Var>();
+ ASSERT_NE(var, nullptr);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- EXPECT_TRUE(e->type->Is<ast::F32>());
- EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kPrivate);
+ EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
+ EXPECT_TRUE(var->type->Is<ast::F32>());
+ EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kPrivate);
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 14u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 15u);
+ EXPECT_EQ(var->source.range.begin.line, 1u);
+ EXPECT_EQ(var->source.range.begin.column, 14u);
+ EXPECT_EQ(var->source.range.end.line, 1u);
+ EXPECT_EQ(var->source.range.end.column, 15u);
- ASSERT_NE(e->constructor, nullptr);
- ASSERT_TRUE(e->constructor->Is<ast::FloatLiteralExpression>());
+ ASSERT_NE(var->constructor, nullptr);
+ ASSERT_TRUE(var->constructor->Is<ast::FloatLiteralExpression>());
}
TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute) {
@@ -73,22 +75,23 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute) {
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* var = e.value->As<ast::Var>();
+ ASSERT_NE(var, nullptr);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- ASSERT_NE(e->type, nullptr);
- EXPECT_TRUE(e->type->Is<ast::F32>());
- EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kUniform);
+ EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
+ ASSERT_NE(var->type, nullptr);
+ EXPECT_TRUE(var->type->Is<ast::F32>());
+ EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kUniform);
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 36u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 37u);
+ EXPECT_EQ(var->source.range.begin.line, 1u);
+ EXPECT_EQ(var->source.range.begin.column, 36u);
+ EXPECT_EQ(var->source.range.end.line, 1u);
+ EXPECT_EQ(var->source.range.end.column, 37u);
- ASSERT_EQ(e->constructor, nullptr);
+ ASSERT_EQ(var->constructor, nullptr);
- auto& attributes = e->attributes;
- ASSERT_EQ(attributes.size(), 2u);
+ auto& attributes = var->attributes;
+ ASSERT_EQ(attributes.Length(), 2u);
ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
}
@@ -103,22 +106,23 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute_MulitpleGroups) {
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
- ASSERT_NE(e.value, nullptr);
+ auto* var = e.value->As<ast::Var>();
+ ASSERT_NE(var, nullptr);
- EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
- ASSERT_NE(e->type, nullptr);
- EXPECT_TRUE(e->type->Is<ast::F32>());
- EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kUniform);
+ EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
+ ASSERT_NE(var->type, nullptr);
+ EXPECT_TRUE(var->type->Is<ast::F32>());
+ EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kUniform);
- EXPECT_EQ(e->source.range.begin.line, 1u);
- EXPECT_EQ(e->source.range.begin.column, 36u);
- EXPECT_EQ(e->source.range.end.line, 1u);
- EXPECT_EQ(e->source.range.end.column, 37u);
+ EXPECT_EQ(var->source.range.begin.line, 1u);
+ EXPECT_EQ(var->source.range.begin.column, 36u);
+ EXPECT_EQ(var->source.range.end.line, 1u);
+ EXPECT_EQ(var->source.range.end.column, 37u);
- ASSERT_EQ(e->constructor, nullptr);
+ ASSERT_EQ(var->constructor, nullptr);
- auto& attributes = e->attributes;
- ASSERT_EQ(attributes.size(), 2u);
+ auto& attributes = var->attributes;
+ ASSERT_EQ(attributes.Length(), 2u);
ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
}
@@ -148,7 +152,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:24: invalid type for const_expr");
+ EXPECT_EQ(p->error(), "1:24: missing initializer for 'var' declaration");
}
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
index b9e5566d61a..59e5ad38ba2 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, IfStmt) {
auto p = parser("if a == 4 { a = b; c = d; }");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -28,13 +28,13 @@ TEST_F(ParserImplTest, IfStmt) {
ASSERT_TRUE(e->Is<ast::IfStatement>());
ASSERT_NE(e->condition, nullptr);
ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
- EXPECT_EQ(e->body->statements.size(), 2u);
+ EXPECT_EQ(e->body->statements.Length(), 2u);
EXPECT_EQ(e->else_statement, nullptr);
}
TEST_F(ParserImplTest, IfStmt_WithElse) {
auto p = parser("if a == 4 { a = b; c = d; } else if(c) { d = 2; } else {}");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -43,21 +43,21 @@ TEST_F(ParserImplTest, IfStmt_WithElse) {
ASSERT_TRUE(e->Is<ast::IfStatement>());
ASSERT_NE(e->condition, nullptr);
ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
- EXPECT_EQ(e->body->statements.size(), 2u);
+ EXPECT_EQ(e->body->statements.Length(), 2u);
auto* elseif = As<ast::IfStatement>(e->else_statement);
ASSERT_NE(elseif, nullptr);
ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>());
- EXPECT_EQ(elseif->body->statements.size(), 1u);
+ EXPECT_EQ(elseif->body->statements.Length(), 1u);
auto* el = As<ast::BlockStatement>(elseif->else_statement);
ASSERT_NE(el, nullptr);
- EXPECT_EQ(el->statements.size(), 0u);
+ EXPECT_EQ(el->statements.Length(), 0u);
}
TEST_F(ParserImplTest, IfStmt_WithElse_WithParens) {
auto p = parser("if(a==4) { a = b; c = d; } else if(c) { d = 2; } else {}");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -66,21 +66,21 @@ TEST_F(ParserImplTest, IfStmt_WithElse_WithParens) {
ASSERT_TRUE(e->Is<ast::IfStatement>());
ASSERT_NE(e->condition, nullptr);
ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
- EXPECT_EQ(e->body->statements.size(), 2u);
+ EXPECT_EQ(e->body->statements.Length(), 2u);
auto* elseif = As<ast::IfStatement>(e->else_statement);
ASSERT_NE(elseif, nullptr);
ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>());
- EXPECT_EQ(elseif->body->statements.size(), 1u);
+ EXPECT_EQ(elseif->body->statements.Length(), 1u);
auto* el = As<ast::BlockStatement>(elseif->else_statement);
ASSERT_NE(el, nullptr);
- EXPECT_EQ(el->statements.size(), 0u);
+ EXPECT_EQ(el->statements.Length(), 0u);
}
TEST_F(ParserImplTest, IfStmt_InvalidCondition) {
auto p = parser("if a = 3 {}");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -90,7 +90,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidCondition) {
TEST_F(ParserImplTest, IfStmt_MissingCondition) {
auto p = parser("if {}");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -100,7 +100,7 @@ TEST_F(ParserImplTest, IfStmt_MissingCondition) {
TEST_F(ParserImplTest, IfStmt_InvalidBody) {
auto p = parser("if a { fn main() {}}");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -110,7 +110,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidBody) {
TEST_F(ParserImplTest, IfStmt_MissingBody) {
auto p = parser("if a");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -120,7 +120,7 @@ TEST_F(ParserImplTest, IfStmt_MissingBody) {
TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
auto p = parser("if a {} else if a { fn main() -> a{}}");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -130,7 +130,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
TEST_F(ParserImplTest, IfStmt_InvalidElse) {
auto p = parser("if a {} else { fn main() -> a{}}");
- auto e = p->if_stmt();
+ auto e = p->if_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
index 80417353295..79220e48e77 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, IncrementDecrementStmt_Increment) {
auto p = parser("a++");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -38,7 +38,7 @@ TEST_F(ParserImplTest, IncrementDecrementStmt_Increment) {
TEST_F(ParserImplTest, IncrementDecrementStmt_Decrement) {
auto p = parser("a--");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -57,7 +57,7 @@ TEST_F(ParserImplTest, IncrementDecrementStmt_Decrement) {
TEST_F(ParserImplTest, IncrementDecrementStmt_Parenthesized) {
auto p = parser("(a)++");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -76,7 +76,7 @@ TEST_F(ParserImplTest, IncrementDecrementStmt_Parenthesized) {
TEST_F(ParserImplTest, IncrementDecrementStmt_ToMember) {
auto p = parser("a.b.c[2].d++");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -121,7 +121,7 @@ TEST_F(ParserImplTest, IncrementDecrementStmt_ToMember) {
TEST_F(ParserImplTest, IncrementDecrementStmt_InvalidLHS) {
auto p = parser("{}++");
- auto e = p->assignment_stmt();
+ auto e = p->variable_updating_statement();
EXPECT_FALSE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_lhs_expression_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_lhs_expression_test.cc
new file mode 100644
index 00000000000..6611f3eee1b
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_lhs_expression_test.cc
@@ -0,0 +1,138 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, LHSExpression_NoPrefix) {
+ auto p = parser("a");
+ auto e = p->lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ ASSERT_NE(e.value, nullptr);
+ ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+}
+
+TEST_F(ParserImplTest, LHSExpression_NoMatch) {
+ auto p = parser("123");
+ auto e = p->lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_FALSE(e.matched);
+ ASSERT_EQ(e.value, nullptr);
+}
+
+TEST_F(ParserImplTest, LHSExpression_And) {
+ auto p = parser("&a");
+ auto e = p->lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ ASSERT_NE(e.value, nullptr);
+ ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+
+ auto* u = e->As<ast::UnaryOpExpression>();
+ EXPECT_EQ(u->op, ast::UnaryOp::kAddressOf);
+ EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
+}
+
+TEST_F(ParserImplTest, LHSExpression_Star) {
+ auto p = parser("*a");
+ auto e = p->lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ ASSERT_NE(e.value, nullptr);
+ ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+
+ auto* u = e->As<ast::UnaryOpExpression>();
+ EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
+ EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
+}
+
+TEST_F(ParserImplTest, LHSExpression_InvalidCoreLHSExpr) {
+ auto p = parser("*123");
+ auto e = p->lhs_expression();
+ ASSERT_TRUE(p->has_error());
+ ASSERT_TRUE(e.errored);
+ EXPECT_FALSE(e.matched);
+ ASSERT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:2: missing expression");
+}
+
+TEST_F(ParserImplTest, LHSExpression_Multiple) {
+ auto p = parser("*&**&&*a");
+ auto e = p->lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ ASSERT_NE(e.value, nullptr);
+
+ std::vector<ast::UnaryOp> results = {ast::UnaryOp::kIndirection, ast::UnaryOp::kAddressOf,
+ ast::UnaryOp::kIndirection, ast::UnaryOp::kIndirection,
+ ast::UnaryOp::kAddressOf, ast::UnaryOp::kAddressOf,
+ ast::UnaryOp::kIndirection};
+
+ auto* expr = e.value;
+ for (auto op : results) {
+ ASSERT_TRUE(expr->Is<ast::UnaryOpExpression>());
+
+ auto* u = expr->As<ast::UnaryOpExpression>();
+ EXPECT_EQ(u->op, op);
+
+ expr = u->expr;
+ }
+
+ EXPECT_TRUE(expr->Is<ast::IdentifierExpression>());
+}
+
+TEST_F(ParserImplTest, LHSExpression_PostfixExpression) {
+ auto p = parser("*a.foo");
+ auto e = p->lhs_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ ASSERT_NE(e.value, nullptr);
+ ASSERT_TRUE(e->Is<ast::MemberAccessorExpression>());
+
+ auto* access = e->As<ast::MemberAccessorExpression>();
+ ASSERT_TRUE(access->structure->Is<ast::UnaryOpExpression>());
+
+ auto* u = access->structure->As<ast::UnaryOpExpression>();
+ EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
+
+ ASSERT_TRUE(u->expr->Is<ast::IdentifierExpression>());
+ auto* struct_ident = u->expr->As<ast::IdentifierExpression>();
+ EXPECT_EQ(struct_ident->symbol, p->builder().Symbols().Get("a"));
+
+ ASSERT_TRUE(access->member->Is<ast::IdentifierExpression>());
+ auto* member_ident = access->member->As<ast::IdentifierExpression>();
+ EXPECT_EQ(member_ident->symbol, p->builder().Symbols().Get("foo"));
+}
+
+TEST_F(ParserImplTest, LHSExpression_InvalidPostfixExpression) {
+ auto p = parser("*a.if");
+ auto e = p->lhs_expression();
+ ASSERT_TRUE(p->has_error());
+ ASSERT_TRUE(e.errored);
+ EXPECT_FALSE(e.matched);
+ ASSERT_EQ(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:4: expected identifier for member accessor");
+}
+
+} // namespace
+} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc
index 20cd4f67703..a3e51b4f7f7 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc
@@ -20,59 +20,59 @@ namespace {
TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) {
auto p = parser("loop { discard; }");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
- ASSERT_EQ(e->body->statements.size(), 1u);
+ ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
- EXPECT_EQ(e->continuing->statements.size(), 0u);
+ EXPECT_EQ(e->continuing->statements.Length(), 0u);
}
TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
auto p = parser("loop { discard; continuing { discard; }}");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
- ASSERT_EQ(e->body->statements.size(), 1u);
+ ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
- EXPECT_EQ(e->continuing->statements.size(), 1u);
+ EXPECT_EQ(e->continuing->statements.Length(), 1u);
EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
}
TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) {
auto p = parser("loop { }");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
- ASSERT_EQ(e->body->statements.size(), 0u);
- ASSERT_EQ(e->continuing->statements.size(), 0u);
+ ASSERT_EQ(e->body->statements.Length(), 0u);
+ ASSERT_EQ(e->continuing->statements.Length(), 0u);
}
TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
auto p = parser("loop { continuing { discard; }}");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
- ASSERT_EQ(e->body->statements.size(), 0u);
- ASSERT_EQ(e->continuing->statements.size(), 1u);
+ ASSERT_EQ(e->body->statements.Length(), 0u);
+ ASSERT_EQ(e->continuing->statements.Length(), 1u);
EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
}
TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
auto p = parser("loop discard; }");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -82,7 +82,7 @@ TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
auto p = parser("loop { discard; ");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -92,7 +92,7 @@ TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {
auto p = parser("loop { discard }");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -102,7 +102,7 @@ TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {
TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) {
auto p = parser("loop { continuing { discard }}");
- auto e = p->loop_stmt();
+ auto e = p->loop_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_param_list_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_param_list_test.cc
index 2d79a99da15..ce542e4c23d 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_param_list_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_param_list_test.cc
@@ -23,11 +23,11 @@ TEST_F(ParserImplTest, ParamList_Single) {
auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- EXPECT_EQ(e.value.size(), 1u);
+ EXPECT_EQ(e.value.Length(), 1u);
EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
- EXPECT_TRUE(e.value[0]->is_const);
+ EXPECT_TRUE(e.value[0]->Is<ast::Parameter>());
ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
ASSERT_EQ(e.value[0]->source.range.begin.column, 1u);
@@ -41,11 +41,11 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- EXPECT_EQ(e.value.size(), 3u);
+ EXPECT_EQ(e.value.Length(), 3u);
EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
- EXPECT_TRUE(e.value[0]->is_const);
+ EXPECT_TRUE(e.value[0]->Is<ast::Parameter>());
ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
ASSERT_EQ(e.value[0]->source.range.begin.column, 1u);
@@ -54,7 +54,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
EXPECT_EQ(e.value[1]->symbol, p->builder().Symbols().Get("b"));
EXPECT_TRUE(e.value[1]->type->Is<ast::F32>());
- EXPECT_TRUE(e.value[1]->is_const);
+ EXPECT_TRUE(e.value[1]->Is<ast::Parameter>());
ASSERT_EQ(e.value[1]->source.range.begin.line, 1u);
ASSERT_EQ(e.value[1]->source.range.begin.column, 10u);
@@ -65,7 +65,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
ASSERT_TRUE(e.value[2]->type->Is<ast::Vector>());
ASSERT_TRUE(e.value[2]->type->As<ast::Vector>()->type->Is<ast::F32>());
EXPECT_EQ(e.value[2]->type->As<ast::Vector>()->width, 2u);
- EXPECT_TRUE(e.value[2]->is_const);
+ EXPECT_TRUE(e.value[2]->Is<ast::Parameter>());
ASSERT_EQ(e.value[2]->source.range.begin.line, 1u);
ASSERT_EQ(e.value[2]->source.range.begin.column, 18u);
@@ -78,7 +78,7 @@ TEST_F(ParserImplTest, ParamList_Empty) {
auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error());
ASSERT_FALSE(e.errored);
- EXPECT_EQ(e.value.size(), 0u);
+ EXPECT_EQ(e.value.Length(), 0u);
}
TEST_F(ParserImplTest, ParamList_TrailingComma) {
@@ -86,7 +86,7 @@ TEST_F(ParserImplTest, ParamList_TrailingComma) {
auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error());
ASSERT_FALSE(e.errored);
- EXPECT_EQ(e.value.size(), 1u);
+ EXPECT_EQ(e.value.Length(), 1u);
}
TEST_F(ParserImplTest, ParamList_Attributes) {
@@ -95,17 +95,17 @@ TEST_F(ParserImplTest, ParamList_Attributes) {
auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
- ASSERT_EQ(e.value.size(), 2u);
+ ASSERT_EQ(e.value.Length(), 2u);
EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("coord"));
ASSERT_TRUE(e.value[0]->type->Is<ast::Vector>());
EXPECT_TRUE(e.value[0]->type->As<ast::Vector>()->type->Is<ast::F32>());
EXPECT_EQ(e.value[0]->type->As<ast::Vector>()->width, 4u);
- EXPECT_TRUE(e.value[0]->is_const);
+ EXPECT_TRUE(e.value[0]->Is<ast::Parameter>());
auto attrs_0 = e.value[0]->attributes;
- ASSERT_EQ(attrs_0.size(), 1u);
+ ASSERT_EQ(attrs_0.Length(), 1u);
EXPECT_TRUE(attrs_0[0]->Is<ast::BuiltinAttribute>());
- EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, ast::Builtin::kPosition);
+ EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, ast::BuiltinValue::kPosition);
ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
ASSERT_EQ(e.value[0]->source.range.begin.column, 20u);
@@ -114,9 +114,9 @@ TEST_F(ParserImplTest, ParamList_Attributes) {
EXPECT_EQ(e.value[1]->symbol, p->builder().Symbols().Get("loc1"));
EXPECT_TRUE(e.value[1]->type->Is<ast::F32>());
- EXPECT_TRUE(e.value[1]->is_const);
+ EXPECT_TRUE(e.value[1]->Is<ast::Parameter>());
auto attrs_1 = e.value[1]->attributes;
- ASSERT_EQ(attrs_1.size(), 1u);
+ ASSERT_EQ(attrs_1.Length(), 1u);
EXPECT_TRUE(attrs_1[0]->Is<ast::LocationAttribute>());
EXPECT_EQ(attrs_1[0]->As<ast::LocationAttribute>()->value, 1u);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_paren_expression_test.cc
index dd5a978bbe9..e6bb2236ef0 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_paren_expression_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, ParenRhsStmt) {
auto p = parser("(a + b)");
- auto e = p->expect_paren_rhs_stmt();
+ auto e = p->expect_paren_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
@@ -28,7 +28,7 @@ TEST_F(ParserImplTest, ParenRhsStmt) {
TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) {
auto p = parser("true)");
- auto e = p->expect_paren_rhs_stmt();
+ auto e = p->expect_paren_expression();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
@@ -37,7 +37,7 @@ TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) {
TEST_F(ParserImplTest, ParenRhsStmt_MissingRightParen) {
auto p = parser("(true");
- auto e = p->expect_paren_rhs_stmt();
+ auto e = p->expect_paren_expression();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
@@ -46,7 +46,7 @@ TEST_F(ParserImplTest, ParenRhsStmt_MissingRightParen) {
TEST_F(ParserImplTest, ParenRhsStmt_InvalidExpression) {
auto p = parser("(if (a() {})");
- auto e = p->expect_paren_rhs_stmt();
+ auto e = p->expect_paren_expression();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
@@ -55,7 +55,7 @@ TEST_F(ParserImplTest, ParenRhsStmt_InvalidExpression) {
TEST_F(ParserImplTest, ParenRhsStmt_MissingExpression) {
auto p = parser("()");
- auto e = p->expect_paren_rhs_stmt();
+ auto e = p->expect_paren_expression();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
index 75a1ec200a5..3c730e2ab13 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
@@ -40,7 +40,7 @@ TEST_P(PipelineStageTest, Parses) {
EXPECT_EQ(stage.source.range.end.line, 1u);
EXPECT_EQ(stage.source.range.end.column, 1u + params.input.size());
- auto t = p->next();
+ auto& t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
index 493ce878a15..82f64c3ca59 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -42,7 +42,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
EXPECT_NE(call->target.type, nullptr);
- ASSERT_EQ(call->args.size(), 4u);
+ ASSERT_EQ(call->args.Length(), 4u);
const auto& val = call->args;
ASSERT_TRUE(val[0]->Is<ast::IntLiteralExpression>());
EXPECT_EQ(val[0]->As<ast::IntLiteralExpression>()->value, 1);
@@ -76,7 +76,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) {
ASSERT_TRUE(e->Is<ast::CallExpression>());
auto* call = e->As<ast::CallExpression>();
- ASSERT_EQ(call->args.size(), 0u);
+ ASSERT_EQ(call->args.Length(), 0u);
}
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
@@ -140,7 +140,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_Empty) {
ASSERT_NE(call->target.name, nullptr);
EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
- ASSERT_EQ(call->args.size(), 0u);
+ ASSERT_EQ(call->args.Length(), 0u);
}
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_NotEmpty) {
@@ -164,7 +164,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_NotEmpty) {
ASSERT_NE(call->target.name, nullptr);
EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
- ASSERT_EQ(call->args.size(), 2u);
+ ASSERT_EQ(call->args.Length(), 2u);
ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_EQ(call->args[0]->As<ast::IntLiteralExpression>()->value, 1u);
@@ -239,7 +239,7 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) {
auto* call = e->As<ast::CallExpression>();
ASSERT_TRUE(call->target.type->Is<ast::F32>());
- ASSERT_EQ(call->args.size(), 1u);
+ ASSERT_EQ(call->args.Length(), 1u);
ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>());
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
index e840af7c0fe..0ad3cc1c5f4 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
@@ -21,90 +21,232 @@ using ParserImplReservedKeywordTest = ParserImplTestWithParam<std::string>;
TEST_P(ParserImplReservedKeywordTest, Function) {
auto name = GetParam();
auto p = parser("fn " + name + "() {}");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:4: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:4: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
-TEST_P(ParserImplReservedKeywordTest, ModuleLet) {
+TEST_P(ParserImplReservedKeywordTest, ModuleConst) {
auto name = GetParam();
- auto p = parser("let " + name + " : i32 = 1;");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
+ auto p = parser("const " + name + " : i32 = 1;");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:7: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, ModuleVar) {
auto name = GetParam();
auto p = parser("var " + name + " : i32 = 1;");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:5: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, FunctionLet) {
auto name = GetParam();
auto p = parser("fn f() { let " + name + " : i32 = 1; }");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:14: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, FunctionVar) {
auto name = GetParam();
auto p = parser("fn f() { var " + name + " : i32 = 1; }");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:14: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, FunctionParam) {
auto name = GetParam();
auto p = parser("fn f(" + name + " : i32) {}");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:6: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, Struct) {
auto name = GetParam();
auto p = parser("struct " + name + " {};");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:8: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:8: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, StructMember) {
auto name = GetParam();
auto p = parser("struct S { " + name + " : i32, };");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:12: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:12: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, Alias) {
auto name = GetParam();
auto p = parser("type " + name + " = i32;");
- EXPECT_FALSE(p->Parse());
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
+ EXPECT_TRUE(p->Parse());
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(p->error(),
+ "1:6: use of deprecated language feature: '" + name + "' is a reserved keyword");
}
INSTANTIATE_TEST_SUITE_P(ParserImplReservedKeywordTest,
ParserImplReservedKeywordTest,
- testing::Values("asm",
- "bf16",
- "const",
+ testing::Values("ComputeShader",
+ "DomainShader",
+ "GeometryShader",
+ "Hullshader",
+ "NULL",
+ "Self",
+ "abstract",
+ "active",
+ "alignas",
+ "alignof",
+ "as",
+ "asm",
+ "asm_fragment",
+ "async",
+ "attribute",
+ "auto",
+ "await",
+ "become",
+ "binding_array",
+ "cast",
+ "catch",
+ "class",
+ "co_await",
+ "co_return",
+ "co_yield",
+ "coherent",
+ "column_major",
+ "common",
+ "compile",
+ "compile_fragment",
+ "concept",
+ "const_cast",
+ "consteval",
+ "constexpr",
+ "constinit",
+ "crate",
+ "debugger",
+ "decltype",
+ "delete",
+ "demote",
+ "demote_to_helper",
"do",
+ "dynamic_cast",
"enum",
- "f64",
+ "explicit",
+ "export",
+ "extends",
+ "extern",
+ "external",
+ "filter",
+ "final",
+ "finally",
+ "friend",
+ "from",
+ "fxgroup",
+ "get",
+ "goto",
+ "groupshared",
"handle",
- "i8",
- "i16",
- "i64",
- "mat",
+ "highp",
+ "impl",
+ "implements",
+ "import",
+ "inline",
+ "inout",
+ "instanceof",
+ "interface",
+ "invariant",
+ "layout",
+ "line",
+ "lineadj",
+ "lowp",
+ "macro",
+ "macro_rules",
+ "match",
+ "mediump",
+ "meta",
+ "mod",
+ "module",
+ "move",
+ "mut",
+ "mutable",
+ "namespace",
+ "new",
+ "nil",
+ "noexcept",
+ "noinline",
+ "nointerpolation",
+ "noperspective",
+ "null",
+ "nullptr",
+ "of",
+ "operator",
+ "package",
+ "packoffset",
+ "partition",
+ "pass",
+ "patch",
+ "pixelfragment",
+ "point",
+ "precise",
+ "precision",
"premerge",
+ "priv",
+ "protected",
+ "pub",
+ "public",
+ "readonly",
+ "ref",
"regardless",
+ "register",
+ "reinterpret_cast",
+ "requires",
+ "resource",
+ "restrict",
+ "self",
+ "set",
+ "shared",
+ "signed",
+ "sizeof",
+ "smooth",
+ "snorm",
+ "static",
+ "static_cast",
+ "std",
+ "subroutine",
+ "super",
+ "target",
+ "template",
+ "this",
+ "thread_local",
+ "throw",
+ "trait",
+ "try",
"typedef",
- "u8",
- "u16",
- "u64",
+ "typeid",
+ "typename",
+ "typeof",
+ "union",
"unless",
+ "unorm",
+ "unsafe",
+ "unsized",
+ "use",
"using",
- "vec",
- "void",
- "while"));
+ "varying",
+ "virtual",
+ "volatile",
+ "wgsl",
+ "where",
+ "with",
+ "writeonly",
+ "yield"
+
+ ));
} // namespace
} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc
index cf9f0898a87..6aa1aab097e 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, SampledTextureType_Invalid) {
auto p = parser("1234");
- auto t = p->sampled_texture();
+ auto t = p->sampled_texture_type();
EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_FALSE(p->has_error());
@@ -27,7 +27,7 @@ TEST_F(ParserImplTest, SampledTextureType_Invalid) {
TEST_F(ParserImplTest, SampledTextureType_1d) {
auto p = parser("texture_1d");
- auto t = p->sampled_texture();
+ auto t = p->sampled_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k1d);
@@ -36,7 +36,7 @@ TEST_F(ParserImplTest, SampledTextureType_1d) {
TEST_F(ParserImplTest, SampledTextureType_2d) {
auto p = parser("texture_2d");
- auto t = p->sampled_texture();
+ auto t = p->sampled_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k2d);
@@ -45,7 +45,7 @@ TEST_F(ParserImplTest, SampledTextureType_2d) {
TEST_F(ParserImplTest, SampledTextureType_2dArray) {
auto p = parser("texture_2d_array");
- auto t = p->sampled_texture();
+ auto t = p->sampled_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k2dArray);
@@ -54,7 +54,7 @@ TEST_F(ParserImplTest, SampledTextureType_2dArray) {
TEST_F(ParserImplTest, SampledTextureType_3d) {
auto p = parser("texture_3d");
- auto t = p->sampled_texture();
+ auto t = p->sampled_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k3d);
@@ -63,7 +63,7 @@ TEST_F(ParserImplTest, SampledTextureType_3d) {
TEST_F(ParserImplTest, SampledTextureType_Cube) {
auto p = parser("texture_cube");
- auto t = p->sampled_texture();
+ auto t = p->sampled_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::kCube);
@@ -72,7 +72,7 @@ TEST_F(ParserImplTest, SampledTextureType_Cube) {
TEST_F(ParserImplTest, SampledTextureType_kCubeArray) {
auto p = parser("texture_cube_array");
- auto t = p->sampled_texture();
+ auto t = p->sampled_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::kCubeArray);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampler_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampler_test.cc
index 7f1e5645b8e..bd3c2d39aa2 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampler_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_sampler_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, SamplerType_Invalid) {
auto p = parser("1234");
- auto t = p->sampler();
+ auto t = p->sampler_type();
EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, nullptr);
@@ -28,7 +28,7 @@ TEST_F(ParserImplTest, SamplerType_Invalid) {
TEST_F(ParserImplTest, SamplerType_Sampler) {
auto p = parser("sampler");
- auto t = p->sampler();
+ auto t = p->sampler_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
@@ -40,7 +40,7 @@ TEST_F(ParserImplTest, SamplerType_Sampler) {
TEST_F(ParserImplTest, SamplerType_ComparisonSampler) {
auto p = parser("sampler_comparison");
- auto t = p->sampler();
+ auto t = p->sampler_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc
index 4ab185bb6e7..a08b45a97e2 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc
@@ -99,7 +99,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_Empty) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
- EXPECT_EQ(c->args.size(), 0u);
+ EXPECT_EQ(c->args.Length(), 0u);
}
TEST_F(ParserImplTest, SingularExpression_Call_WithArgs) {
@@ -115,7 +115,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_WithArgs) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("test"));
- EXPECT_EQ(c->args.size(), 3u);
+ EXPECT_EQ(c->args.Length(), 3u);
EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
@@ -130,7 +130,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_TrailingComma) {
ASSERT_TRUE(e->Is<ast::CallExpression>());
auto* c = e->As<ast::CallExpression>();
- EXPECT_EQ(c->args.size(), 1u);
+ EXPECT_EQ(c->args.Length(), 1u);
}
TEST_F(ParserImplTest, SingularExpression_Call_InvalidArg) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statement_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statement_test.cc
index 235c7485486..7bb51d3d37b 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statement_test.cc
@@ -114,7 +114,7 @@ TEST_F(ParserImplTest, Statement_Variable_Invalid) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:14: missing constructor for variable declaration");
+ EXPECT_EQ(p->error(), "1:14: missing initializer for 'var' declaration");
}
TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) {
@@ -272,5 +272,47 @@ TEST_F(ParserImplTest, Statement_Body_Invalid) {
EXPECT_EQ(p->error(), "1:3: expected '}'");
}
+TEST_F(ParserImplTest, Statement_StaticAssert_WithParen) {
+ auto p = parser("static_assert(true);");
+ auto e = p->statement();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+
+ auto* sa = As<ast::StaticAssert>(e.value);
+ ASSERT_NE(sa, nullptr);
+ EXPECT_EQ(sa->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->source.range.begin.column, 1u);
+ EXPECT_EQ(sa->source.range.end.line, 1u);
+ EXPECT_EQ(sa->source.range.end.column, 20u);
+
+ EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
+ EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.begin.column, 15u);
+ EXPECT_EQ(sa->condition->source.range.end.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.end.column, 19u);
+}
+
+TEST_F(ParserImplTest, Statement_StaticAssert_WithoutParen) {
+ auto p = parser("static_assert true;");
+ auto e = p->statement();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ EXPECT_TRUE(e.matched);
+ EXPECT_FALSE(e.errored);
+
+ auto* sa = As<ast::StaticAssert>(e.value);
+ ASSERT_NE(sa, nullptr);
+ EXPECT_EQ(sa->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->source.range.begin.column, 1u);
+ EXPECT_EQ(sa->source.range.end.line, 1u);
+ EXPECT_EQ(sa->source.range.end.column, 20u);
+
+ EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
+ EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.begin.column, 16u);
+ EXPECT_EQ(sa->condition->source.range.end.line, 1u);
+ EXPECT_EQ(sa->condition->source.range.end.column, 20u);
+}
+
} // namespace
} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statements_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statements_test.cc
index b96a28a4a16..c631f7ae218 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statements_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_statements_test.cc
@@ -23,7 +23,7 @@ TEST_F(ParserImplTest, Statements) {
auto e = p->expect_statements();
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
- ASSERT_EQ(e->size(), 2u);
+ ASSERT_EQ(e->Length(), 2u);
EXPECT_TRUE(e.value[0]->Is<ast::DiscardStatement>());
EXPECT_TRUE(e.value[1]->Is<ast::ReturnStatement>());
}
@@ -33,7 +33,7 @@ TEST_F(ParserImplTest, Statements_Empty) {
auto e = p->expect_statements();
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
- ASSERT_EQ(e->size(), 0u);
+ ASSERT_EQ(e->Length(), 0u);
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_class_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
index 4abbe766925..c6ef7eb470b 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
@@ -26,40 +26,35 @@ inline std::ostream& operator<<(std::ostream& out, StorageClassData data) {
return out;
}
-class StorageClassTest : public ParserImplTestWithParam<StorageClassData> {};
+class ParserStorageClassTest : public ParserImplTestWithParam<StorageClassData> {};
-TEST_P(StorageClassTest, Parses) {
+TEST_P(ParserStorageClassTest, Parses) {
auto params = GetParam();
auto p = parser(params.input);
- auto sc = p->expect_storage_class("test");
+ auto sc = p->expect_address_space("test");
EXPECT_FALSE(sc.errored);
EXPECT_FALSE(p->has_error());
EXPECT_EQ(sc.value, params.result);
- auto t = p->next();
+ auto& t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
ParserImplTest,
- StorageClassTest,
+ ParserStorageClassTest,
testing::Values(StorageClassData{"uniform", ast::StorageClass::kUniform},
StorageClassData{"workgroup", ast::StorageClass::kWorkgroup},
StorageClassData{"storage", ast::StorageClass::kStorage},
- StorageClassData{"storage_buffer", ast::StorageClass::kStorage},
StorageClassData{"private", ast::StorageClass::kPrivate},
StorageClassData{"function", ast::StorageClass::kFunction}));
TEST_F(ParserImplTest, StorageClass_NoMatch) {
auto p = parser("not-a-storage-class");
- auto sc = p->expect_storage_class("test");
+ auto sc = p->expect_address_space("test");
EXPECT_EQ(sc.errored, true);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:1: invalid storage class for test");
-
- auto t = p->next();
- EXPECT_TRUE(t.IsIdentifier());
- EXPECT_EQ(t.to_str(), "not");
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc
index 6297a1ef27b..528f3a4e7c1 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, StorageTextureType_Invalid) {
auto p = parser("abc");
- auto t = p->storage_texture();
+ auto t = p->storage_texture_type();
EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_FALSE(p->has_error());
@@ -27,7 +27,7 @@ TEST_F(ParserImplTest, StorageTextureType_Invalid) {
TEST_F(ParserImplTest, StorageTextureType_1d) {
auto p = parser("texture_storage_1d");
- auto t = p->storage_texture();
+ auto t = p->storage_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k1d);
@@ -36,7 +36,7 @@ TEST_F(ParserImplTest, StorageTextureType_1d) {
TEST_F(ParserImplTest, StorageTextureType_2d) {
auto p = parser("texture_storage_2d");
- auto t = p->storage_texture();
+ auto t = p->storage_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k2d);
@@ -45,7 +45,7 @@ TEST_F(ParserImplTest, StorageTextureType_2d) {
TEST_F(ParserImplTest, StorageTextureType_2dArray) {
auto p = parser("texture_storage_2d_array");
- auto t = p->storage_texture();
+ auto t = p->storage_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k2dArray);
@@ -54,7 +54,7 @@ TEST_F(ParserImplTest, StorageTextureType_2dArray) {
TEST_F(ParserImplTest, StorageTextureType_3d) {
auto p = parser("texture_storage_3d");
- auto t = p->storage_texture();
+ auto t = p->storage_texture_type();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::TextureDimension::k3d);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
index a22abee1b1c..e0150331541 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
@@ -24,7 +24,7 @@ TEST_F(ParserImplTest, AttributeDecl_Parses) {
EXPECT_FALSE(p->has_error());
EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched);
- ASSERT_EQ(attrs.value.size(), 1u);
+ ASSERT_EQ(attrs.value.Length(), 1u);
auto* invariant = attrs.value[0]->As<ast::Attribute>();
EXPECT_TRUE(invariant->Is<ast::InvariantAttribute>());
}
@@ -35,7 +35,7 @@ TEST_F(ParserImplTest, AttributeDecl_MissingParenLeft) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_TRUE(attrs.value.empty());
+ EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:11: expected '(' for location attribute");
}
@@ -45,7 +45,7 @@ TEST_F(ParserImplTest, AttributeDecl_MissingValue) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_TRUE(attrs.value.empty());
+ EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:11: expected signed integer literal for location attribute");
}
@@ -55,7 +55,7 @@ TEST_F(ParserImplTest, AttributeDecl_MissingParenRight) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_TRUE(attrs.value.empty());
+ EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:12: expected ')' for location attribute");
}
@@ -65,7 +65,7 @@ TEST_F(ParserImplTest, AttributeDecl_Invalidattribute) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_TRUE(attrs.value.empty());
+ EXPECT_TRUE(attrs.value.IsEmpty());
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
index b02fb5a177d..3499b5cb00d 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
@@ -25,12 +25,12 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses) {
auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored);
- ASSERT_EQ(m.value.size(), 1u);
+ ASSERT_EQ(m.value.Length(), 1u);
const auto* mem = m.value[0];
EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(mem->type->Is<ast::I32>());
- EXPECT_EQ(mem->attributes.size(), 0u);
+ EXPECT_EQ(mem->attributes.Length(), 0u);
}
TEST_F(ParserImplTest, StructBodyDecl_Parses_TrailingComma) {
@@ -41,12 +41,12 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses_TrailingComma) {
auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored);
- ASSERT_EQ(m.value.size(), 1u);
+ ASSERT_EQ(m.value.Length(), 1u);
const auto* mem = m.value[0];
EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(mem->type->Is<ast::I32>());
- EXPECT_EQ(mem->attributes.size(), 0u);
+ EXPECT_EQ(mem->attributes.Length(), 0u);
}
TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
@@ -54,7 +54,7 @@ TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored);
- ASSERT_EQ(m.value.size(), 0u);
+ ASSERT_EQ(m.value.Length(), 0u);
}
TEST_F(ParserImplTest, StructBodyDecl_InvalidAlign) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
index 106ffd581bc..dbb9ca6ab59 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
@@ -30,7 +30,7 @@ struct S {
EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr);
ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
- ASSERT_EQ(s->members.size(), 2u);
+ ASSERT_EQ(s->members.Length(), 2u);
EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a"));
EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b"));
}
@@ -64,7 +64,7 @@ struct $struct {
EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr);
ASSERT_EQ(s->name, p->builder().Symbols().Register(struct_ident));
- ASSERT_EQ(s->members.size(), 2u);
+ ASSERT_EQ(s->members.Length(), 2u);
EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register(member_a_ident));
EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register(member_b_ident));
}
@@ -77,7 +77,7 @@ TEST_F(ParserImplTest, StructDecl_EmptyMembers) {
EXPECT_FALSE(s.errored);
EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr);
- ASSERT_EQ(s->members.size(), 0u);
+ ASSERT_EQ(s->members.Length(), 0u);
}
TEST_F(ParserImplTest, StructDecl_MissingIdent) {
@@ -104,23 +104,5 @@ TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration");
}
-// TODO(crbug.com/tint/1475): Remove this.
-TEST_F(ParserImplTest, DEPRECATED_StructDecl_Parses_WithSemicolons) {
- auto p = parser(R"(
-struct S {
- a : i32;
- b : f32;
-})");
- auto s = p->struct_decl();
- EXPECT_FALSE(p->has_error());
- EXPECT_FALSE(s.errored);
- EXPECT_TRUE(s.matched);
- ASSERT_NE(s.value, nullptr);
- ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
- ASSERT_EQ(s->members.size(), 2u);
- EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a"));
- EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b"));
-}
-
} // namespace
} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
index 2695074c6c0..09d5274fe19 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
@@ -23,7 +23,7 @@ TEST_F(ParserImplTest, AttributeDecl_EmptyStr) {
EXPECT_FALSE(p->has_error());
EXPECT_FALSE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_EQ(attrs.value.size(), 0u);
+ EXPECT_EQ(attrs.value.Length(), 0u);
}
TEST_F(ParserImplTest, AttributeDecl_Single) {
@@ -32,7 +32,7 @@ TEST_F(ParserImplTest, AttributeDecl_Single) {
EXPECT_FALSE(p->has_error());
EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched);
- ASSERT_EQ(attrs.value.size(), 1u);
+ ASSERT_EQ(attrs.value.Length(), 1u);
auto* attr = attrs.value[0]->As<ast::Attribute>();
ASSERT_NE(attr, nullptr);
EXPECT_TRUE(attr->Is<ast::StructMemberSizeAttribute>());
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
index d185f3736a9..df75f969845 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
@@ -33,6 +33,22 @@ TEST_F(ParserImplTest, Attribute_Size) {
EXPECT_EQ(o->size, 4u);
}
+TEST_F(ParserImplTest, Attribute_Size_TrailingComma) {
+ auto p = parser("size(4,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ ASSERT_FALSE(p->has_error());
+
+ auto* member_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(member_attr, nullptr);
+ ASSERT_TRUE(member_attr->Is<ast::StructMemberSizeAttribute>());
+
+ auto* o = member_attr->As<ast::StructMemberSizeAttribute>();
+ EXPECT_EQ(o->size, 4u);
+}
+
TEST_F(ParserImplTest, Attribute_Size_MissingLeftParen) {
auto p = parser("size 4)");
auto attr = p->attribute();
@@ -89,6 +105,22 @@ TEST_F(ParserImplTest, Attribute_Align) {
EXPECT_EQ(o->align, 4u);
}
+TEST_F(ParserImplTest, Attribute_Align_TrailingComma) {
+ auto p = parser("align(4,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ ASSERT_FALSE(p->has_error());
+
+ auto* member_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(member_attr, nullptr);
+ ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>());
+
+ auto* o = member_attr->As<ast::StructMemberAlignAttribute>();
+ EXPECT_EQ(o->align, 4u);
+}
+
TEST_F(ParserImplTest, Attribute_Align_MissingLeftParen) {
auto p = parser("align 4)");
auto attr = p->attribute();
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
index 3e8b60e7159..d2ab9160a42 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
@@ -29,7 +29,7 @@ TEST_F(ParserImplTest, StructMember_Parses) {
EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(m->type->Is<ast::I32>());
- EXPECT_EQ(m->attributes.size(), 0u);
+ EXPECT_EQ(m->attributes.Length(), 0u);
EXPECT_EQ(m->source.range, (Source::Range{{1u, 1u}, {1u, 2u}}));
EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 5u}, {1u, 8u}}));
@@ -47,7 +47,7 @@ TEST_F(ParserImplTest, StructMember_ParsesWithAlignAttribute) {
EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(m->type->Is<ast::I32>());
- EXPECT_EQ(m->attributes.size(), 1u);
+ EXPECT_EQ(m->attributes.Length(), 1u);
EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberAlignAttribute>());
EXPECT_EQ(m->attributes[0]->As<ast::StructMemberAlignAttribute>()->align, 2u);
@@ -67,7 +67,7 @@ TEST_F(ParserImplTest, StructMember_ParsesWithSizeAttribute) {
EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(m->type->Is<ast::I32>());
- EXPECT_EQ(m->attributes.size(), 1u);
+ EXPECT_EQ(m->attributes.Length(), 1u);
EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>());
EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u);
@@ -88,7 +88,7 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleattributes) {
EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(m->type->Is<ast::I32>());
- EXPECT_EQ(m->attributes.size(), 2u);
+ EXPECT_EQ(m->attributes.Length(), 2u);
EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>());
EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u);
EXPECT_TRUE(m->attributes[1]->Is<ast::StructMemberAlignAttribute>());
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_body_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_body_test.cc
index 0f7384de83e..076b1c3f1a6 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_body_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_body_test.cc
@@ -27,10 +27,10 @@ TEST_F(ParserImplTest, SwitchBody_Case) {
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
- ASSERT_EQ(stmt->selectors.size(), 1u);
+ ASSERT_EQ(stmt->selectors.Length(), 1u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
- ASSERT_EQ(e->body->statements.size(), 1u);
+ ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
@@ -44,10 +44,10 @@ TEST_F(ParserImplTest, SwitchBody_Case_WithColon) {
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
- ASSERT_EQ(stmt->selectors.size(), 1u);
+ ASSERT_EQ(stmt->selectors.Length(), 1u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
- ASSERT_EQ(e->body->statements.size(), 1u);
+ ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
@@ -61,7 +61,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma) {
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
- ASSERT_EQ(stmt->selectors.size(), 2u);
+ ASSERT_EQ(stmt->selectors.Length(), 2u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
EXPECT_EQ(stmt->selectors[1]->value, 2);
@@ -77,7 +77,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma_WithColon) {
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
- ASSERT_EQ(stmt->selectors.size(), 2u);
+ ASSERT_EQ(stmt->selectors.Length(), 2u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
EXPECT_EQ(stmt->selectors[1]->value, 2);
@@ -162,8 +162,8 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
- ASSERT_EQ(e->body->statements.size(), 0u);
- ASSERT_EQ(e->selectors.size(), 2u);
+ ASSERT_EQ(e->body->statements.Length(), 0u);
+ ASSERT_EQ(e->selectors.Length(), 2u);
ASSERT_EQ(e->selectors[0]->value, 1);
EXPECT_EQ(e->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->selectors[1]->value, 2);
@@ -179,8 +179,8 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors_WithColon) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
- ASSERT_EQ(e->body->statements.size(), 0u);
- ASSERT_EQ(e->selectors.size(), 2u);
+ ASSERT_EQ(e->body->statements.Length(), 0u);
+ ASSERT_EQ(e->selectors.Length(), 2u);
ASSERT_EQ(e->selectors[0]->value, 1);
EXPECT_EQ(e->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->selectors[1]->value, 2);
@@ -216,7 +216,7 @@ TEST_F(ParserImplTest, SwitchBody_Default) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_TRUE(e->IsDefault());
- ASSERT_EQ(e->body->statements.size(), 1u);
+ ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
@@ -229,7 +229,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_WithColon) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_TRUE(e->IsDefault());
- ASSERT_EQ(e->body->statements.size(), 1u);
+ ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc
index c898b123d86..014d850b362 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc
@@ -22,26 +22,26 @@ TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) {
case 1: {}
case 2: {}
})");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::SwitchStatement>());
- ASSERT_EQ(e->body.size(), 2u);
+ ASSERT_EQ(e->body.Length(), 2u);
EXPECT_FALSE(e->body[0]->IsDefault());
EXPECT_FALSE(e->body[1]->IsDefault());
}
TEST_F(ParserImplTest, SwitchStmt_Empty) {
auto p = parser("switch a { }");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::SwitchStatement>());
- ASSERT_EQ(e->body.size(), 0u);
+ ASSERT_EQ(e->body.Length(), 0u);
}
TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
@@ -50,14 +50,14 @@ TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
default: {}
case 2: {}
})");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::SwitchStatement>());
- ASSERT_EQ(e->body.size(), 3u);
+ ASSERT_EQ(e->body.Length(), 3u);
ASSERT_FALSE(e->body[0]->IsDefault());
ASSERT_TRUE(e->body[1]->IsDefault());
ASSERT_FALSE(e->body[2]->IsDefault());
@@ -65,18 +65,18 @@ TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
TEST_F(ParserImplTest, SwitchStmt_WithParens) {
auto p = parser("switch(a+b) { }");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::SwitchStatement>());
- ASSERT_EQ(e->body.size(), 0u);
+ ASSERT_EQ(e->body.Length(), 0u);
}
TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) {
auto p = parser("switch a=b {}");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -86,7 +86,7 @@ TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) {
TEST_F(ParserImplTest, SwitchStmt_MissingExpression) {
auto p = parser("switch {}");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -96,7 +96,7 @@ TEST_F(ParserImplTest, SwitchStmt_MissingExpression) {
TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) {
auto p = parser("switch a }");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -106,7 +106,7 @@ TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) {
TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
auto p = parser("switch a {");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
@@ -118,7 +118,7 @@ TEST_F(ParserImplTest, SwitchStmt_InvalidBody) {
auto p = parser(R"(switch a {
case: {}
})");
- auto e = p->switch_stmt();
+ auto e = p->switch_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test.cc
index 99ca25da019..c23481118c0 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test.cc
@@ -32,7 +32,7 @@ fn main() -> @location(0) vec4<f32> {
ASSERT_TRUE(p->Parse()) << p->error();
Program program = p->program();
- ASSERT_EQ(1u, program.AST().Functions().size());
+ ASSERT_EQ(1u, program.AST().Functions().Length());
}
TEST_F(ParserImplTest, Parses_ExtraSemicolons) {
@@ -52,8 +52,8 @@ fn foo() -> S {
ASSERT_TRUE(p->Parse()) << p->error();
Program program = p->program();
- ASSERT_EQ(1u, program.AST().Functions().size());
- ASSERT_EQ(1u, program.AST().TypeDecls().size());
+ ASSERT_EQ(1u, program.AST().Functions().Length());
+ ASSERT_EQ(1u, program.AST().TypeDecls().Length());
}
TEST_F(ParserImplTest, HandlesError) {
@@ -121,7 +121,7 @@ parameters
}/* block comments are OK at EOF...*/)");
ASSERT_TRUE(p->Parse()) << p->error();
- ASSERT_EQ(1u, p->program().AST().Functions().size());
+ ASSERT_EQ(1u, p->program().AST().Functions().Length());
}
TEST_F(ParserImplTest, Comments_UnterminatedBlockComment) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test_helper.h b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test_helper.h
index f6ee8ea3b7d..1b140399fe5 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test_helper.h
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_test_helper.h
@@ -38,6 +38,7 @@ class ParserImplTest : public testing::Test, public ProgramBuilder {
std::unique_ptr<ParserImpl> parser(const std::string& str) {
auto file = std::make_unique<Source::File>("test.wgsl", str);
auto impl = std::make_unique<ParserImpl>(file.get());
+ impl->InitializeLex();
files_.emplace_back(std::move(file));
return impl;
}
@@ -60,6 +61,7 @@ class ParserImplTestWithParam : public testing::TestWithParam<T>, public Program
std::unique_ptr<ParserImpl> parser(const std::string& str) {
auto file = std::make_unique<Source::File>("test.wgsl", str);
auto impl = std::make_unique<ParserImpl>(file.get());
+ impl->InitializeLex();
files_.emplace_back(std::move(file));
return impl;
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc
index 162b41c15b8..1143c5215af 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc
@@ -22,7 +22,7 @@ namespace {
TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) {
auto p = parser("1234");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
@@ -31,7 +31,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) {
TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
auto p = parser("sampler");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -43,7 +43,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
auto p = parser("sampler_comparison");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -55,7 +55,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
auto p = parser("texture_depth_2d");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -68,7 +68,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
auto p = parser("texture_1d<f32>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -82,7 +82,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
auto p = parser("texture_2d<i32>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -96,7 +96,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
auto p = parser("texture_3d<u32>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -110,7 +110,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) {
auto p = parser("texture_1d<>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
@@ -120,7 +120,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) {
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) {
auto p = parser("texture_1d");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
@@ -130,7 +130,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) {
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) {
auto p = parser("texture_1d<u32");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
@@ -140,7 +140,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) {
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
auto p = parser("texture_multisampled_2d<i32>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -154,7 +154,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
auto p = parser("texture_multisampled_2d<>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
@@ -164,7 +164,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingLessThan) {
auto p = parser("texture_multisampled_2d");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
@@ -173,7 +173,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingLessThan)
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) {
auto p = parser("texture_multisampled_2d<u32");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
@@ -182,7 +182,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingGreaterTha
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) {
auto p = parser("texture_storage_1d<rg32float, read>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -198,7 +198,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) {
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR32Uint) {
auto p = parser("texture_storage_2d<r32uint, write>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
@@ -214,7 +214,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR32Uint) {
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
auto p = parser("texture_storage_1d<abc, read>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
@@ -223,7 +223,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidAccess) {
auto p = parser("texture_storage_1d<r32float, abc>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
@@ -232,7 +232,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidAccess) {
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
auto p = parser("texture_storage_1d<>");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
@@ -241,7 +241,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) {
auto p = parser("texture_storage_1d");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
@@ -250,7 +250,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) {
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) {
auto p = parser("texture_storage_1d<r32uint, read");
- auto t = p->texture_samplers();
+ auto t = p->texture_and_sampler_types();
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_alias_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
index ea5cbe25b4b..c9bb72cb25f 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
@@ -20,7 +20,7 @@ namespace {
TEST_F(ParserImplTest, TypeDecl_ParsesType) {
auto p = parser("type a = i32");
- auto t = p->type_alias();
+ auto t = p->type_alias_decl();
EXPECT_FALSE(p->has_error());
EXPECT_FALSE(t.errored);
EXPECT_TRUE(t.matched);
@@ -35,7 +35,7 @@ TEST_F(ParserImplTest, TypeDecl_ParsesType) {
TEST_F(ParserImplTest, TypeDecl_Parses_Ident) {
auto p = parser("type a = B");
- auto t = p->type_alias();
+ auto t = p->type_alias_decl();
EXPECT_FALSE(p->has_error());
EXPECT_FALSE(t.errored);
EXPECT_TRUE(t.matched);
@@ -54,7 +54,7 @@ TEST_F(ParserImplTest, TypeDecl_Unicode_Parses_Ident) {
auto p = parser("type " + ident + " = i32");
- auto t = p->type_alias();
+ auto t = p->type_alias_decl();
EXPECT_FALSE(p->has_error());
EXPECT_FALSE(t.errored);
EXPECT_TRUE(t.matched);
@@ -68,7 +68,7 @@ TEST_F(ParserImplTest, TypeDecl_Unicode_Parses_Ident) {
TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
auto p = parser("type = i32");
- auto t = p->type_alias();
+ auto t = p->type_alias_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(p->has_error());
@@ -78,7 +78,7 @@ TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
TEST_F(ParserImplTest, TypeDecl_InvalidIdent) {
auto p = parser("type 123 = i32");
- auto t = p->type_alias();
+ auto t = p->type_alias_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(p->has_error());
@@ -88,7 +88,7 @@ TEST_F(ParserImplTest, TypeDecl_InvalidIdent) {
TEST_F(ParserImplTest, TypeDecl_MissingEqual) {
auto p = parser("type a i32");
- auto t = p->type_alias();
+ auto t = p->type_alias_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(p->has_error());
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
index bc2bfe5d666..1cf66c06377 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
@@ -272,7 +272,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) {
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
+ ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
@@ -302,7 +302,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
+ ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) {
@@ -399,7 +399,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_AbstractIntLiteralSize) {
auto* a = t.value->As<ast::Array>();
ASSERT_FALSE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
- EXPECT_EQ(a->attributes.size(), 0u);
+ EXPECT_EQ(a->attributes.Length(), 0u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 14u}}));
auto* size = a->count->As<ast::IntLiteralExpression>();
@@ -420,7 +420,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_SintLiteralSize) {
auto* a = t.value->As<ast::Array>();
ASSERT_FALSE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
- EXPECT_EQ(a->attributes.size(), 0u);
+ EXPECT_EQ(a->attributes.Length(), 0u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
auto* size = a->count->As<ast::IntLiteralExpression>();
@@ -441,7 +441,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_UintLiteralSize) {
auto* a = t.value->As<ast::Array>();
ASSERT_FALSE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
- EXPECT_EQ(a->attributes.size(), 0u);
+ EXPECT_EQ(a->attributes.Length(), 0u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
auto* size = a->count->As<ast::IntLiteralExpression>();
@@ -461,7 +461,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_ConstantSize) {
auto* a = t.value->As<ast::Array>();
ASSERT_FALSE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
- EXPECT_EQ(a->attributes.size(), 0u);
+ EXPECT_EQ(a->attributes.Length(), 0u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
auto* count_expr = a->count->As<ast::IdentifierExpression>();
@@ -501,6 +501,22 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Vec) {
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
}
+TEST_F(ParserImplTest, TypeDecl_Array_InferTypeAndSize) {
+ auto p = parser("array");
+ auto t = p->type_decl();
+ EXPECT_TRUE(t.matched);
+ EXPECT_FALSE(t.errored);
+ ASSERT_NE(t.value, nullptr) << p->error();
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(t.value->Is<ast::Array>());
+
+ auto* a = t.value->As<ast::Array>();
+ EXPECT_FALSE(a->IsRuntimeArray());
+ EXPECT_EQ(a->type, nullptr);
+ EXPECT_EQ(a->count, nullptr);
+ EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 6u}}));
+}
+
TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
auto p = parser("array<f32, !>");
auto t = p->type_decl();
@@ -521,16 +537,6 @@ TEST_F(ParserImplTest, TypeDecl_Array_MissingSize) {
ASSERT_EQ(p->error(), "1:11: expected array size expression");
}
-TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
- auto p = parser("array f32>");
- auto t = p->type_decl();
- EXPECT_TRUE(t.errored);
- EXPECT_FALSE(t.matched);
- ASSERT_EQ(t.value, nullptr);
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:7: expected '<' for array declaration");
-}
-
TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
auto p = parser("array<f32");
auto t = p->type_decl();
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc
index 133dd369184..2745e5fc7ba 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc
@@ -23,7 +23,7 @@ TEST_F(ParserImplTest, AttributeList_Parses) {
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(attrs.errored);
ASSERT_TRUE(attrs.matched);
- ASSERT_EQ(attrs.value.size(), 2u);
+ ASSERT_EQ(attrs.value.Length(), 2u);
auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
@@ -33,7 +33,7 @@ TEST_F(ParserImplTest, AttributeList_Parses) {
ASSERT_TRUE(attr_0->Is<ast::LocationAttribute>());
EXPECT_EQ(attr_0->As<ast::LocationAttribute>()->value, 4u);
ASSERT_TRUE(attr_1->Is<ast::BuiltinAttribute>());
- EXPECT_EQ(attr_1->As<ast::BuiltinAttribute>()->builtin, ast::Builtin::kPosition);
+ EXPECT_EQ(attr_1->As<ast::BuiltinAttribute>()->builtin, ast::BuiltinValue::kPosition);
}
TEST_F(ParserImplTest, AttributeList_Invalid) {
@@ -42,7 +42,7 @@ TEST_F(ParserImplTest, AttributeList_Invalid) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_TRUE(attrs.value.empty());
+ EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), R"(1:2: expected attribute)");
}
@@ -52,7 +52,7 @@ TEST_F(ParserImplTest, AttributeList_InvalidValue) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
- EXPECT_TRUE(attrs.value.empty());
+ EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:10: invalid value for builtin attribute");
}
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
index 8833273f273..ef778917d54 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
@@ -32,6 +32,21 @@ TEST_F(ParserImplTest, Attribute_Location) {
EXPECT_EQ(loc->value, 4u);
}
+TEST_F(ParserImplTest, Attribute_Location_TrailingComma) {
+ auto p = parser("location(4,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(var_attr->Is<ast::LocationAttribute>());
+
+ auto* loc = var_attr->As<ast::LocationAttribute>();
+ EXPECT_EQ(loc->value, 4u);
+}
+
TEST_F(ParserImplTest, Attribute_Location_MissingLeftParen) {
auto p = parser("location 4)");
auto attr = p->attribute();
@@ -74,7 +89,7 @@ TEST_F(ParserImplTest, Attribute_Location_MissingInvalid) {
struct BuiltinData {
const char* input;
- ast::Builtin result;
+ ast::BuiltinValue result;
};
inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
out << std::string(data.input);
@@ -99,22 +114,37 @@ TEST_P(BuiltinTest, Attribute_Builtin) {
auto* builtin = var_attr->As<ast::BuiltinAttribute>();
EXPECT_EQ(builtin->builtin, params.result);
}
+TEST_P(BuiltinTest, Attribute_Builtin_TrailingComma) {
+ auto params = GetParam();
+ auto p = parser(std::string("builtin(") + params.input + ",)");
+
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_TRUE(var_attr->Is<ast::BuiltinAttribute>());
+
+ auto* builtin = var_attr->As<ast::BuiltinAttribute>();
+ EXPECT_EQ(builtin->builtin, params.result);
+}
INSTANTIATE_TEST_SUITE_P(
ParserImplTest,
BuiltinTest,
- testing::Values(BuiltinData{"position", ast::Builtin::kPosition},
- BuiltinData{"vertex_index", ast::Builtin::kVertexIndex},
- BuiltinData{"instance_index", ast::Builtin::kInstanceIndex},
- BuiltinData{"front_facing", ast::Builtin::kFrontFacing},
- BuiltinData{"frag_depth", ast::Builtin::kFragDepth},
- BuiltinData{"local_invocation_id", ast::Builtin::kLocalInvocationId},
- BuiltinData{"local_invocation_idx", ast::Builtin::kLocalInvocationIndex},
- BuiltinData{"local_invocation_index", ast::Builtin::kLocalInvocationIndex},
- BuiltinData{"global_invocation_id", ast::Builtin::kGlobalInvocationId},
- BuiltinData{"workgroup_id", ast::Builtin::kWorkgroupId},
- BuiltinData{"num_workgroups", ast::Builtin::kNumWorkgroups},
- BuiltinData{"sample_index", ast::Builtin::kSampleIndex},
- BuiltinData{"sample_mask", ast::Builtin::kSampleMask}));
+ testing::Values(BuiltinData{"position", ast::BuiltinValue::kPosition},
+ BuiltinData{"vertex_index", ast::BuiltinValue::kVertexIndex},
+ BuiltinData{"instance_index", ast::BuiltinValue::kInstanceIndex},
+ BuiltinData{"front_facing", ast::BuiltinValue::kFrontFacing},
+ BuiltinData{"frag_depth", ast::BuiltinValue::kFragDepth},
+ BuiltinData{"local_invocation_id", ast::BuiltinValue::kLocalInvocationId},
+ BuiltinData{"local_invocation_index", ast::BuiltinValue::kLocalInvocationIndex},
+ BuiltinData{"global_invocation_id", ast::BuiltinValue::kGlobalInvocationId},
+ BuiltinData{"workgroup_id", ast::BuiltinValue::kWorkgroupId},
+ BuiltinData{"num_workgroups", ast::BuiltinValue::kNumWorkgroups},
+ BuiltinData{"sample_index", ast::BuiltinValue::kSampleIndex},
+ BuiltinData{"sample_mask", ast::BuiltinValue::kSampleMask}));
TEST_F(ParserImplTest, Attribute_Builtin_MissingLeftParen) {
auto p = parser("builtin position)");
@@ -182,6 +212,32 @@ TEST_F(ParserImplTest, Attribute_Interpolate_Flat) {
EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kNone);
}
+TEST_F(ParserImplTest, Attribute_Interpolate_Single_TrailingComma) {
+ auto p = parser("interpolate(flat,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+
+ auto* interp = var_attr->As<ast::InterpolateAttribute>();
+ EXPECT_EQ(interp->type, ast::InterpolationType::kFlat);
+ EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kNone);
+}
+
+TEST_F(ParserImplTest, Attribute_Interpolate_Single_DoubleTrailingComma) {
+ auto p = parser("interpolate(flat,,)");
+ auto attr = p->attribute();
+ EXPECT_FALSE(attr.matched);
+ EXPECT_TRUE(attr.errored);
+ EXPECT_EQ(attr.value, nullptr);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:18: expected identifier for interpolation sample name");
+}
+
TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Center) {
auto p = parser("interpolate(perspective, center)");
auto attr = p->attribute();
@@ -198,6 +254,22 @@ TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Center) {
EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
}
+TEST_F(ParserImplTest, Attribute_Interpolate_Double_TrailingComma) {
+ auto p = parser("interpolate(perspective, center,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+
+ auto* interp = var_attr->As<ast::InterpolateAttribute>();
+ EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
+ EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
+}
+
TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Centroid) {
auto p = parser("interpolate(perspective, centroid)");
auto attr = p->attribute();
@@ -257,7 +329,7 @@ TEST_F(ParserImplTest, Attribute_Interpolate_MissingFirstValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:13: invalid interpolation type");
+ EXPECT_EQ(p->error(), "1:13: expected identifier for interpolation type name");
}
TEST_F(ParserImplTest, Attribute_Interpolate_InvalidFirstValue) {
@@ -270,16 +342,6 @@ TEST_F(ParserImplTest, Attribute_Interpolate_InvalidFirstValue) {
EXPECT_EQ(p->error(), "1:13: invalid interpolation type");
}
-TEST_F(ParserImplTest, Attribute_Interpolate_MissingSecondValue) {
- auto p = parser("interpolate(perspective,)");
- auto attr = p->attribute();
- EXPECT_FALSE(attr.matched);
- EXPECT_TRUE(attr.errored);
- EXPECT_EQ(attr.value, nullptr);
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:25: invalid interpolation sampling");
-}
-
TEST_F(ParserImplTest, Attribute_Interpolate_InvalidSecondValue) {
auto p = parser("interpolate(perspective, nope)");
auto attr = p->attribute();
@@ -305,6 +367,21 @@ TEST_F(ParserImplTest, Attribute_Binding) {
EXPECT_EQ(binding->value, 4u);
}
+TEST_F(ParserImplTest, Attribute_Binding_TrailingComma) {
+ auto p = parser("binding(4,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(var_attr->Is<ast::BindingAttribute>());
+
+ auto* binding = var_attr->As<ast::BindingAttribute>();
+ EXPECT_EQ(binding->value, 4u);
+}
+
TEST_F(ParserImplTest, Attribute_Binding_MissingLeftParen) {
auto p = parser("binding 4)");
auto attr = p->attribute();
@@ -360,6 +437,21 @@ TEST_F(ParserImplTest, Attribute_group) {
EXPECT_EQ(group->value, 4u);
}
+TEST_F(ParserImplTest, Attribute_group_TrailingComma) {
+ auto p = parser("group(4,)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_FALSE(p->has_error());
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_TRUE(var_attr->Is<ast::GroupAttribute>());
+
+ auto* group = var_attr->As<ast::GroupAttribute>();
+ EXPECT_EQ(group->value, 4u);
+}
+
TEST_F(ParserImplTest, Attribute_Group_MissingLeftParen) {
auto p = parser("group 2)");
auto attr = p->attribute();
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
index 70ec394afd7..2fee83c38a7 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
@@ -51,7 +51,7 @@ TEST_F(ParserImplTest, VariableDecl_Unicode_Parses) {
TEST_F(ParserImplTest, VariableDecl_Inferred_Parses) {
auto p = parser("var my_var = 1.0");
- auto v = p->variable_decl(/*allow_inferred = */ true);
+ auto v = p->variable_decl();
EXPECT_FALSE(p->has_error());
EXPECT_TRUE(v.matched);
EXPECT_FALSE(v.errored);
@@ -68,19 +68,10 @@ TEST_F(ParserImplTest, VariableDecl_MissingVar) {
EXPECT_FALSE(v.errored);
EXPECT_FALSE(p->has_error());
- auto t = p->next();
+ auto& t = p->next();
ASSERT_TRUE(t.IsIdentifier());
}
-TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) {
- auto p = parser("var my_var f32");
- auto v = p->variable_decl();
- EXPECT_FALSE(v.matched);
- EXPECT_TRUE(v.errored);
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:12: expected ':' for variable declaration");
-}
-
TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
auto p = parser("var<private> my_var : f32");
auto v = p->variable_decl();
@@ -97,6 +88,17 @@ TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
EXPECT_EQ(v->source.range.end.column, 20u);
}
+TEST_F(ParserImplTest, VariableDecl_WithPushConstant) {
+ auto p = parser("var<push_constant> my_var : f32");
+ auto v = p->variable_decl();
+ EXPECT_TRUE(v.matched);
+ EXPECT_FALSE(v.errored);
+ EXPECT_FALSE(p->has_error());
+ EXPECT_EQ(v->name, "my_var");
+ EXPECT_TRUE(v->type->Is<ast::F32>());
+ EXPECT_EQ(v->storage_class, ast::StorageClass::kPushConstant);
+}
+
TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
auto p = parser("var<unknown> my_var : f32");
auto v = p->variable_decl();
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc
index 3ffb29ec6c7..00dd59b43b9 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
auto p = parser("my_var : f32");
- auto decl = p->expect_variable_ident_decl("test");
+ auto decl = p->expect_ident_with_type_decl("test");
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(decl.errored);
ASSERT_EQ(decl->name, "my_var");
@@ -30,9 +30,29 @@ TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
EXPECT_EQ(decl->type->source.range, (Source::Range{{1u, 10u}, {1u, 13u}}));
}
-TEST_F(ParserImplTest, VariableIdentDecl_Inferred_Parses) {
+TEST_F(ParserImplTest, VariableIdentDecl_Parses_AllowInferredType) {
+ auto p = parser("my_var : f32");
+ auto decl = p->expect_optionally_typed_ident("test");
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_FALSE(decl.errored);
+ ASSERT_EQ(decl->name, "my_var");
+ ASSERT_NE(decl->type, nullptr);
+ ASSERT_TRUE(decl->type->Is<ast::F32>());
+
+ EXPECT_EQ(decl->source.range, (Source::Range{{1u, 1u}, {1u, 7u}}));
+ EXPECT_EQ(decl->type->source.range, (Source::Range{{1u, 10u}, {1u, 13u}}));
+}
+
+TEST_F(ParserImplTest, VariableIdentDecl_Inferred_Parse_Failure) {
+ auto p = parser("my_var = 1.0");
+ auto decl = p->expect_ident_with_type_decl("test");
+ ASSERT_TRUE(p->has_error());
+ ASSERT_EQ(p->error(), "1:8: expected ':' for test");
+}
+
+TEST_F(ParserImplTest, VariableIdentDecl_Inferred_Parses_AllowInferredType) {
auto p = parser("my_var = 1.0");
- auto decl = p->expect_variable_ident_decl("test", /*allow_inferred = */ true);
+ auto decl = p->expect_optionally_typed_ident("test");
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(decl.errored);
ASSERT_EQ(decl->name, "my_var");
@@ -43,23 +63,31 @@ TEST_F(ParserImplTest, VariableIdentDecl_Inferred_Parses) {
TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
auto p = parser(": f32");
- auto decl = p->expect_variable_ident_decl("test");
+ auto decl = p->expect_ident_with_type_decl("test");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:1: expected identifier for test");
}
-TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) {
- auto p = parser("my_var f32");
- auto decl = p->expect_variable_ident_decl("test");
+TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent_AllowInferredType) {
+ auto p = parser(": f32");
+ auto decl = p->expect_optionally_typed_ident("test");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
- ASSERT_EQ(p->error(), "1:8: expected ':' for test");
+ ASSERT_EQ(p->error(), "1:1: expected identifier for test");
}
TEST_F(ParserImplTest, VariableIdentDecl_MissingType) {
auto p = parser("my_var :");
- auto decl = p->expect_variable_ident_decl("test");
+ auto decl = p->expect_ident_with_type_decl("test");
+ ASSERT_TRUE(p->has_error());
+ ASSERT_TRUE(decl.errored);
+ ASSERT_EQ(p->error(), "1:9: invalid type for test");
+}
+
+TEST_F(ParserImplTest, VariableIdentDecl_MissingType_AllowInferredType) {
+ auto p = parser("my_var :");
+ auto decl = p->expect_optionally_typed_ident("test");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:9: invalid type for test");
@@ -67,7 +95,15 @@ TEST_F(ParserImplTest, VariableIdentDecl_MissingType) {
TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
auto p = parser("123 : f32");
- auto decl = p->expect_variable_ident_decl("test");
+ auto decl = p->expect_ident_with_type_decl("test");
+ ASSERT_TRUE(p->has_error());
+ ASSERT_TRUE(decl.errored);
+ ASSERT_EQ(p->error(), "1:1: expected identifier for test");
+}
+
+TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent_AllowInferredType) {
+ auto p = parser("123 : f32");
+ auto decl = p->expect_optionally_typed_ident("test");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:1: expected identifier for test");
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
index de63f923b06..5362d38d980 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
@@ -40,7 +40,7 @@ TEST_P(VariableQualifierTest, ParsesStorageClass) {
EXPECT_EQ(sc->storage_class, params.storage_class);
EXPECT_EQ(sc->access, params.access);
- auto t = p->next();
+ auto& t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
@@ -50,7 +50,6 @@ INSTANTIATE_TEST_SUITE_P(
VariableStorageData{"uniform", ast::StorageClass::kUniform, ast::Access::kUndefined},
VariableStorageData{"workgroup", ast::StorageClass::kWorkgroup, ast::Access::kUndefined},
VariableStorageData{"storage", ast::StorageClass::kStorage, ast::Access::kUndefined},
- VariableStorageData{"storage_buffer", ast::StorageClass::kStorage, ast::Access::kUndefined},
VariableStorageData{"private", ast::StorageClass::kPrivate, ast::Access::kUndefined},
VariableStorageData{"function", ast::StorageClass::kFunction, ast::Access::kUndefined},
VariableStorageData{"storage, read", ast::StorageClass::kStorage, ast::Access::kRead},
@@ -73,7 +72,7 @@ TEST_F(ParserImplTest, VariableQualifier_Empty) {
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(sc.errored);
EXPECT_FALSE(sc.matched);
- EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
+ EXPECT_EQ(p->error(), "1:2: expected identifier for storage class");
}
TEST_F(ParserImplTest, VariableQualifier_MissingLessThan) {
@@ -83,8 +82,8 @@ TEST_F(ParserImplTest, VariableQualifier_MissingLessThan) {
EXPECT_FALSE(sc.errored);
EXPECT_FALSE(sc.matched);
- auto t = p->next();
- ASSERT_TRUE(t.Is(Token::Type::kPrivate));
+ auto& t = p->next();
+ ASSERT_TRUE(t.Is(Token::Type::kIdentifier));
}
TEST_F(ParserImplTest, VariableQualifier_MissingLessThan_AfterSC) {
@@ -94,8 +93,8 @@ TEST_F(ParserImplTest, VariableQualifier_MissingLessThan_AfterSC) {
EXPECT_FALSE(sc.errored);
EXPECT_FALSE(sc.matched);
- auto t = p->next();
- ASSERT_TRUE(t.Is(Token::Type::kPrivate));
+ auto& t = p->next();
+ ASSERT_TRUE(t.Is(Token::Type::kIdentifier));
}
TEST_F(ParserImplTest, VariableQualifier_MissingGreaterThan) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc
index ee899478a89..c370262bd8a 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc
@@ -19,7 +19,7 @@ namespace {
TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
auto p = parser("var a : i32;");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -38,7 +38,7 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
auto p = parser("var a : i32 = 1;");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -58,17 +58,17 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
TEST_F(ParserImplTest, VariableStmt_VariableDecl_ConstructorInvalid) {
auto p = parser("var a : i32 = if(a) {}");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:15: missing constructor for variable declaration");
+ EXPECT_EQ(p->error(), "1:15: missing initializer for 'var' declaration");
}
TEST_F(ParserImplTest, VariableStmt_VariableDecl_ArrayInit) {
auto p = parser("var a : array<i32> = array<i32>();");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -86,7 +86,7 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_ArrayInit) {
TEST_F(ParserImplTest, VariableStmt_VariableDecl_ArrayInit_NoSpace) {
auto p = parser("var a : array<i32>=array<i32>();");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -104,7 +104,7 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_ArrayInit_NoSpace) {
TEST_F(ParserImplTest, VariableStmt_VariableDecl_VecInit) {
auto p = parser("var a : vec2<i32> = vec2<i32>();");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -122,7 +122,7 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_VecInit) {
TEST_F(ParserImplTest, VariableStmt_VariableDecl_VecInit_NoSpace) {
auto p = parser("var a : vec2<i32>=vec2<i32>();");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -140,7 +140,7 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_VecInit_NoSpace) {
TEST_F(ParserImplTest, VariableStmt_Let) {
auto p = parser("let a : i32 = 1");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
@@ -155,32 +155,32 @@ TEST_F(ParserImplTest, VariableStmt_Let) {
TEST_F(ParserImplTest, VariableStmt_Let_MissingEqual) {
auto p = parser("let a : i32 1");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:13: expected '=' for let declaration");
+ EXPECT_EQ(p->error(), "1:13: expected '=' for 'let' declaration");
}
TEST_F(ParserImplTest, VariableStmt_Let_MissingConstructor) {
auto p = parser("let a : i32 =");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:14: missing constructor for let declaration");
+ EXPECT_EQ(p->error(), "1:14: missing initializer for 'let' declaration");
}
TEST_F(ParserImplTest, VariableStmt_Let_InvalidConstructor) {
auto p = parser("let a : i32 = if (a) {}");
- auto e = p->variable_stmt();
+ auto e = p->variable_statement();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:15: missing constructor for let declaration");
+ EXPECT_EQ(p->error(), "1:15: missing initializer for 'let' declaration");
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
new file mode 100644
index 00000000000..247f340dce3
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
@@ -0,0 +1,157 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+#include "src/tint/ast/discard_statement.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+using WhileStmtTest = ParserImplTest;
+
+// Test an empty while loop.
+TEST_F(WhileStmtTest, Empty) {
+ auto p = parser("while (true) { }");
+ auto wl = p->while_statement();
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_FALSE(wl.errored);
+ ASSERT_TRUE(wl.matched);
+ EXPECT_TRUE(Is<ast::Expression>(wl->condition));
+ EXPECT_TRUE(wl->body->Empty());
+}
+
+// Test a while loop with non-empty body.
+TEST_F(WhileStmtTest, Body) {
+ auto p = parser("while (true) { discard; }");
+ auto wl = p->while_statement();
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_FALSE(wl.errored);
+ ASSERT_TRUE(wl.matched);
+ EXPECT_TRUE(Is<ast::Expression>(wl->condition));
+ ASSERT_EQ(wl->body->statements.Length(), 1u);
+ EXPECT_TRUE(wl->body->statements[0]->Is<ast::DiscardStatement>());
+}
+
+// Test a while loop with complex condition.
+TEST_F(WhileStmtTest, ComplexCondition) {
+ auto p = parser("while ((a + 1 - 2) == 3) { }");
+ auto wl = p->while_statement();
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_FALSE(wl.errored);
+ ASSERT_TRUE(wl.matched);
+ EXPECT_TRUE(Is<ast::Expression>(wl->condition));
+ EXPECT_TRUE(wl->body->Empty());
+}
+
+// Test a while loop with no brackets.
+TEST_F(WhileStmtTest, NoBrackets) {
+ auto p = parser("while (a + 1 - 2) == 3 { }");
+ auto wl = p->while_statement();
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_FALSE(wl.errored);
+ ASSERT_TRUE(wl.matched);
+ EXPECT_TRUE(Is<ast::BinaryExpression>(wl->condition));
+ EXPECT_TRUE(wl->body->Empty());
+}
+
+class WhileStmtErrorTest : public ParserImplTest {
+ public:
+ void TestForWithError(std::string for_str, std::string error_str) {
+ auto p_for = parser(for_str);
+ auto e_for = p_for->while_statement();
+
+ EXPECT_FALSE(e_for.matched);
+ EXPECT_TRUE(e_for.errored);
+ EXPECT_TRUE(p_for->has_error());
+ ASSERT_EQ(e_for.value, nullptr);
+ EXPECT_EQ(p_for->error(), error_str);
+ }
+};
+
+// Test a while loop with missing left parenthesis is invalid.
+TEST_F(WhileStmtErrorTest, MissingLeftParen) {
+ std::string while_str = "while bool) { }";
+ std::string error_str = "1:11: expected '(' for type constructor";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a while loop with missing condition is invalid.
+TEST_F(WhileStmtErrorTest, MissingFirstSemicolon) {
+ std::string while_str = "while () {}";
+ std::string error_str = "1:8: unable to parse expression";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a while loop with missing right parenthesis is invalid.
+TEST_F(WhileStmtErrorTest, MissingRightParen) {
+ std::string while_str = "while (true {}";
+ std::string error_str = "1:13: expected ')'";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a while loop with missing left brace is invalid.
+TEST_F(WhileStmtErrorTest, MissingLeftBrace) {
+ std::string while_str = "while (true) }";
+ std::string error_str = "1:14: expected '{'";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a for loop with missing right brace is invalid.
+TEST_F(WhileStmtErrorTest, MissingRightBrace) {
+ std::string while_str = "while (true) {";
+ std::string error_str = "1:15: expected '}'";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a while loop with an invalid break condition.
+TEST_F(WhileStmtErrorTest, InvalidBreakConditionAsExpression) {
+ std::string while_str = "while ((0 == 1) { }";
+ std::string error_str = "1:17: expected ')'";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a while loop with a break condition not matching
+// logical_or_expression.
+TEST_F(WhileStmtErrorTest, InvalidBreakConditionMatch) {
+ std::string while_str = "while (var i: i32 = 0) { }";
+ std::string error_str = "1:8: unable to parse expression";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a while loop with an invalid body.
+TEST_F(WhileStmtErrorTest, InvalidBody) {
+ std::string while_str = "while (true) { let x: i32; }";
+ std::string error_str = "1:26: expected '=' for 'let' declaration";
+
+ TestForWithError(while_str, error_str);
+}
+
+// Test a for loop with a body not matching statements
+TEST_F(WhileStmtErrorTest, InvalidBodyMatch) {
+ std::string while_str = "while (true) { fn main() {} }";
+ std::string error_str = "1:16: expected '}'";
+
+ TestForWithError(while_str, error_str);
+}
+
+} // namespace
+} // namespace tint::reader::wgsl
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_test.cc
index 1f0e206c744..860120cc576 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/parser_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/parser_test.cc
@@ -41,7 +41,7 @@ fn main() -> @location(0) vec4<f32> {
auto errs = diag::Formatter().format(program.Diagnostics());
ASSERT_TRUE(program.IsValid()) << errs;
- ASSERT_EQ(1u, program.AST().Functions().size());
+ ASSERT_EQ(1u, program.AST().Functions().Length());
}
TEST_F(ParserTest, HandlesError) {
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/token.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/token.cc
index 4680eee0d7f..ac5eb089222 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/token.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/token.cc
@@ -29,12 +29,16 @@ std::string_view Token::TypeToName(Type type) {
return "abstract float literal";
case Token::Type::kFloatLiteral_F:
return "'f'-suffixed float literal";
+ case Token::Type::kFloatLiteral_H:
+ return "'h'-suffixed float literal";
case Token::Type::kIntLiteral:
return "abstract integer literal";
case Token::Type::kIntLiteral_I:
return "'i'-suffixed integer literal";
case Token::Type::kIntLiteral_U:
return "'u'-suffixed integer literal";
+ case Token::Type::kPlaceholder:
+ return "placeholder";
case Token::Type::kUninitialized:
return "uninitialized";
@@ -126,6 +130,10 @@ std::string_view Token::TypeToName(Type type) {
return "|=";
case Token::Type::kXorEqual:
return "^=";
+ case Token::Type::kShiftLeftEqual:
+ return "<<=";
+ case Token::Type::kShiftRightEqual:
+ return ">>=";
case Token::Type::kArray:
return "array";
@@ -139,6 +147,8 @@ std::string_view Token::TypeToName(Type type) {
return "break";
case Token::Type::kCase:
return "case";
+ case Token::Type::kConst:
+ return "const";
case Token::Type::kContinue:
return "continue";
case Token::Type::kContinuing:
@@ -163,14 +173,10 @@ std::string_view Token::TypeToName(Type type) {
return "fn";
case Token::Type::kFor:
return "for";
- case Token::Type::kFunction:
- return "function";
case Token::Type::kI32:
return "i32";
case Token::Type::kIf:
return "if";
- case Token::Type::kImport:
- return "import";
case Token::Type::kLet:
return "let";
case Token::Type::kLoop:
@@ -195,8 +201,6 @@ std::string_view Token::TypeToName(Type type) {
return "mat4x4";
case Token::Type::kOverride:
return "override";
- case Token::Type::kPrivate:
- return "private";
case Token::Type::kPtr:
return "ptr";
case Token::Type::kReturn:
@@ -205,8 +209,8 @@ std::string_view Token::TypeToName(Type type) {
return "sampler";
case Token::Type::kComparisonSampler:
return "sampler_comparison";
- case Token::Type::kStorage:
- return "storage";
+ case Token::Type::kStaticAssert:
+ return "static_assert";
case Token::Type::kStruct:
return "struct";
case Token::Type::kSwitch:
@@ -251,8 +255,6 @@ std::string_view Token::TypeToName(Type type) {
return "type";
case Token::Type::kU32:
return "u32";
- case Token::Type::kUniform:
- return "uniform";
case Token::Type::kVar:
return "var";
case Token::Type::kVec2:
@@ -261,8 +263,8 @@ std::string_view Token::TypeToName(Type type) {
return "vec3";
case Token::Type::kVec4:
return "vec4";
- case Token::Type::kWorkgroup:
- return "workgroup";
+ case Token::Type::kWhile:
+ return "while";
}
return "<unknown>";
@@ -289,13 +291,9 @@ Token::Token(Type type, const Source& source) : type_(type), source_(source) {}
Token::Token(Token&&) = default;
-Token::Token(const Token&) = default;
-
Token::~Token() = default;
-Token& Token::operator=(const Token& rhs) = default;
-
-bool Token::operator==(std::string_view ident) {
+bool Token::operator==(std::string_view ident) const {
if (type_ != Type::kIdentifier) {
return false;
}
@@ -311,6 +309,8 @@ std::string Token::to_str() const {
return std::to_string(std::get<double>(value_));
case Type::kFloatLiteral_F:
return std::to_string(std::get<double>(value_)) + "f";
+ case Type::kFloatLiteral_H:
+ return std::to_string(std::get<double>(value_)) + "h";
case Type::kIntLiteral:
return std::to_string(std::get<int64_t>(value_));
case Type::kIntLiteral_I:
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/token.h b/chromium/third_party/dawn/src/tint/reader/wgsl/token.h
index 0a68f9b0554..d8b93c61671 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/token.h
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/token.h
@@ -17,8 +17,7 @@
#include <string>
#include <string_view>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <variant> // NOLINT(build/include_order))
+#include <variant>
#include "src/tint/source.h"
@@ -33,6 +32,8 @@ class Token {
kError = -2,
/// Uninitialized token
kUninitialized = 0,
+ /// Placeholder token which maybe fillled in later
+ kPlaceholder = 1,
/// End of input string reached
kEOF,
@@ -42,6 +43,8 @@ class Token {
kFloatLiteral,
/// A float literal with an 'f' suffix
kFloatLiteral_F,
+ /// A float literal with an 'h' suffix
+ kFloatLiteral_H,
/// An integer literal with no suffix
kIntLiteral,
/// An integer literal with an 'i' suffix
@@ -137,6 +140,10 @@ class Token {
kOrEqual,
/// A '^='
kXorEqual,
+ /// A '>>='
+ kShiftRightEqual,
+ /// A '<<='
+ kShiftLeftEqual,
/// A 'array'
kArray,
@@ -150,6 +157,8 @@ class Token {
kBreak,
/// A 'case'
kCase,
+ /// A 'const'
+ kConst,
/// A 'continue'
kContinue,
/// A 'continuing'
@@ -174,14 +183,10 @@ class Token {
kFn,
// A 'for'
kFor,
- /// A 'function'
- kFunction,
/// A 'i32'
kI32,
/// A 'if'
kIf,
- /// A 'import'
- kImport,
/// A 'let'
kLet,
/// A 'loop'
@@ -206,8 +211,6 @@ class Token {
kMat4x4,
/// A 'override'
kOverride,
- /// A 'private'
- kPrivate,
/// A 'ptr'
kPtr,
/// A 'return'
@@ -216,8 +219,8 @@ class Token {
kSampler,
/// A 'sampler_comparison'
kComparisonSampler,
- /// A 'storage'
- kStorage,
+ /// A 'static_assert'
+ kStaticAssert,
/// A 'struct'
kStruct,
/// A 'switch'
@@ -262,8 +265,6 @@ class Token {
kType,
/// A 'u32'
kU32,
- /// A 'uniform'
- kUniform,
/// A 'var'
kVar,
/// A 'vec2'
@@ -272,8 +273,8 @@ class Token {
kVec3,
/// A 'vec4'
kVec4,
- /// A 'workgroup'
- kWorkgroup,
+ /// A 'while'
+ kWhile,
};
/// Converts a token type to a name
@@ -315,19 +316,16 @@ class Token {
Token(Type type, const Source& source, double val);
/// Move constructor
Token(Token&&);
- /// Copy constructor
- Token(const Token&);
~Token();
- /// Assignment operator
- /// @param b the token to copy
- /// @return Token
- Token& operator=(const Token& b);
-
/// Equality operator with an identifier
/// @param ident the identifier string
/// @return true if this token is an identifier and is equal to ident.
- bool operator==(std::string_view ident);
+ bool operator==(std::string_view ident) const;
+
+ /// Sets the token to the given type
+ /// @param type the type to set
+ void SetType(Token::Type type) { type_ = type; }
/// Returns true if the token is of the given type
/// @param t the type to check against.
@@ -336,6 +334,8 @@ class Token {
/// @returns true if the token is uninitialized
bool IsUninitialized() const { return type_ == Type::kUninitialized; }
+ /// @returns true if the token is a placeholder
+ bool IsPlaceholder() const { return type_ == Type::kPlaceholder; }
/// @returns true if the token is EOF
bool IsEof() const { return type_ == Type::kEOF; }
/// @returns true if the token is Error
@@ -346,7 +346,8 @@ class Token {
bool IsLiteral() const {
return type_ == Type::kIntLiteral || type_ == Type::kIntLiteral_I ||
type_ == Type::kIntLiteral_U || type_ == Type::kFalse || type_ == Type::kTrue ||
- type_ == Type::kFloatLiteral || type_ == Type::kFloatLiteral_F;
+ type_ == Type::kFloatLiteral || type_ == Type::kFloatLiteral_F ||
+ type_ == Type::kFloatLiteral_H;
}
/// @returns true if token is a 'matNxM'
bool IsMatrix() const {
@@ -376,9 +377,18 @@ class Token {
return type_ == Type::kVec2 || type_ == Type::kVec3 || type_ == Type::kVec4;
}
+ /// @returns true if the token can be split during parse into component tokens
+ bool IsSplittable() const {
+ return Is(Token::Type::kShiftRight) || Is(Token::Type::kGreaterThanEqual) ||
+ Is(Token::Type::kAndAnd);
+ }
+
/// @returns the source information for this token
Source source() const { return source_; }
+ /// @returns the type of the token
+ Type type() const { return type_; }
+
/// Returns the string value of the token
/// @return std::string
std::string to_str() const;
diff --git a/chromium/third_party/dawn/src/tint/reader/wgsl/token_test.cc b/chromium/third_party/dawn/src/tint/reader/wgsl/token_test.cc
index 93fe8349ca3..fd4515fabb2 100644
--- a/chromium/third_party/dawn/src/tint/reader/wgsl/token_test.cc
+++ b/chromium/third_party/dawn/src/tint/reader/wgsl/token_test.cc
@@ -85,6 +85,8 @@ TEST_F(TokenTest, ToStr) {
EXPECT_THAT(Token(Token::Type::kFloatLiteral, Source{}, d).to_str(), Not(EndsWith("f")));
EXPECT_THAT(Token(Token::Type::kFloatLiteral_F, Source{}, d).to_str(), StartsWith("123"));
EXPECT_THAT(Token(Token::Type::kFloatLiteral_F, Source{}, d).to_str(), EndsWith("f"));
+ EXPECT_THAT(Token(Token::Type::kFloatLiteral_H, Source{}, d).to_str(), StartsWith("123"));
+ EXPECT_THAT(Token(Token::Type::kFloatLiteral_H, Source{}, d).to_str(), EndsWith("h"));
EXPECT_EQ(Token(Token::Type::kIntLiteral, Source{}, i).to_str(), "123");
EXPECT_EQ(Token(Token::Type::kIntLiteral_I, Source{}, i).to_str(), "123i");
EXPECT_EQ(Token(Token::Type::kIntLiteral_U, Source{}, i).to_str(), "123u");
diff --git a/chromium/third_party/dawn/src/tint/resolver/array_accessor_test.cc b/chromium/third_party/dawn/src/tint/resolver/array_accessor_test.cc
index d9ef10e4e71..a07f6dfd2a0 100644
--- a/chromium/third_party/dawn/src/tint/resolver/array_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/array_accessor_test.cc
@@ -16,6 +16,7 @@
#include "gmock/gmock.h"
#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/index_accessor_expression.h"
#include "src/tint/sem/reference.h"
using namespace tint::number_suffixes; // NOLINT
@@ -26,7 +27,7 @@ namespace {
using ResolverIndexAccessorTest = ResolverTest;
TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
- Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1_f));
WrapInFunction(acc);
@@ -35,22 +36,32 @@ TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
}
TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Ref) {
- Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
auto* acc = IndexAccessor("my_var", idx);
WrapInFunction(Decl(idx), acc);
EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions_Dynamic_Ref) {
- Global("my_var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
auto* idx = Var("idx", ty.u32(), Expr(3_u));
auto* idy = Var("idy", ty.u32(), Expr(2_u));
auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
WrapInFunction(Decl(idx), Decl(idy), acc);
EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic) {
@@ -61,12 +72,17 @@ TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic) {
EXPECT_TRUE(r()->Resolve());
EXPECT_EQ(r()->error(), "");
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Matrix_XDimension_Dynamic) {
- GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
+ GlobalConst("my_const", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
auto* idx = Var("idx", ty.u32(), Expr(3_u));
- auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
+ auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
WrapInFunction(Decl(idx), acc);
EXPECT_TRUE(r()->Resolve());
@@ -74,9 +90,9 @@ TEST_F(ResolverIndexAccessorTest, Matrix_XDimension_Dynamic) {
}
TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic) {
- GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
+ GlobalConst("my_const", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
auto* idx = Var("idy", ty.u32(), Expr(2_u));
- auto* acc = IndexAccessor(IndexAccessor("my_var", Expr(Source{{12, 34}}, idx)), 1_i);
+ auto* acc = IndexAccessor(IndexAccessor("my_const", Expr(Source{{12, 34}}, idx)), 1_i);
WrapInFunction(Decl(idx), acc);
EXPECT_TRUE(r()->Resolve());
@@ -84,7 +100,7 @@ TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic) {
}
TEST_F(ResolverIndexAccessorTest, Matrix) {
- Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2_i);
WrapInFunction(acc);
@@ -97,10 +113,15 @@ TEST_F(ResolverIndexAccessorTest, Matrix) {
auto* ref = TypeOf(acc)->As<sem::Reference>();
ASSERT_TRUE(ref->StoreType()->Is<sem::Vector>());
EXPECT_EQ(ref->StoreType()->As<sem::Vector>()->Width(), 3u);
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
- Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor(IndexAccessor("my_var", 2_i), 1_i);
WrapInFunction(acc);
@@ -112,10 +133,15 @@ TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
auto* ref = TypeOf(acc)->As<sem::Reference>();
EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Vector_F32) {
- Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2_f));
WrapInFunction(acc);
@@ -124,25 +150,30 @@ TEST_F(ResolverIndexAccessorTest, Vector_F32) {
}
TEST_F(ResolverIndexAccessorTest, Vector_Dynamic_Ref) {
- Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* idx = Var("idx", ty.i32(), Expr(2_i));
auto* acc = IndexAccessor("my_var", idx);
WrapInFunction(Decl(idx), acc);
EXPECT_TRUE(r()->Resolve());
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Vector_Dynamic) {
- GlobalConst("my_var", ty.vec3<f32>(), Construct(ty.vec3<f32>()));
+ GlobalConst("my_const", ty.vec3<f32>(), Construct(ty.vec3<f32>()));
auto* idx = Var("idx", ty.i32(), Expr(2_i));
- auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
+ auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
WrapInFunction(Decl(idx), acc);
EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverIndexAccessorTest, Vector) {
- Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2_i);
WrapInFunction(acc);
@@ -154,10 +185,15 @@ TEST_F(ResolverIndexAccessorTest, Vector) {
auto* ref = TypeOf(acc)->As<sem::Reference>();
EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Array_Literal_i32) {
- Global("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2_i);
WrapInFunction(acc);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -165,10 +201,15 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_i32) {
auto* ref = TypeOf(acc)->As<sem::Reference>();
ASSERT_NE(ref, nullptr);
EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Array_Literal_u32) {
- Global("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2_u);
WrapInFunction(acc);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -176,10 +217,15 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_u32) {
auto* ref = TypeOf(acc)->As<sem::Reference>();
ASSERT_NE(ref, nullptr);
EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Array_Literal_AInt) {
- Global("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2_a);
WrapInFunction(acc);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -187,12 +233,17 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_AInt) {
auto* ref = TypeOf(acc)->As<sem::Reference>();
ASSERT_NE(ref, nullptr);
EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Alias_Array) {
auto* aary = Alias("myarrty", ty.array<f32, 3>());
- Global("my_var", ty.Of(aary), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.Of(aary), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2_i);
WrapInFunction(acc);
@@ -204,12 +255,17 @@ TEST_F(ResolverIndexAccessorTest, Alias_Array) {
auto* ref = TypeOf(acc)->As<sem::Reference>();
EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Array_Constant) {
- GlobalConst("my_var", ty.array<f32, 3>(), array<f32, 3>());
+ GlobalConst("my_const", ty.array<f32, 3>(), array<f32, 3>());
- auto* acc = IndexAccessor("my_var", 2_i);
+ auto* acc = IndexAccessor("my_const", 2_i);
WrapInFunction(acc);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -224,17 +280,22 @@ TEST_F(ResolverIndexAccessorTest, Array_Dynamic_I32) {
// var f : f32 = a[idx];
auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
- auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ auto* acc = IndexAccessor("a", Expr(Source{{12, 34}}, idx));
+ auto* f = Var("f", ty.f32(), acc);
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(a),
Decl(idx),
Decl(f),
- },
- ast::AttributeList{});
+ });
EXPECT_TRUE(r()->Resolve());
EXPECT_EQ(r()->error(), "");
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Array_Literal_F32) {
@@ -242,12 +303,11 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_F32) {
// var f : f32 = a[2.0f];
auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
auto* f = Var("a_2", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, 2_f)));
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(a),
Decl(f),
- },
- ast::AttributeList{});
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
}
@@ -256,14 +316,19 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_I32) {
// let a : array<f32, 3>;
// var f : f32 = a[2i];
auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
- auto* f = Var("a_2", ty.f32(), IndexAccessor("a", 2_i));
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ auto* acc = IndexAccessor("a", 2_i);
+ auto* f = Var("a_2", ty.f32(), acc);
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(a),
Decl(f),
- },
- ast::AttributeList{});
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Expr_Deref_FuncGoodParent) {
@@ -275,11 +340,16 @@ TEST_F(ResolverIndexAccessorTest, Expr_Deref_FuncGoodParent) {
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
auto* idx = Let("idx", ty.u32(), Construct(ty.u32()));
auto* star_p = Deref(p);
- auto* accessor_expr = IndexAccessor(Source{{12, 34}}, star_p, idx);
- auto* x = Var("x", ty.f32(), accessor_expr);
- Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
+ auto* acc = IndexAccessor(Source{{12, 34}}, star_p, idx);
+ auto* x = Var("x", ty.f32(), acc);
+ Func("func", utils::Vector{p}, ty.f32(), utils::Vector{Decl(idx), Decl(x), Return(x)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto idx_sem = Sem().Get<sem::IndexAccessorExpression>(acc);
+ ASSERT_NE(idx_sem, nullptr);
+ EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
+ EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
}
TEST_F(ResolverIndexAccessorTest, Expr_Deref_FuncBadParent) {
@@ -293,7 +363,7 @@ TEST_F(ResolverIndexAccessorTest, Expr_Deref_FuncBadParent) {
auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
auto* star_p = Deref(accessor_expr);
auto* x = Var("x", ty.f32(), star_p);
- Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
+ Func("func", utils::Vector{p}, ty.f32(), utils::Vector{Decl(idx), Decl(x), Return(x)});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
diff --git a/chromium/third_party/dawn/src/tint/resolver/assignment_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/assignment_validation_test.cc
index 64363e39428..d6a7e5c977e 100644
--- a/chromium/third_party/dawn/src/tint/resolver/assignment_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/assignment_validation_test.cc
@@ -29,12 +29,14 @@ TEST_F(ResolverAssignmentValidationTest, ReadOnlyBuffer) {
// struct S { m : i32 };
// @group(0) @binding(0)
// var<storage,read> a : S;
- auto* s = Structure("S", {Member("m", ty.i32())});
- Global(Source{{12, 34}}, "a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{
+ Member("m", ty.i32()),
+ });
+ GlobalVar(Source{{12, 34}}, "a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("a", "m"), 1_i));
@@ -61,7 +63,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignIncompatibleTypes) {
}
TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpressions_Pass) {
- // let len = 4u;
+ // const len = 4u;
// {
// var a : array<f32, 4u>;
// var b : array<f32, len>;
@@ -80,7 +82,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpression
}
TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpressions_Fail) {
- // let len = 5u;
+ // const len = 5u;
// {
// var a : array<f32, 4u>;
// var b : array<f32, len>;
@@ -222,7 +224,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignToLet_Fail) {
WrapInFunction(var, Assign(Expr(Source{{12, 34}}, "a"), 2_i));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: cannot assign to const\nnote: 'a' is declared here:");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot assign to 'let'\nnote: 'a' is declared here:");
}
TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Handle) {
@@ -235,16 +237,16 @@ TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Handle) {
ast::Access::kWrite);
};
- Global("a", make_type(), ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
- Global("b", make_type(), ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("a", make_type(), ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+ GlobalVar("b", make_type(), ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
WrapInFunction(Assign(Source{{56, 78}}, "a", "b"));
@@ -257,12 +259,14 @@ TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Atomic) {
// @group(0) @binding(0) var<storage, read_write> v : S;
// v.a = v.a;
- auto* s = Structure("S", {Member("a", ty.atomic(ty.i32()))});
- Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.atomic(ty.i32())),
+ });
+ GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
@@ -275,12 +279,14 @@ TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_RuntimeArray) {
// @group(0) @binding(0) var<storage, read_write> v : S;
// v.a = v.a;
- auto* s = Structure("S", {Member("a", ty.array(ty.f32()))});
- Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.array(ty.f32())),
+ });
+ GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
@@ -296,8 +302,10 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_NonConstructibleStruct_Fa
// fn f() {
// _ = s;
// }
- auto* s = Structure("S", {Member("arr", ty.array<i32>())});
- Global("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
+ auto* s = Structure("S", utils::Vector{
+ Member("arr", ty.array<i32>()),
+ });
+ GlobalVar("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
WrapInFunction(Assign(Phony(), Expr(Source{{12, 34}}, "s")));
@@ -316,8 +324,10 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_DynamicArray_Fail) {
// fn f() {
// _ = s.arr;
// }
- auto* s = Structure("S", {Member("arr", ty.array<i32>())});
- Global("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
+ auto* s = Structure("S", utils::Vector{
+ Member("arr", ty.array<i32>()),
+ });
+ GlobalVar("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
WrapInFunction(Assign(Phony(), MemberAccessor(Source{{12, 34}}, "s", "arr")));
@@ -360,16 +370,19 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_Pass) {
// _ = wg;
// _ = wg[3i];
// }
- auto* S = Structure("S", {
+ auto* S = Structure("S", utils::Vector{
Member("i", ty.i32()),
Member("arr", ty.array<i32>()),
});
- auto* U = Structure("U", {Member("i", ty.i32())});
- Global("tex", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(0, 0));
- Global("smp", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 1));
- Global("u", ty.Of(U), ast::StorageClass::kUniform, GroupAndBinding(0, 2));
- Global("s", ty.Of(S), ast::StorageClass::kStorage, GroupAndBinding(0, 3));
- Global("wg", ty.array<f32, 10>(), ast::StorageClass::kWorkgroup);
+ auto* U = Structure("U", utils::Vector{
+ Member("i", ty.i32()),
+ });
+ GlobalVar("tex", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ GroupAndBinding(0, 0));
+ GlobalVar("smp", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 1));
+ GlobalVar("u", ty.Of(U), ast::StorageClass::kUniform, GroupAndBinding(0, 2));
+ GlobalVar("s", ty.Of(S), ast::StorageClass::kStorage, GroupAndBinding(0, 3));
+ GlobalVar("wg", ty.array<f32, 10>(), ast::StorageClass::kWorkgroup);
WrapInFunction(Assign(Phony(), 1_i), //
Assign(Phony(), 2_u), //
diff --git a/chromium/third_party/dawn/src/tint/resolver/atomics_test.cc b/chromium/third_party/dawn/src/tint/resolver/atomics_test.cc
index c0fe5ce2995..d7b382454bf 100644
--- a/chromium/third_party/dawn/src/tint/resolver/atomics_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/atomics_test.cc
@@ -25,7 +25,7 @@ namespace {
struct ResolverAtomicTest : public resolver::TestHelper, public testing::Test {};
TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
- auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
+ auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
@@ -35,7 +35,7 @@ TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
}
TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
- auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.u32()), ast::StorageClass::kWorkgroup);
+ auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.u32()), ast::StorageClass::kWorkgroup);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
@@ -45,12 +45,12 @@ TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
}
TEST_F(ResolverAtomicTest, GlobalStorageStruct) {
- auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
- auto* g = Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+ auto* g = GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
diff --git a/chromium/third_party/dawn/src/tint/resolver/atomics_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/atomics_validation_test.cc
index 78c1fb94f71..09613974cbc 100644
--- a/chromium/third_party/dawn/src/tint/resolver/atomics_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/atomics_validation_test.cc
@@ -27,35 +27,35 @@ namespace {
struct ResolverAtomicValidationTest : public resolver::TestHelper, public testing::Test {};
TEST_F(ResolverAtomicValidationTest, StorageClass_WorkGroup) {
- Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverAtomicValidationTest, StorageClass_Storage) {
- Global("g", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kStorage,
- ast::Access::kReadWrite, GroupAndBinding(0, 0));
+ GlobalVar("g", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kStorage,
+ ast::Access::kReadWrite, GroupAndBinding(0, 0));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverAtomicValidationTest, StorageClass_Storage_Struct) {
- auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
- Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- GroupAndBinding(0, 0));
+ auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ GroupAndBinding(0, 0));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverAtomicValidationTest, InvalidType) {
- Global("a", ty.atomic(ty.f32(Source{{12, 34}})), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic(ty.f32(Source{{12, 34}})), ast::StorageClass::kWorkgroup);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
}
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Simple) {
- Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -64,7 +64,7 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Simple) {
}
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Array) {
- Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -73,8 +73,8 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Array) {
}
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Struct) {
- auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -88,9 +88,10 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStruct) {
// struct Outer { m : array<Inner, 4>; };
// var<private> g : Outer;
- auto* Inner = Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
- auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
- Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
+ auto* Inner =
+ Structure("Inner", utils::Vector{Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
+ auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
+ GlobalVar("g", ty.Of(Outer), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -104,9 +105,10 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStructOfArray)
// struct Outer { m : array<Inner, 4>; };
// var<private> g : Outer;
- auto* Inner = Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
- auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
- Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
+ auto* Inner =
+ Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
+ auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
+ GlobalVar("g", ty.Of(Outer), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -121,7 +123,7 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfArray) {
auto* atomic_array =
Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
- Global(Source{{56, 78}}, "v", ty.Of(atomic_array), ast::StorageClass::kPrivate);
+ GlobalVar(Source{{56, 78}}, "v", ty.Of(atomic_array), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -135,8 +137,8 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStruct) {
// };
// var<private> v: array<S, 5u>;
- auto* s = Structure("S", {Member("m", ty.atomic<u32>())});
- Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
+ auto* s = Structure("S", utils::Vector{Member("m", ty.atomic<u32>())});
+ GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -154,8 +156,8 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStructOfArray) {
auto* atomic_array =
Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
- auto* s = Structure("S", {Member("m", ty.Of(atomic_array))});
- Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
+ auto* s = Structure("S", utils::Vector{Member("m", ty.Of(atomic_array))});
+ GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -185,18 +187,18 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Complex) {
auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8_u);
auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4_u);
- auto* s6 = Structure("S6", {Member("x", array_i32_4)});
- auto* s5 = Structure("S5", {Member("x", ty.Of(s6)), //
- Member("y", ty.Of(atomic_array)), //
- Member("z", array_atomic_u32_8)}); //
- auto* s4 = Structure("S4", {Member("x", ty.Of(s6)), //
- Member("y", ty.Of(s5)), //
- Member("z", array_atomic_i32_4)}); //
- auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
- auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
- auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
- auto* s0 = Structure("S0", {Member("x", ty.Of(s1))});
- Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kPrivate);
+ auto* s6 = Structure("S6", utils::Vector{Member("x", array_i32_4)});
+ auto* s5 = Structure("S5", utils::Vector{Member("x", ty.Of(s6)), //
+ Member("y", ty.Of(atomic_array)), //
+ Member("z", array_atomic_u32_8)}); //
+ auto* s4 = Structure("S4", utils::Vector{Member("x", ty.Of(s6)), //
+ Member("y", ty.Of(s5)), //
+ Member("z", array_atomic_i32_4)}); //
+ auto* s3 = Structure("S3", utils::Vector{Member("x", ty.Of(s4))});
+ auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
+ auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
+ auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -206,9 +208,9 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Complex) {
}
TEST_F(ResolverAtomicValidationTest, Struct_AccessMode_Read) {
- auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
- Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- GroupAndBinding(0, 0));
+ auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -218,9 +220,9 @@ TEST_F(ResolverAtomicValidationTest, Struct_AccessMode_Read) {
}
TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Struct) {
- auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
- Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- GroupAndBinding(0, 0));
+ auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -234,10 +236,11 @@ TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStruct) {
// struct Outer { m : array<Inner, 4>; };
// var<storage, read> g : Outer;
- auto* Inner = Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
- auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
- Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
- GroupAndBinding(0, 0));
+ auto* Inner =
+ Structure("Inner", utils::Vector{Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
+ auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -251,10 +254,11 @@ TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStructOfArray) {
// struct Outer { m : array<Inner, 4>; };
// var<storage, read> g : Outer;
- auto* Inner = Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
- auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
- Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
- GroupAndBinding(0, 0));
+ auto* Inner =
+ Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
+ auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -284,19 +288,19 @@ TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Complex) {
auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8_u);
auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4_u);
- auto* s6 = Structure("S6", {Member("x", array_i32_4)});
- auto* s5 = Structure("S5", {Member("x", ty.Of(s6)), //
- Member("y", ty.Of(atomic_array)), //
- Member("z", array_atomic_u32_8)}); //
- auto* s4 = Structure("S4", {Member("x", ty.Of(s6)), //
- Member("y", ty.Of(s5)), //
- Member("z", array_atomic_i32_4)}); //
- auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
- auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
- auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
- auto* s0 = Structure("S0", {Member("x", ty.Of(s1))});
- Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kStorage, ast::Access::kRead,
- GroupAndBinding(0, 0));
+ auto* s6 = Structure("S6", utils::Vector{Member("x", array_i32_4)});
+ auto* s5 = Structure("S5", utils::Vector{Member("x", ty.Of(s6)), //
+ Member("y", ty.Of(atomic_array)), //
+ Member("z", array_atomic_u32_8)}); //
+ auto* s4 = Structure("S4", utils::Vector{Member("x", ty.Of(s6)), //
+ Member("y", ty.Of(s5)), //
+ Member("z", array_atomic_i32_4)}); //
+ auto* s3 = Structure("S3", utils::Vector{Member("x", ty.Of(s4))});
+ auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
+ auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
+ auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -309,7 +313,7 @@ TEST_F(ResolverAtomicValidationTest, Local) {
WrapInFunction(Var("a", ty.atomic(Source{{12, 34}}, ty.i32())));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: function variable must have a constructible type");
+ EXPECT_EQ(r()->error(), "12:34 error: function-scope 'var' must have a constructible type");
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/resolver/attribute_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/attribute_validation_test.cc
index 3280ebf46b9..ed0227e7790 100644
--- a/chromium/third_party/dawn/src/tint/resolver/attribute_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/attribute_validation_test.cc
@@ -84,16 +84,16 @@ struct TestParams {
};
struct TestWithParams : ResolverTestWithParam<TestParams> {};
-static ast::AttributeList createAttributes(const Source& source,
- ProgramBuilder& builder,
- AttributeKind kind) {
+static utils::Vector<const ast::Attribute*, 2> createAttributes(const Source& source,
+ ProgramBuilder& builder,
+ AttributeKind kind) {
switch (kind) {
case AttributeKind::kAlign:
return {builder.create<ast::StructMemberAlignAttribute>(source, 4u)};
case AttributeKind::kBinding:
return {builder.create<ast::BindingAttribute>(source, 1u)};
case AttributeKind::kBuiltin:
- return {builder.Builtin(source, ast::Builtin::kPosition)};
+ return {builder.Builtin(source, ast::BuiltinValue::kPosition)};
case AttributeKind::kGroup:
return {builder.create<ast::GroupAttribute>(source, 1u)};
case AttributeKind::kId:
@@ -128,8 +128,10 @@ TEST_P(FunctionParameterAttributeTest, IsValid) {
auto& params = GetParam();
Func("main",
- ast::VariableList{Param("a", ty.vec4<f32>(), createAttributes({}, *this, params.kind))},
- ty.void_(), {});
+ utils::Vector{
+ Param("a", ty.vec4<f32>(), createAttributes({}, *this, params.kind)),
+ },
+ ty.void_(), utils::Empty);
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -161,8 +163,11 @@ using FunctionReturnTypeAttributeTest = TestWithParams;
TEST_P(FunctionReturnTypeAttributeTest, IsValid) {
auto& params = GetParam();
- Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1_f)}, {},
- createAttributes({}, *this, params.kind));
+ Func("main", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Empty, createAttributes({}, *this, params.kind));
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -195,9 +200,15 @@ namespace EntryPointInputAndOutputTests {
using ComputeShaderParameterAttributeTest = TestWithParams;
TEST_P(ComputeShaderParameterAttributeTest, IsValid) {
auto& params = GetParam();
- auto* p = Param("a", ty.vec4<f32>(), createAttributes(Source{{12, 34}}, *this, params.kind));
- Func("main", ast::VariableList{p}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ Func("main",
+ utils::Vector{
+ Param("a", ty.vec4<f32>(), createAttributes(Source{{12, 34}}, *this, params.kind)),
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -239,10 +250,13 @@ TEST_P(FragmentShaderParameterAttributeTest, IsValid) {
auto& params = GetParam();
auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
if (params.kind != AttributeKind::kBuiltin && params.kind != AttributeKind::kLocation) {
- attrs.push_back(Builtin(Source{{34, 56}}, ast::Builtin::kPosition));
+ attrs.Push(Builtin(Source{{34, 56}}, ast::BuiltinValue::kPosition));
}
auto* p = Param("a", ty.vec4<f32>(), attrs);
- Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func("frag_main", utils::Vector{p}, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -273,11 +287,19 @@ TEST_P(VertexShaderParameterAttributeTest, IsValid) {
auto& params = GetParam();
auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
if (params.kind != AttributeKind::kLocation) {
- attrs.push_back(Location(Source{{34, 56}}, 2));
+ attrs.Push(Location(Source{{34, 56}}, 2));
}
auto* p = Param("a", ty.vec4<f32>(), attrs);
- Func("vertex_main", ast::VariableList{p}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
+ Func("vertex_main", utils::Vector{p}, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -316,8 +338,14 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
using ComputeShaderReturnTypeAttributeTest = TestWithParams;
TEST_P(ComputeShaderReturnTypeAttributeTest, IsValid) {
auto& params = GetParam();
- Func("main", ast::VariableList{}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>(), 1_f))},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)},
+ Func("main", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>(), 1_f)),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ },
createAttributes(Source{{12, 34}}, *this, params.kind));
if (params.should_pass) {
@@ -361,9 +389,13 @@ using FragmentShaderReturnTypeAttributeTest = TestWithParams;
TEST_P(FragmentShaderReturnTypeAttributeTest, IsValid) {
auto& params = GetParam();
auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
- attrs.push_back(Location(Source{{34, 56}}, 2));
- Func("frag_main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- {Stage(ast::PipelineStage::kFragment)}, attrs);
+ attrs.Push(Location(Source{{34, 56}}, 2));
+ Func("frag_main", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{Return(Construct(ty.vec4<f32>()))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ attrs);
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -411,10 +443,16 @@ TEST_P(VertexShaderReturnTypeAttributeTest, IsValid) {
auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
// a vertex shader must include the 'position' builtin in its return type
if (params.kind != AttributeKind::kBuiltin) {
- attrs.push_back(Builtin(Source{{34, 56}}, ast::Builtin::kPosition));
+ attrs.Push(Builtin(Source{{34, 56}}, ast::BuiltinValue::kPosition));
}
- Func("vertex_main", ast::VariableList{}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- {Stage(ast::PipelineStage::kVertex)}, attrs);
+ Func("vertex_main", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ attrs);
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -450,9 +488,14 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
using EntryPointParameterAttributeTest = TestWithParams;
TEST_F(EntryPointParameterAttributeTest, DuplicateAttribute) {
- Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)},
- {
+ Func("main", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
Location(Source{{12, 34}}, 2),
Location(Source{{56, 78}}, 3),
});
@@ -465,22 +508,30 @@ TEST_F(EntryPointParameterAttributeTest, DuplicateAttribute) {
TEST_F(EntryPointParameterAttributeTest, DuplicateInternalAttribute) {
auto* s = Param("s", ty.sampler(ast::SamplerKind::kSampler),
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
Disable(ast::DisabledValidation::kBindingPointCollision),
Disable(ast::DisabledValidation::kEntryPointParameter),
});
- Func("f", {s}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func("f", utils::Vector{s}, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
using EntryPointReturnTypeAttributeTest = ResolverTest;
TEST_F(EntryPointReturnTypeAttributeTest, DuplicateAttribute) {
- Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1_f)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
- ast::AttributeList{
+ Func("main", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
Location(Source{{12, 34}}, 2),
Location(Source{{56, 78}}, 3),
});
@@ -492,8 +543,11 @@ TEST_F(EntryPointReturnTypeAttributeTest, DuplicateAttribute) {
}
TEST_F(EntryPointReturnTypeAttributeTest, DuplicateInternalAttribute) {
- Func("f", {}, ty.i32(), {Return(1_i)}, {Stage(ast::PipelineStage::kFragment)},
- ast::AttributeList{
+ Func("f", utils::Empty, ty.i32(), utils::Vector{Return(1_i)},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
Disable(ast::DisabledValidation::kBindingPointCollision),
Disable(ast::DisabledValidation::kEntryPointParameter),
});
@@ -508,7 +562,7 @@ using SpirvBlockAttribute = transform::AddSpirvBlockAttribute::SpirvBlockAttribu
TEST_P(StructAttributeTest, IsValid) {
auto& params = GetParam();
- auto* str = create<ast::Struct>(Sym("mystruct"), ast::StructMemberList{Member("a", ty.f32())},
+ auto* str = create<ast::Struct>(Sym("mystruct"), utils::Vector{Member("a", ty.f32())},
createAttributes(Source{{12, 34}}, *this, params.kind));
AST().AddGlobalDeclaration(str);
@@ -539,16 +593,14 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
using StructMemberAttributeTest = TestWithParams;
TEST_P(StructMemberAttributeTest, IsValid) {
auto& params = GetParam();
- ast::StructMemberList members;
+ utils::Vector<const ast::StructMember*, 1> members;
if (params.kind == AttributeKind::kBuiltin) {
- members.push_back(
- {Member("a", ty.vec4<f32>(), createAttributes(Source{{12, 34}}, *this, params.kind))});
+ members.Push(
+ Member("a", ty.vec4<f32>(), createAttributes(Source{{12, 34}}, *this, params.kind)));
} else {
- members.push_back(
- {Member("a", ty.f32(), createAttributes(Source{{12, 34}}, *this, params.kind))});
+ members.Push(Member("a", ty.f32(), createAttributes(Source{{12, 34}}, *this, params.kind)));
}
Structure("mystruct", members);
- WrapInFunction();
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
@@ -574,38 +626,35 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kBindingAndGroup, false}));
TEST_F(StructMemberAttributeTest, DuplicateAttribute) {
Structure("mystruct",
- {
+ utils::Vector{
Member("a", ty.i32(),
- {
+ utils::Vector{
create<ast::StructMemberAlignAttribute>(Source{{12, 34}}, 4u),
create<ast::StructMemberAlignAttribute>(Source{{56, 78}}, 8u),
}),
});
- WrapInFunction();
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(56:78 error: duplicate align attribute
12:34 note: first attribute declared here)");
}
TEST_F(StructMemberAttributeTest, InvariantAttributeWithPosition) {
- Structure("mystruct", {
+ Structure("mystruct", utils::Vector{
Member("a", ty.vec4<f32>(),
- {
+ utils::Vector{
Invariant(),
- Builtin(ast::Builtin::kPosition),
+ Builtin(ast::BuiltinValue::kPosition),
}),
});
- WrapInFunction();
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(StructMemberAttributeTest, InvariantAttributeWithoutPosition) {
- Structure("mystruct", {
+ Structure("mystruct", utils::Vector{
Member("a", ty.vec4<f32>(),
- {
+ utils::Vector{
Invariant(Source{{12, 34}}),
}),
});
- WrapInFunction();
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: invariant attribute must only be applied to a "
@@ -619,12 +668,10 @@ TEST_P(ArrayAttributeTest, IsValid) {
auto& params = GetParam();
auto* arr = ty.array(ty.f32(), nullptr, createAttributes(Source{{12, 34}}, *this, params.kind));
- Structure("mystruct", {
+ Structure("mystruct", utils::Vector{
Member("a", arr),
});
- WrapInFunction();
-
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
@@ -654,21 +701,19 @@ TEST_P(VariableAttributeTest, IsValid) {
auto& params = GetParam();
if (IsBindingAttribute(params.kind)) {
- Global("a", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
- createAttributes(Source{{12, 34}}, *this, params.kind));
+ GlobalVar("a", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
+ createAttributes(Source{{12, 34}}, *this, params.kind));
} else {
- Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
- createAttributes(Source{{12, 34}}, *this, params.kind));
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
+ createAttributes(Source{{12, 34}}, *this, params.kind));
}
- WrapInFunction();
-
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
if (!IsBindingAttribute(params.kind)) {
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for variables");
+ EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for module-scope 'var'");
}
}
}
@@ -690,14 +735,12 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kBindingAndGroup, true}));
TEST_F(VariableAttributeTest, DuplicateAttribute) {
- Global("a", ty.sampler(ast::SamplerKind::kSampler),
- ast::AttributeList{
- create<ast::BindingAttribute>(Source{{12, 34}}, 2),
- create<ast::GroupAttribute>(2),
- create<ast::BindingAttribute>(Source{{56, 78}}, 3),
- });
-
- WrapInFunction();
+ GlobalVar("a", ty.sampler(ast::SamplerKind::kSampler),
+ utils::Vector{
+ create<ast::BindingAttribute>(Source{{12, 34}}, 2u),
+ create<ast::GroupAttribute>(2u),
+ create<ast::BindingAttribute>(Source{{56, 78}}, 3u),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -707,8 +750,8 @@ TEST_F(VariableAttributeTest, DuplicateAttribute) {
TEST_F(VariableAttributeTest, LocalVariable) {
auto* v = Var("a", ty.f32(),
- ast::AttributeList{
- create<ast::BindingAttribute>(Source{{12, 34}}, 2),
+ utils::Vector{
+ create<ast::BindingAttribute>(Source{{12, 34}}, 2u),
});
WrapInFunction(v);
@@ -724,13 +767,12 @@ TEST_P(ConstantAttributeTest, IsValid) {
GlobalConst("a", ty.f32(), Expr(1.23_f),
createAttributes(Source{{12, 34}}, *this, params.kind));
- WrapInFunction();
-
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for constants");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: attribute is not valid for module-scope 'const' declaration");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -739,7 +781,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kBinding, false},
TestParams{AttributeKind::kBuiltin, false},
TestParams{AttributeKind::kGroup, false},
- TestParams{AttributeKind::kId, true},
+ TestParams{AttributeKind::kId, false},
TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false},
@@ -752,12 +794,53 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TEST_F(ConstantAttributeTest, DuplicateAttribute) {
GlobalConst("a", ty.f32(), Expr(1.23_f),
- ast::AttributeList{
- create<ast::IdAttribute>(Source{{12, 34}}, 0),
- create<ast::IdAttribute>(Source{{56, 78}}, 1),
+ utils::Vector{
+ create<ast::IdAttribute>(Source{{12, 34}}, 0u),
+ create<ast::IdAttribute>(Source{{56, 78}}, 1u),
});
- WrapInFunction();
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(56:78 error: duplicate id attribute
+12:34 note: first attribute declared here)");
+}
+
+using OverrideAttributeTest = TestWithParams;
+TEST_P(OverrideAttributeTest, IsValid) {
+ auto& params = GetParam();
+
+ Override("a", ty.f32(), Expr(1.23_f), createAttributes(Source{{12, 34}}, *this, params.kind));
+
+ if (params.should_pass) {
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ } else {
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for 'override' declaration");
+ }
+}
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+ OverrideAttributeTest,
+ testing::Values(TestParams{AttributeKind::kAlign, false},
+ TestParams{AttributeKind::kBinding, false},
+ TestParams{AttributeKind::kBuiltin, false},
+ TestParams{AttributeKind::kGroup, false},
+ TestParams{AttributeKind::kId, true},
+ TestParams{AttributeKind::kInterpolate, false},
+ TestParams{AttributeKind::kInvariant, false},
+ TestParams{AttributeKind::kLocation, false},
+ TestParams{AttributeKind::kOffset, false},
+ TestParams{AttributeKind::kSize, false},
+ TestParams{AttributeKind::kStage, false},
+ TestParams{AttributeKind::kStride, false},
+ TestParams{AttributeKind::kWorkgroup, false},
+ TestParams{AttributeKind::kBindingAndGroup, false}));
+
+TEST_F(OverrideAttributeTest, DuplicateAttribute) {
+ Override("a", ty.f32(), Expr(1.23_f),
+ utils::Vector{
+ create<ast::IdAttribute>(Source{{12, 34}}, 0u),
+ create<ast::IdAttribute>(Source{{56, 78}}, 1u),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -794,9 +877,12 @@ TEST_P(ArrayStrideTest, All) {
<< ", should_pass: " << params.should_pass;
SCOPED_TRACE(ss.str());
- auto* arr = ty.array(Source{{12, 34}}, el_ty, 4_u, params.stride);
+ auto* arr = ty.array(el_ty, 4_u,
+ utils::Vector{
+ create<ast::StrideAttribute>(Source{{12, 34}}, params.stride),
+ });
- Global("myarray", arr, ast::StorageClass::kPrivate);
+ GlobalVar("myarray", arr, ast::StorageClass::kPrivate);
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -805,7 +891,7 @@ TEST_P(ArrayStrideTest, All) {
EXPECT_EQ(r()->error(),
"12:34 error: arrays decorated with the stride attribute must "
"have a stride that is at least the size of the element type, "
- "and be a multiple of the element type's alignment value.");
+ "and be a multiple of the element type's alignment value");
}
}
@@ -874,12 +960,12 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TEST_F(ArrayStrideTest, DuplicateAttribute) {
auto* arr = ty.array(Source{{12, 34}}, ty.i32(), 4_u,
- {
- create<ast::StrideAttribute>(Source{{12, 34}}, 4_i),
- create<ast::StrideAttribute>(Source{{56, 78}}, 4_i),
+ utils::Vector{
+ create<ast::StrideAttribute>(Source{{12, 34}}, 4u),
+ create<ast::StrideAttribute>(Source{{56, 78}}, 4u),
});
- Global("myarray", arr, ast::StorageClass::kPrivate);
+ GlobalVar("myarray", arr, ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -895,8 +981,10 @@ namespace {
using ResourceAttributeTest = ResolverTest;
TEST_F(ResourceAttributeTest, UniformBufferMissingBinding) {
- auto* s = Structure("S", {Member("x", ty.i32())});
- Global(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kUniform);
+ auto* s = Structure("S", utils::Vector{
+ Member("x", ty.i32()),
+ });
+ GlobalVar(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kUniform);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -904,8 +992,10 @@ TEST_F(ResourceAttributeTest, UniformBufferMissingBinding) {
}
TEST_F(ResourceAttributeTest, StorageBufferMissingBinding) {
- auto* s = Structure("S", {Member("x", ty.i32())});
- Global(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead);
+ auto* s = Structure("S", utils::Vector{
+ Member("x", ty.i32()),
+ });
+ GlobalVar(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -913,8 +1003,8 @@ TEST_F(ResourceAttributeTest, StorageBufferMissingBinding) {
}
TEST_F(ResourceAttributeTest, TextureMissingBinding) {
- Global(Source{{12, 34}}, "G", ty.depth_texture(ast::TextureDimension::k2d),
- ast::StorageClass::kNone);
+ GlobalVar(Source{{12, 34}}, "G", ty.depth_texture(ast::TextureDimension::k2d),
+ ast::StorageClass::kNone);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -922,7 +1012,8 @@ TEST_F(ResourceAttributeTest, TextureMissingBinding) {
}
TEST_F(ResourceAttributeTest, SamplerMissingBinding) {
- Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone);
+ GlobalVar(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
+ ast::StorageClass::kNone);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -930,10 +1021,11 @@ TEST_F(ResourceAttributeTest, SamplerMissingBinding) {
}
TEST_F(ResourceAttributeTest, BindingPairMissingBinding) {
- Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
+ ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::GroupAttribute>(1u),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -941,10 +1033,11 @@ TEST_F(ResourceAttributeTest, BindingPairMissingBinding) {
}
TEST_F(ResourceAttributeTest, BindingPairMissingGroup) {
- Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- });
+ GlobalVar(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
+ ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -952,27 +1045,29 @@ TEST_F(ResourceAttributeTest, BindingPairMissingGroup) {
}
TEST_F(ResourceAttributeTest, BindingPointUsedTwiceByEntryPoint) {
- Global(Source{{12, 34}}, "A", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
- ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
- Global(Source{{56, 78}}, "B", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
- ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("F", {}, ty.void_(),
- {
+ GlobalVar(Source{{12, 34}}, "A", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+ GlobalVar(Source{{56, 78}}, "B", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.vec4<f32>(), ast::StorageClass::kNone,
Call("textureLoad", "A", vec2<i32>(1_i, 2_i), 0_i))),
Decl(Var("b", ty.vec4<f32>(), ast::StorageClass::kNone,
Call("textureLoad", "B", vec2<i32>(1_i, 2_i), 0_i))),
},
- {Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -982,41 +1077,45 @@ TEST_F(ResourceAttributeTest, BindingPointUsedTwiceByEntryPoint) {
}
TEST_F(ResourceAttributeTest, BindingPointUsedTwiceByDifferentEntryPoints) {
- Global(Source{{12, 34}}, "A", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
- ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
- Global(Source{{56, 78}}, "B", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
- ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("F_A", {}, ty.void_(),
- {
+ GlobalVar(Source{{12, 34}}, "A", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+ GlobalVar(Source{{56, 78}}, "B", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("F_A", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.vec4<f32>(), ast::StorageClass::kNone,
Call("textureLoad", "A", vec2<i32>(1_i, 2_i), 0_i))),
},
- {Stage(ast::PipelineStage::kFragment)});
- Func("F_B", {}, ty.void_(),
- {
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
+ Func("F_B", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("b", ty.vec4<f32>(), ast::StorageClass::kNone,
Call("textureLoad", "B", vec2<i32>(1_i, 2_i), 0_i))),
},
- {Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResourceAttributeTest, BindingPointOnNonResource) {
- Global(Source{{12, 34}}, "G", ty.f32(), ast::StorageClass::kPrivate,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar(Source{{12, 34}}, "G", ty.f32(), ast::StorageClass::kPrivate,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -1030,24 +1129,38 @@ namespace InvariantAttributeTests {
namespace {
using InvariantAttributeTests = ResolverTest;
TEST_F(InvariantAttributeTests, InvariantWithPosition) {
- auto* param =
- Param("p", ty.vec4<f32>(),
- {Invariant(Source{{12, 34}}), Builtin(Source{{56, 78}}, ast::Builtin::kPosition)});
- Func("main", ast::VariableList{param}, ty.vec4<f32>(),
- ast::StatementList{Return(Construct(ty.vec4<f32>()))},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
- ast::AttributeList{
+ auto* param = Param("p", ty.vec4<f32>(),
+ utils::Vector{
+ Invariant(Source{{12, 34}}),
+ Builtin(Source{{56, 78}}, ast::BuiltinValue::kPosition),
+ });
+ Func("main", utils::Vector{param}, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
Location(0),
});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(InvariantAttributeTests, InvariantWithoutPosition) {
- auto* param = Param("p", ty.vec4<f32>(), {Invariant(Source{{12, 34}}), Location(0)});
- Func("main", ast::VariableList{param}, ty.vec4<f32>(),
- ast::StatementList{Return(Construct(ty.vec4<f32>()))},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
- ast::AttributeList{
+ auto* param = Param("p", ty.vec4<f32>(),
+ utils::Vector{
+ Invariant(Source{{12, 34}}),
+ Location(0),
+ });
+ Func("main", utils::Vector{param}, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
Location(0),
});
EXPECT_FALSE(r()->Resolve());
@@ -1063,15 +1176,20 @@ namespace {
using WorkgroupAttribute = ResolverTest;
TEST_F(WorkgroupAttribute, ComputeShaderPass) {
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute),
- create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(WorkgroupAttribute, Missing) {
- Func(Source{{12, 34}}, "main", {}, ty.void_(), {}, {Stage(ast::PipelineStage::kCompute)});
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -1080,8 +1198,10 @@ TEST_F(WorkgroupAttribute, Missing) {
}
TEST_F(WorkgroupAttribute, NotAnEntryPoint) {
- Func("main", {}, ty.void_(), {},
- {create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -1090,9 +1210,11 @@ TEST_F(WorkgroupAttribute, NotAnEntryPoint) {
}
TEST_F(WorkgroupAttribute, NotAComputeShader) {
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment),
- create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -1101,8 +1223,8 @@ TEST_F(WorkgroupAttribute, NotAComputeShader) {
}
TEST_F(WorkgroupAttribute, DuplicateAttribute) {
- Func(Source{{12, 34}}, "main", {}, ty.void_(), {},
- {
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(Source{{12, 34}}, 1_i, nullptr, nullptr),
WorkgroupSize(Source{{56, 78}}, 2_i, nullptr, nullptr),
@@ -1135,10 +1257,17 @@ TEST_P(InterpolateParameterTest, All) {
auto& params = GetParam();
Func("main",
- ast::VariableList{
+ utils::Vector{
Param("a", ty.f32(),
- {Location(0), Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
- ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Location(0),
+ Interpolate(Source{{12, 34}}, params.type, params.sampling),
+ }),
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1154,10 +1283,17 @@ TEST_P(InterpolateParameterTest, IntegerScalar) {
auto& params = GetParam();
Func("main",
- ast::VariableList{
+ utils::Vector{
Param("a", ty.i32(),
- {Location(0), Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
- ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Location(0),
+ Interpolate(Source{{12, 34}}, params.type, params.sampling),
+ }),
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (params.type != ast::InterpolationType::kFlat) {
EXPECT_FALSE(r()->Resolve());
@@ -1178,10 +1314,17 @@ TEST_P(InterpolateParameterTest, IntegerVector) {
auto& params = GetParam();
Func("main",
- ast::VariableList{
+ utils::Vector{
Param("a", ty.vec4<u32>(),
- {Location(0), Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
- ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Location(0),
+ Interpolate(Source{{12, 34}}, params.type, params.sampling),
+ }),
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (params.type != ast::InterpolationType::kFlat) {
EXPECT_FALSE(r()->Resolve());
@@ -1217,8 +1360,11 @@ INSTANTIATE_TEST_SUITE_P(
Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kSample, false}));
TEST_F(InterpolateTest, FragmentInput_Integer_MissingFlatInterpolation) {
- Func("main", ast::VariableList{Param(Source{{12, 34}}, "a", ty.i32(), {Location(0)})},
- ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Vector{Param(Source{{12, 34}}, "a", ty.i32(), utils::Vector{Location(0)})},
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -1227,12 +1373,19 @@ TEST_F(InterpolateTest, FragmentInput_Integer_MissingFlatInterpolation) {
}
TEST_F(InterpolateTest, VertexOutput_Integer_MissingFlatInterpolation) {
- auto* s = Structure("S", {
- Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
- Member(Source{{12, 34}}, "u", ty.u32(), {Location(0)}),
- });
- Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
- ast::AttributeList{Stage(ast::PipelineStage::kVertex)});
+ auto* s = Structure(
+ "S",
+ utils::Vector{
+ Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+ Member(Source{{12, 34}}, "u", ty.u32(), utils::Vector{Location(0)}),
+ });
+ Func("main", utils::Empty, ty.Of(s),
+ utils::Vector{
+ Return(Construct(ty.Of(s))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -1243,11 +1396,18 @@ note: while analysing entry point 'main')");
TEST_F(InterpolateTest, MissingLocationAttribute_Parameter) {
Func("main",
- ast::VariableList{Param("a", ty.vec4<f32>(),
- {Builtin(ast::Builtin::kPosition),
- Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
- ast::InterpolationSampling::kNone)})},
- ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Param("a", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
+ ast::InterpolationSampling::kNone),
+ }),
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -1255,11 +1415,18 @@ TEST_F(InterpolateTest, MissingLocationAttribute_Parameter) {
}
TEST_F(InterpolateTest, MissingLocationAttribute_ReturnType) {
- Func("main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
- {Builtin(ast::Builtin::kPosition),
- Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
- ast::InterpolationSampling::kNone)});
+ Func("main", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
+ ast::InterpolationSampling::kNone),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -1267,9 +1434,12 @@ TEST_F(InterpolateTest, MissingLocationAttribute_ReturnType) {
}
TEST_F(InterpolateTest, MissingLocationAttribute_Struct) {
- Structure("S", {Member("a", ty.f32(),
- {Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
- ast::InterpolationSampling::kNone)})});
+ Structure("S",
+ utils::Vector{
+ Member("a", ty.f32(),
+ utils::Vector{Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
+ ast::InterpolationSampling::kNone)}),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
diff --git a/chromium/third_party/dawn/src/tint/resolver/builtin_test.cc b/chromium/third_party/dawn/src/tint/resolver/builtin_test.cc
index 74a898ca709..6046a730f53 100644
--- a/chromium/third_party/dawn/src/tint/resolver/builtin_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/builtin_test.cc
@@ -44,73 +44,41 @@ using namespace tint::number_suffixes; // NOLINT
namespace tint::resolver {
namespace {
+using ExpressionList = utils::Vector<const ast::Expression*, 8>;
+
using BuiltinType = sem::BuiltinType;
using ResolverBuiltinTest = ResolverTest;
-using ResolverBuiltinDerivativeTest = ResolverTestWithParam<std::string>;
-TEST_P(ResolverBuiltinDerivativeTest, Scalar) {
- auto name = GetParam();
-
- Global("ident", ty.f32(), ast::StorageClass::kPrivate);
-
- auto* expr = Call(name, "ident");
- Func("func", {}, ty.void_(), {Ignore(expr)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(expr), nullptr);
- ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
-}
-
-TEST_P(ResolverBuiltinDerivativeTest, Vector) {
- auto name = GetParam();
- Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-
- auto* expr = Call(name, "ident");
- Func("func", {}, ty.void_(), {Ignore(expr)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+struct BuiltinData {
+ const char* name;
+ BuiltinType builtin;
+};
- ASSERT_NE(TypeOf(expr), nullptr);
- ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
- EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
- EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
+inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
+ out << data.name;
+ return out;
}
-TEST_P(ResolverBuiltinDerivativeTest, MissingParam) {
- auto name = GetParam();
-
- auto* expr = Call(name);
- WrapInFunction(expr);
+TEST_F(ResolverBuiltinTest, ModuleScopeUsage) {
+ GlobalConst("c", ty.f32(), Call(Source{{12, 34}}, "abs", 1._f));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: no matching call to " + name +
- "()\n\n"
- "2 candidate functions:\n " +
- name + "(f32) -> f32\n " + name + "(vecN<f32>) -> vecN<f32>\n");
+ // TODO(crbug.com/tint/1581): Once 'abs' is implemented as @const, this will no longer be an
+ // error.
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'const' initializer must be constant expression)");
}
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinDerivativeTest,
- testing::Values("dpdx",
- "dpdxCoarse",
- "dpdxFine",
- "dpdy",
- "dpdyCoarse",
- "dpdyFine",
- "fwidth",
- "fwidthCoarse",
- "fwidthFine"));
+// Tests for Logical builtins
+namespace logical_builtin_tests {
using ResolverBuiltinTest_BoolMethod = ResolverTestWithParam<std::string>;
+
TEST_P(ResolverBuiltinTest_BoolMethod, Scalar) {
auto name = GetParam();
- Global("my_var", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var");
WrapInFunction(expr);
@@ -123,7 +91,7 @@ TEST_P(ResolverBuiltinTest_BoolMethod, Scalar) {
TEST_P(ResolverBuiltinTest_BoolMethod, Vector) {
auto name = GetParam();
- Global("my_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var");
WrapInFunction(expr);
@@ -137,173 +105,10 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest,
ResolverBuiltinTest_BoolMethod,
testing::Values("any", "all"));
-enum class Texture { kF32, kI32, kU32 };
-inline std::ostream& operator<<(std::ostream& out, Texture data) {
- if (data == Texture::kF32) {
- out << "f32";
- } else if (data == Texture::kI32) {
- out << "i32";
- } else {
- out << "u32";
- }
- return out;
-}
-
-struct TextureTestParams {
- ast::TextureDimension dim;
- Texture type = Texture::kF32;
- ast::TexelFormat format = ast::TexelFormat::kR32Float;
-};
-inline std::ostream& operator<<(std::ostream& out, TextureTestParams data) {
- out << data.dim << "_" << data.type;
- return out;
-}
-
-class ResolverBuiltinTest_TextureOperation : public ResolverTestWithParam<TextureTestParams> {
- public:
- /// Gets an appropriate type for the coords parameter depending the the
- /// dimensionality of the texture being sampled.
- /// @param dim dimensionality of the texture being sampled
- /// @param scalar the scalar type
- /// @returns a pointer to a type appropriate for the coord param
- const ast::Type* GetCoordsType(ast::TextureDimension dim, const ast::Type* scalar) {
- switch (dim) {
- case ast::TextureDimension::k1d:
- return scalar;
- case ast::TextureDimension::k2d:
- case ast::TextureDimension::k2dArray:
- return ty.vec(scalar, 2);
- case ast::TextureDimension::k3d:
- case ast::TextureDimension::kCube:
- case ast::TextureDimension::kCubeArray:
- return ty.vec(scalar, 3);
- default:
- [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
- }
- return nullptr;
- }
-
- void add_call_param(std::string name, const ast::Type* type, ast::ExpressionList* call_params) {
- if (type->IsAnyOf<ast::Texture, ast::Sampler>()) {
- Global(name, type,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
-
- } else {
- Global(name, type, ast::StorageClass::kPrivate);
- }
-
- call_params->push_back(Expr(name));
- }
- const ast::Type* subtype(Texture type) {
- if (type == Texture::kF32) {
- return ty.f32();
- }
- if (type == Texture::kI32) {
- return ty.i32();
- }
- return ty.u32();
- }
-};
-
-using ResolverBuiltinTest_SampledTextureOperation = ResolverBuiltinTest_TextureOperation;
-TEST_P(ResolverBuiltinTest_SampledTextureOperation, TextureLoadSampled) {
- auto dim = GetParam().dim;
- auto type = GetParam().type;
-
- auto* s = subtype(type);
- auto* coords_type = GetCoordsType(dim, ty.i32());
- auto* texture_type = ty.sampled_texture(dim, s);
-
- ast::ExpressionList call_params;
-
- add_call_param("texture", texture_type, &call_params);
- add_call_param("coords", coords_type, &call_params);
- if (dim == ast::TextureDimension::k2dArray) {
- add_call_param("array_index", ty.i32(), &call_params);
- }
- add_call_param("level", ty.i32(), &call_params);
-
- auto* expr = Call("textureLoad", call_params);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(expr), nullptr);
- ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
- if (type == Texture::kF32) {
- EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
- } else if (type == Texture::kI32) {
- EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::I32>());
- } else {
- EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::U32>());
- }
- EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
-}
-
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_SampledTextureOperation,
- testing::Values(TextureTestParams{ast::TextureDimension::k1d},
- TextureTestParams{ast::TextureDimension::k2d},
- TextureTestParams{ast::TextureDimension::k2dArray},
- TextureTestParams{ast::TextureDimension::k3d}));
-
-TEST_F(ResolverBuiltinTest, Dot_Vec2) {
- Global("my_var", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-
- auto* expr = Call("dot", "my_var", "my_var");
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(expr), nullptr);
- EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
-}
-
-TEST_F(ResolverBuiltinTest, Dot_Vec3) {
- Global("my_var", ty.vec3<i32>(), ast::StorageClass::kPrivate);
-
- auto* expr = Call("dot", "my_var", "my_var");
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(expr), nullptr);
- EXPECT_TRUE(TypeOf(expr)->Is<sem::I32>());
-}
-
-TEST_F(ResolverBuiltinTest, Dot_Vec4) {
- Global("my_var", ty.vec4<u32>(), ast::StorageClass::kPrivate);
-
- auto* expr = Call("dot", "my_var", "my_var");
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(expr), nullptr);
- EXPECT_TRUE(TypeOf(expr)->Is<sem::U32>());
-}
-
-TEST_F(ResolverBuiltinTest, Dot_Error_Scalar) {
- auto* expr = Call("dot", 1_f, 1_f);
- WrapInFunction(expr);
-
- EXPECT_FALSE(r()->Resolve());
-
- EXPECT_EQ(r()->error(),
- R"(error: no matching call to dot(f32, f32)
-
-1 candidate function:
- dot(vecN<T>, vecN<T>) -> T where: T is f32, i32 or u32
-)");
-}
-
TEST_F(ResolverBuiltinTest, Select) {
- Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("bool_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("bool_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
auto* expr = Call("select", "my_var", "my_var", "bool_var");
WrapInFunction(expr);
@@ -326,9 +131,9 @@ TEST_F(ResolverBuiltinTest, Select_Error_NoParams) {
R"(error: no matching call to select()
3 candidate functions:
- select(T, T, bool) -> T where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
+ select(T, T, bool) -> T where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, f16, i32, u32 or bool
)");
}
@@ -342,9 +147,9 @@ TEST_F(ResolverBuiltinTest, Select_Error_SelectorInt) {
R"(error: no matching call to select(i32, i32, i32)
3 candidate functions:
- select(T, T, bool) -> T where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
+ select(T, T, bool) -> T where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, f16, i32, u32 or bool
)");
}
@@ -359,9 +164,9 @@ TEST_F(ResolverBuiltinTest, Select_Error_Matrix) {
R"(error: no matching call to select(mat2x2<f32>, mat2x2<f32>, bool)
3 candidate functions:
- select(T, T, bool) -> T where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
+ select(T, T, bool) -> T where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, f16, i32, u32 or bool
)");
}
@@ -375,9 +180,9 @@ TEST_F(ResolverBuiltinTest, Select_Error_MismatchTypes) {
R"(error: no matching call to select(f32, vec2<f32>, bool)
3 candidate functions:
- select(T, T, bool) -> T where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
+ select(T, T, bool) -> T where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, f16, i32, u32 or bool
)");
}
@@ -391,163 +196,528 @@ TEST_F(ResolverBuiltinTest, Select_Error_MismatchVectorSize) {
R"(error: no matching call to select(vec2<f32>, vec3<f32>, bool)
3 candidate functions:
- select(T, T, bool) -> T where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
+ select(T, T, bool) -> T where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, f16, i32, u32 or bool
+ select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, f16, i32, u32 or bool
)");
}
-struct BuiltinData {
+} // namespace logical_builtin_tests
+
+// Tests for Array builtins
+namespace array_builtin_tests {
+
+using ResolverBuiltinArrayTest = ResolverTest;
+
+TEST_F(ResolverBuiltinArrayTest, ArrayLength_Vector) {
+ auto* ary = ty.array<i32>();
+ auto* str = Structure("S", utils::Vector{Member("x", ary)});
+ GlobalVar("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+}
+
+TEST_F(ResolverBuiltinArrayTest, ArrayLength_Error_ArraySized) {
+ GlobalVar("arr", ty.array<i32, 4>(), ast::StorageClass::kPrivate);
+ auto* call = Call("arrayLength", AddressOf("arr"));
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching call to arrayLength(ptr<private, array<i32, 4>, read_write>)
+
+1 candidate function:
+ arrayLength(ptr<storage, array<T>, A>) -> u32
+)");
+}
+
+} // namespace array_builtin_tests
+
+// Tests for Numeric builtins with float parameter
+namespace float_builtin_tests {
+
+// Testcase parameters for float built-in having signature of (T, ...) -> T and (vecN<T>, ...) ->
+// vecN<T>
+struct BuiltinDataWithParamNum {
+ uint32_t args_number;
const char* name;
BuiltinType builtin;
};
-inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
+inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
out << data.name;
return out;
}
-using ResolverBuiltinTest_Barrier = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_Barrier, InferType) {
+// Tests for float built-ins that has signiture (T, ...) -> T and (vecN<T>, ...) -> vecN<T>
+using ResolverBuiltinTest_FloatBuiltin_IdenticalType =
+ ResolverTestWithParam<BuiltinDataWithParamNum>;
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, Error_NoParams) {
auto param = GetParam();
auto* call = Call(param.name);
- WrapInFunction(CallStmt(call));
+ WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) + "()"));
}
-TEST_P(ResolverBuiltinTest_Barrier, Error_TooManyParams) {
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Scalar_f32) {
auto param = GetParam();
- auto* call = Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f), 1_f);
- WrapInFunction(CallStmt(call));
+ auto* call = Call(param.name, 1_f);
+ WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) + "(f32)"));
+ }
}
-INSTANTIATE_TEST_SUITE_P(
- ResolverTest,
- ResolverBuiltinTest_Barrier,
- testing::Values(BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
- BuiltinData{"workgroupBarrier", BuiltinType::kWorkgroupBarrier}));
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Vector_f32) {
+ auto param = GetParam();
-using ResolverBuiltinTest_DataPacking = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_DataPacking, InferType) {
+ auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f));
+ WrapInFunction(call);
+
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<f32>)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, TwoParams_Scalar_f32) {
auto param = GetParam();
- bool pack4 =
- param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
+ auto* call = Call(param.name, 1_f, 1_f);
+ WrapInFunction(call);
- auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f))
- : Call(param.name, vec2<f32>(1_f, 2_f));
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(f32, f32)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, TwoParams_Vector_f32) {
+ auto param = GetParam();
+
+ auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<f32>, vec3<f32>)"));
+ }
}
-TEST_P(ResolverBuiltinTest_DataPacking, Error_IncorrectParamType) {
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Scalar_f32) {
auto param = GetParam();
- bool pack4 =
- param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
+ auto* call = Call(param.name, 1_f, 1_f, 1_f);
+ WrapInFunction(call);
- auto* call = pack4 ? Call(param.name, vec4<i32>(1_i, 2_i, 3_i, 4_i))
- : Call(param.name, vec2<i32>(1_i, 2_i));
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(f32, f32, f32)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Vector_f32) {
+ auto param = GetParam();
+
+ auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
+ vec3<f32>(1_f, 1_f, 3_f));
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<f32>, vec3<f32>, vec3<f32>)"));
+ }
}
-TEST_P(ResolverBuiltinTest_DataPacking, Error_NoParams) {
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, FourParams_Scalar_f32) {
auto param = GetParam();
- auto* call = Call(param.name);
+ auto* call = Call(param.name, 1_f, 1_f, 1_f, 1_f);
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(f32, f32, f32, f32)"));
+ }
}
-TEST_P(ResolverBuiltinTest_DataPacking, Error_TooManyParams) {
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, FourParams_Vector_f32) {
auto param = GetParam();
- bool pack4 =
- param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
+ auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
+ vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
+ WrapInFunction(call);
- auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f), 1_f)
- : Call(param.name, vec2<f32>(1_f, 2_f), 1_f);
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<f32>, vec3<f32>, vec3<f32>, vec3<f32>)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Scalar_f16) {
+ auto param = GetParam();
+
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call(param.name, 1_h);
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) + "(f16)"));
+ }
}
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_DataPacking,
- testing::Values(BuiltinData{"pack4x8snorm", BuiltinType::kPack4x8snorm},
- BuiltinData{"pack4x8unorm", BuiltinType::kPack4x8unorm},
- BuiltinData{"pack2x16snorm", BuiltinType::kPack2x16snorm},
- BuiltinData{"pack2x16unorm", BuiltinType::kPack2x16unorm},
- BuiltinData{"pack2x16float",
- BuiltinType::kPack2x16float}));
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Vector_f16) {
+ auto param = GetParam();
-using ResolverBuiltinTest_DataUnpacking = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_DataUnpacking, InferType) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h));
+ WrapInFunction(call);
+
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F16>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<f16>)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, TwoParams_Scalar_f16) {
auto param = GetParam();
- bool pack4 = param.builtin == BuiltinType::kUnpack4x8snorm ||
- param.builtin == BuiltinType::kUnpack4x8unorm;
+ Enable(ast::Extension::kF16);
- auto* call = Call(param.name, 1_u);
+ auto* call = Call(param.name, 1_h, 1_h);
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- if (pack4) {
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 4u);
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
} else {
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 2u);
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(f16, f16)"));
}
}
-INSTANTIATE_TEST_SUITE_P(
- ResolverTest,
- ResolverBuiltinTest_DataUnpacking,
- testing::Values(BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4x8snorm},
- BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4x8unorm},
- BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2x16snorm},
- BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2x16unorm},
- BuiltinData{"unpack2x16float", BuiltinType::kUnpack2x16float}));
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, TwoParams_Vector_f16) {
+ auto param = GetParam();
+
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
+ WrapInFunction(call);
+
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
-using ResolverBuiltinTest_SingleParam = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_SingleParam, Scalar) {
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F16>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<f16>, vec3<f16>)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Scalar_f16) {
auto param = GetParam();
- auto* call = Call(param.name, 1_f);
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call(param.name, 1_h, 1_h, 1_h);
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(f16, f16, f16)"));
+ }
}
-TEST_P(ResolverBuiltinTest_SingleParam, Vector) {
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Vector_f16) {
auto param = GetParam();
- auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f));
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h),
+ vec3<f16>(1_h, 1_h, 3_h));
+ WrapInFunction(call);
+
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F16>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<f16>, vec3<f16>, vec3<f16>)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, FourParams_Scalar_f16) {
+ auto param = GetParam();
+
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call(param.name, 1_h, 1_h, 1_h, 1_h);
+ WrapInFunction(call);
+
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(f16, f16, f16, f16)"));
+ }
+}
+
+TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, FourParams_Vector_f16) {
+ auto param = GetParam();
+
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h),
+ vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
+ WrapInFunction(call);
+
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F16>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<f16>, vec3<f16>, vec3<f16>, vec3<f16>)"));
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ResolverTest,
+ ResolverBuiltinTest_FloatBuiltin_IdenticalType,
+ testing::Values(BuiltinDataWithParamNum{1, "abs", BuiltinType::kAbs},
+ BuiltinDataWithParamNum{1, "acos", BuiltinType::kAcos},
+ BuiltinDataWithParamNum{1, "acosh", BuiltinType::kAcos},
+ BuiltinDataWithParamNum{1, "asin", BuiltinType::kAsin},
+ BuiltinDataWithParamNum{1, "asinh", BuiltinType::kAsin},
+ BuiltinDataWithParamNum{1, "atan", BuiltinType::kAtan},
+ BuiltinDataWithParamNum{1, "atanh", BuiltinType::kAtan},
+ BuiltinDataWithParamNum{2, "atan2", BuiltinType::kAtan2},
+ BuiltinDataWithParamNum{1, "ceil", BuiltinType::kCeil},
+ BuiltinDataWithParamNum{3, "clamp", BuiltinType::kClamp},
+ BuiltinDataWithParamNum{1, "cos", BuiltinType::kCos},
+ BuiltinDataWithParamNum{1, "cosh", BuiltinType::kCosh},
+ // cross: (vec3<T>, vec3<T>) -> vec3<T>
+ BuiltinDataWithParamNum{1, "degrees", BuiltinType::kDegrees},
+ // distance: (T, T) -> T, (vecN<T>, vecN<T>) -> T
+ BuiltinDataWithParamNum{1, "exp", BuiltinType::kExp},
+ BuiltinDataWithParamNum{1, "exp2", BuiltinType::kExp2},
+ // faceForward: (vecN<T>, vecN<T>, vecN<T>) -> vecN<T>
+ BuiltinDataWithParamNum{1, "floor", BuiltinType::kFloor},
+ BuiltinDataWithParamNum{3, "fma", BuiltinType::kFma},
+ BuiltinDataWithParamNum{1, "fract", BuiltinType::kFract},
+ // frexp
+ BuiltinDataWithParamNum{1, "inverseSqrt", BuiltinType::kInverseSqrt},
+ // ldexp: (T, i32) -> T, (vecN<T>, vecN<i32>) -> vecN<T>
+ // length: (vecN<T>) -> T
+ BuiltinDataWithParamNum{1, "log", BuiltinType::kLog},
+ BuiltinDataWithParamNum{1, "log2", BuiltinType::kLog2},
+ BuiltinDataWithParamNum{2, "max", BuiltinType::kMax},
+ BuiltinDataWithParamNum{2, "min", BuiltinType::kMin},
+ // Note that `mix(vecN<f32>, vecN<f32>, f32) -> vecN<f32>` is not tested here.
+ BuiltinDataWithParamNum{3, "mix", BuiltinType::kMix},
+ // modf
+ // normalize: (vecN<T>) -> vecN<T>
+ BuiltinDataWithParamNum{2, "pow", BuiltinType::kPow},
+ // quantizeToF16 is not implemented yet.
+ BuiltinDataWithParamNum{1, "radians", BuiltinType::kRadians},
+ // reflect: (vecN<T>, vecN<T>) -> vecN<T>
+ // refract: (vecN<T>, vecN<T>, T) -> vecN<T>
+ BuiltinDataWithParamNum{1, "round", BuiltinType::kRound},
+ // saturate not implemented yet.
+ BuiltinDataWithParamNum{1, "sign", BuiltinType::kSign},
+ BuiltinDataWithParamNum{1, "sin", BuiltinType::kSin},
+ BuiltinDataWithParamNum{1, "sinh", BuiltinType::kSinh},
+ BuiltinDataWithParamNum{3, "smoothstep", BuiltinType::kSmoothstep},
+ BuiltinDataWithParamNum{1, "sqrt", BuiltinType::kSqrt},
+ BuiltinDataWithParamNum{2, "step", BuiltinType::kStep},
+ BuiltinDataWithParamNum{1, "tan", BuiltinType::kTan},
+ BuiltinDataWithParamNum{1, "tanh", BuiltinType::kTanh},
+ BuiltinDataWithParamNum{1, "trunc", BuiltinType::kTrunc}));
+
+using ResolverBuiltinFloatTest = ResolverTest;
+
+// cross: (vec3<T>, vec3<T>) -> vec3<T>
+TEST_F(ResolverBuiltinFloatTest, Cross_f32) {
+ auto* call = Call("cross", vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -555,122 +725,185 @@ TEST_P(ResolverBuiltinTest_SingleParam, Vector) {
ASSERT_NE(TypeOf(call), nullptr);
EXPECT_TRUE(TypeOf(call)->is_float_vector());
EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
}
-TEST_P(ResolverBuiltinTest_SingleParam, Error_NoParams) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinFloatTest, Cross_f16) {
+ Enable(ast::Extension::kF16);
- auto* call = Call(param.name);
+ auto* call = Call("cross", vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(1_h, 2_h, 3_h));
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F16>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Cross_Error_NoArgs) {
+ auto* call = Call("cross");
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
- "()\n\n"
- "2 candidate functions:\n " +
- std::string(param.name) + "(f32) -> f32\n " +
- std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
+ EXPECT_EQ(r()->error(), R"(error: no matching call to cross()
+
+1 candidate function:
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+)");
}
-TEST_P(ResolverBuiltinTest_SingleParam, Error_TooManyParams) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinFloatTest, Cross_Error_Scalar) {
+ auto* call = Call("cross", 1_f, 1_f);
+ WrapInFunction(call);
- auto* call = Call(param.name, 1_i, 2_i, 3_i);
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), R"(error: no matching call to cross(f32, f32)
+
+1 candidate function:
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+)");
+}
+
+TEST_F(ResolverBuiltinFloatTest, Cross_Error_Vec3Int) {
+ auto* call = Call("cross", vec3<i32>(1_i, 2_i, 3_i), vec3<i32>(1_i, 2_i, 3_i));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
- "(i32, i32, i32)\n\n"
- "2 candidate functions:\n " +
- std::string(param.name) + "(f32) -> f32\n " +
- std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching call to cross(vec3<i32>, vec3<i32>)
+
+1 candidate function:
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+)");
}
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_SingleParam,
- testing::Values(BuiltinData{"acos", BuiltinType::kAcos},
- BuiltinData{"asin", BuiltinType::kAsin},
- BuiltinData{"atan", BuiltinType::kAtan},
- BuiltinData{"ceil", BuiltinType::kCeil},
- BuiltinData{"cos", BuiltinType::kCos},
- BuiltinData{"cosh", BuiltinType::kCosh},
- BuiltinData{"exp", BuiltinType::kExp},
- BuiltinData{"exp2", BuiltinType::kExp2},
- BuiltinData{"floor", BuiltinType::kFloor},
- BuiltinData{"fract", BuiltinType::kFract},
- BuiltinData{"inverseSqrt", BuiltinType::kInverseSqrt},
- BuiltinData{"log", BuiltinType::kLog},
- BuiltinData{"log2", BuiltinType::kLog2},
- BuiltinData{"round", BuiltinType::kRound},
- BuiltinData{"sign", BuiltinType::kSign},
- BuiltinData{"sin", BuiltinType::kSin},
- BuiltinData{"sinh", BuiltinType::kSinh},
- BuiltinData{"sqrt", BuiltinType::kSqrt},
- BuiltinData{"tan", BuiltinType::kTan},
- BuiltinData{"tanh", BuiltinType::kTanh},
- BuiltinData{"trunc", BuiltinType::kTrunc}));
-
-using ResolverBuiltinDataTest = ResolverTest;
-
-TEST_F(ResolverBuiltinDataTest, ArrayLength_Vector) {
- auto* ary = ty.array<i32>();
- auto* str = Structure("S", {Member("x", ary)});
- Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+TEST_F(ResolverBuiltinFloatTest, Cross_Error_Vec4) {
+ auto* call = Call("cross", vec4<f32>(1_f, 2_f, 3_f, 4_f), vec4<f32>(1_f, 2_f, 3_f, 4_f));
- auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_FALSE(r()->Resolve());
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching call to cross(vec4<f32>, vec4<f32>)
+
+1 candidate function:
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+)");
}
-TEST_F(ResolverBuiltinDataTest, ArrayLength_Error_ArraySized) {
- Global("arr", ty.array<i32, 4>(), ast::StorageClass::kPrivate);
- auto* call = Call("arrayLength", AddressOf("arr"));
+TEST_F(ResolverBuiltinFloatTest, Cross_Error_TooManyParams) {
+ auto* call =
+ Call("cross", vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f));
+
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to arrayLength(ptr<private, array<i32, 4>, read_write>)
+ R"(error: no matching call to cross(vec3<f32>, vec3<f32>, vec3<f32>)
1 candidate function:
- arrayLength(ptr<storage, array<T>, A>) -> u32
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, Normalize_Vector) {
- auto* call = Call("normalize", vec3<f32>(1_f, 1_f, 3_f));
+// distance: (T, T) -> T, (vecN<T>, vecN<T>) -> T
+TEST_F(ResolverBuiltinFloatTest, Distance_Scalar_f32) {
+ auto* call = Call("distance", 1_f, 1_f);
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
}
-TEST_F(ResolverBuiltinDataTest, Normalize_Error_NoParams) {
- auto* call = Call("normalize");
+TEST_F(ResolverBuiltinFloatTest, Distance_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("distance", 1_h, 1_h);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Distance_Vector_f32) {
+ auto* call = Call("distance", vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Distance_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("distance", vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Distance_TooManyParams) {
+ auto* call = Call("distance", vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
+ vec3<f32>(1_f, 1_f, 3_f));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
+ EXPECT_EQ(r()->error(), R"(error: no matching call to distance(vec3<f32>, vec3<f32>, vec3<f32>)
-1 candidate function:
- normalize(vecN<f32>) -> vecN<f32>
+2 candidate functions:
+ distance(T, T) -> T where: T is f32 or f16
+ distance(vecN<T>, vecN<T>) -> T where: T is f32 or f16
+)");
+}
+
+TEST_F(ResolverBuiltinFloatTest, Distance_TooFewParams) {
+ auto* call = Call("distance", vec3<f32>(1_f, 1_f, 3_f));
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), R"(error: no matching call to distance(vec3<f32>)
+
+2 candidate functions:
+ distance(T, T) -> T where: T is f32 or f16
+ distance(vecN<T>, vecN<T>) -> T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, FrexpScalar) {
+TEST_F(ResolverBuiltinFloatTest, Distance_NoParams) {
+ auto* call = Call("distance");
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), R"(error: no matching call to distance()
+
+2 candidate functions:
+ distance(T, T) -> T where: T is f32 or f16
+ distance(vecN<T>, vecN<T>) -> T where: T is f32 or f16
+)");
+}
+
+// frexp: (f32) -> __frexp_result, (vecN<f32>) -> __frexp_result_vecN, (f16) -> __frexp_result_16,
+// (vecN<f16>) -> __frexp_result_vecN_f16
+TEST_F(ResolverBuiltinFloatTest, FrexpScalar_f32) {
auto* call = Call("frexp", 1_f);
WrapInFunction(call);
@@ -699,7 +932,38 @@ TEST_F(ResolverBuiltinDataTest, FrexpScalar) {
EXPECT_EQ(ty->SizeNoPadding(), 8u);
}
-TEST_F(ResolverBuiltinDataTest, FrexpVector) {
+TEST_F(ResolverBuiltinFloatTest, FrexpScalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", 1_h);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ auto* ty = TypeOf(call)->As<sem::Struct>();
+ ASSERT_NE(ty, nullptr);
+ ASSERT_EQ(ty->Members().size(), 2u);
+
+ auto* sig = ty->Members()[0];
+ EXPECT_TRUE(sig->Type()->Is<sem::F16>());
+ EXPECT_EQ(sig->Offset(), 0u);
+ EXPECT_EQ(sig->Size(), 2u);
+ EXPECT_EQ(sig->Align(), 2u);
+ EXPECT_EQ(sig->Name(), Sym("sig"));
+
+ auto* exp = ty->Members()[1];
+ EXPECT_TRUE(exp->Type()->Is<sem::I32>());
+ EXPECT_EQ(exp->Offset(), 4u);
+ EXPECT_EQ(exp->Size(), 4u);
+ EXPECT_EQ(exp->Align(), 4u);
+ EXPECT_EQ(exp->Name(), Sym("exp"));
+
+ EXPECT_EQ(ty->Size(), 8u);
+ EXPECT_EQ(ty->SizeNoPadding(), 8u);
+}
+
+TEST_F(ResolverBuiltinFloatTest, FrexpVector_f32) {
auto* call = Call("frexp", vec3<f32>());
WrapInFunction(call);
@@ -732,8 +996,43 @@ TEST_F(ResolverBuiltinDataTest, FrexpVector) {
EXPECT_EQ(ty->SizeNoPadding(), 28u);
}
-TEST_F(ResolverBuiltinDataTest, Frexp_Error_FirstParamInt) {
- Global("v", ty.i32(), ast::StorageClass::kWorkgroup);
+TEST_F(ResolverBuiltinFloatTest, FrexpVector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", vec3<f16>());
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ auto* ty = TypeOf(call)->As<sem::Struct>();
+ ASSERT_NE(ty, nullptr);
+ ASSERT_EQ(ty->Members().size(), 2u);
+
+ auto* sig = ty->Members()[0];
+ ASSERT_TRUE(sig->Type()->Is<sem::Vector>());
+ EXPECT_EQ(sig->Type()->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(sig->Type()->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(sig->Offset(), 0u);
+ EXPECT_EQ(sig->Size(), 6u);
+ EXPECT_EQ(sig->Align(), 8u);
+ EXPECT_EQ(sig->Name(), Sym("sig"));
+
+ auto* exp = ty->Members()[1];
+ ASSERT_TRUE(exp->Type()->Is<sem::Vector>());
+ EXPECT_EQ(exp->Type()->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(exp->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_EQ(exp->Offset(), 16u);
+ EXPECT_EQ(exp->Size(), 12u);
+ EXPECT_EQ(exp->Align(), 16u);
+ EXPECT_EQ(exp->Name(), Sym("exp"));
+
+ EXPECT_EQ(ty->Size(), 32u);
+ EXPECT_EQ(ty->SizeNoPadding(), 28u);
+}
+
+TEST_F(ResolverBuiltinFloatTest, Frexp_Error_FirstParamInt) {
+ GlobalVar("v", ty.i32(), ast::StorageClass::kWorkgroup);
auto* call = Call("frexp", 1_i, AddressOf("v"));
WrapInFunction(call);
@@ -743,13 +1042,13 @@ TEST_F(ResolverBuiltinDataTest, Frexp_Error_FirstParamInt) {
R"(error: no matching call to frexp(i32, ptr<workgroup, i32, read_write>)
2 candidate functions:
- frexp(f32) -> __frexp_result
- frexp(vecN<f32>) -> __frexp_result_vecN
+ frexp(T) -> __frexp_result_T where: T is f32 or f16
+ frexp(vecN<T>) -> __frexp_result_vecN_T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, Frexp_Error_SecondParamFloatPtr) {
- Global("v", ty.f32(), ast::StorageClass::kWorkgroup);
+TEST_F(ResolverBuiltinFloatTest, Frexp_Error_SecondParamFloatPtr) {
+ GlobalVar("v", ty.f32(), ast::StorageClass::kWorkgroup);
auto* call = Call("frexp", 1_f, AddressOf("v"));
WrapInFunction(call);
@@ -759,12 +1058,12 @@ TEST_F(ResolverBuiltinDataTest, Frexp_Error_SecondParamFloatPtr) {
R"(error: no matching call to frexp(f32, ptr<workgroup, f32, read_write>)
2 candidate functions:
- frexp(f32) -> __frexp_result
- frexp(vecN<f32>) -> __frexp_result_vecN
+ frexp(T) -> __frexp_result_T where: T is f32 or f16
+ frexp(vecN<T>) -> __frexp_result_vecN_T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, Frexp_Error_SecondParamNotAPointer) {
+TEST_F(ResolverBuiltinFloatTest, Frexp_Error_SecondParamNotAPointer) {
auto* call = Call("frexp", 1_f, 1_i);
WrapInFunction(call);
@@ -773,13 +1072,13 @@ TEST_F(ResolverBuiltinDataTest, Frexp_Error_SecondParamNotAPointer) {
EXPECT_EQ(r()->error(), R"(error: no matching call to frexp(f32, i32)
2 candidate functions:
- frexp(f32) -> __frexp_result
- frexp(vecN<f32>) -> __frexp_result_vecN
+ frexp(T) -> __frexp_result_T where: T is f32 or f16
+ frexp(vecN<T>) -> __frexp_result_vecN_T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, Frexp_Error_VectorSizesDontMatch) {
- Global("v", ty.vec4<i32>(), ast::StorageClass::kWorkgroup);
+TEST_F(ResolverBuiltinFloatTest, Frexp_Error_VectorSizesDontMatch) {
+ GlobalVar("v", ty.vec4<i32>(), ast::StorageClass::kWorkgroup);
auto* call = Call("frexp", vec2<f32>(1_f, 2_f), AddressOf("v"));
WrapInFunction(call);
@@ -789,12 +1088,117 @@ TEST_F(ResolverBuiltinDataTest, Frexp_Error_VectorSizesDontMatch) {
R"(error: no matching call to frexp(vec2<f32>, ptr<workgroup, vec4<i32>, read_write>)
2 candidate functions:
- frexp(vecN<f32>) -> __frexp_result_vecN
- frexp(f32) -> __frexp_result
+ frexp(T) -> __frexp_result_T where: T is f32 or f16
+ frexp(vecN<T>) -> __frexp_result_vecN_T where: T is f32 or f16
+)");
+}
+
+// length: (T) -> T, (vecN<T>) -> T
+TEST_F(ResolverBuiltinFloatTest, Length_Scalar_f32) {
+ auto* call = Call("length", 1_f);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Length_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("length", 1_h);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Length_FloatVector_f32) {
+ auto* call = Call("length", vec3<f32>(1_f, 1_f, 3_f));
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Length_FloatVector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("length", vec3<f16>(1_h, 1_h, 3_h));
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Length_NoParams) {
+ auto* call = Call("length");
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), R"(error: no matching call to length()
+
+2 candidate functions:
+ length(T) -> T where: T is f32 or f16
+ length(vecN<T>) -> T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, ModfScalar) {
+TEST_F(ResolverBuiltinFloatTest, Length_TooManyParams) {
+ auto* call = Call("length", 1_f, 2_f);
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), R"(error: no matching call to length(f32, f32)
+
+2 candidate functions:
+ length(T) -> T where: T is f32 or f16
+ length(vecN<T>) -> T where: T is f32 or f16
+)");
+}
+
+// mix(vecN<T>, vecN<T>, T) -> vecN<T>. Other overloads are tested in
+// ResolverBuiltinTest_FloatBuiltin_IdenticalType above.
+TEST_F(ResolverBuiltinFloatTest, Mix_VectorScalar_f32) {
+ auto* call = Call("mix", vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f), 4_f);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
+}
+
+TEST_F(ResolverBuiltinFloatTest, Mix_VectorScalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("mix", vec3<f16>(1_h, 1_h, 1_h), vec3<f16>(1_h, 1_h, 1_h), 4_h);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F16>());
+}
+
+// modf: (f32) -> __modf_result, (vecN<f32>) -> __modf_result_vecN, (f16) -> __modf_result_f16,
+// (vecN<f16>) -> __modf_result_vecN_f16
+TEST_F(ResolverBuiltinFloatTest, ModfScalar_f32) {
auto* call = Call("modf", 1_f);
WrapInFunction(call);
@@ -823,7 +1227,38 @@ TEST_F(ResolverBuiltinDataTest, ModfScalar) {
EXPECT_EQ(ty->SizeNoPadding(), 8u);
}
-TEST_F(ResolverBuiltinDataTest, ModfVector) {
+TEST_F(ResolverBuiltinFloatTest, ModfScalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", 1_h);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ auto* ty = TypeOf(call)->As<sem::Struct>();
+ ASSERT_NE(ty, nullptr);
+ ASSERT_EQ(ty->Members().size(), 2u);
+
+ auto* fract = ty->Members()[0];
+ EXPECT_TRUE(fract->Type()->Is<sem::F16>());
+ EXPECT_EQ(fract->Offset(), 0u);
+ EXPECT_EQ(fract->Size(), 2u);
+ EXPECT_EQ(fract->Align(), 2u);
+ EXPECT_EQ(fract->Name(), Sym("fract"));
+
+ auto* whole = ty->Members()[1];
+ EXPECT_TRUE(whole->Type()->Is<sem::F16>());
+ EXPECT_EQ(whole->Offset(), 2u);
+ EXPECT_EQ(whole->Size(), 2u);
+ EXPECT_EQ(whole->Align(), 2u);
+ EXPECT_EQ(whole->Name(), Sym("whole"));
+
+ EXPECT_EQ(ty->Size(), 4u);
+ EXPECT_EQ(ty->SizeNoPadding(), 4u);
+}
+
+TEST_F(ResolverBuiltinFloatTest, ModfVector_f32) {
auto* call = Call("modf", vec3<f32>());
WrapInFunction(call);
@@ -856,8 +1291,43 @@ TEST_F(ResolverBuiltinDataTest, ModfVector) {
EXPECT_EQ(ty->SizeNoPadding(), 28u);
}
-TEST_F(ResolverBuiltinDataTest, Modf_Error_FirstParamInt) {
- Global("whole", ty.f32(), ast::StorageClass::kWorkgroup);
+TEST_F(ResolverBuiltinFloatTest, ModfVector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", vec3<f16>());
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(call), nullptr);
+ auto* ty = TypeOf(call)->As<sem::Struct>();
+ ASSERT_NE(ty, nullptr);
+ ASSERT_EQ(ty->Members().size(), 2u);
+
+ auto* fract = ty->Members()[0];
+ ASSERT_TRUE(fract->Type()->Is<sem::Vector>());
+ EXPECT_EQ(fract->Type()->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(fract->Type()->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(fract->Offset(), 0u);
+ EXPECT_EQ(fract->Size(), 6u);
+ EXPECT_EQ(fract->Align(), 8u);
+ EXPECT_EQ(fract->Name(), Sym("fract"));
+
+ auto* whole = ty->Members()[1];
+ ASSERT_TRUE(whole->Type()->Is<sem::Vector>());
+ EXPECT_EQ(whole->Type()->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(whole->Type()->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(whole->Offset(), 8u);
+ EXPECT_EQ(whole->Size(), 6u);
+ EXPECT_EQ(whole->Align(), 8u);
+ EXPECT_EQ(whole->Name(), Sym("whole"));
+
+ EXPECT_EQ(ty->Size(), 16u);
+ EXPECT_EQ(ty->SizeNoPadding(), 14u);
+}
+
+TEST_F(ResolverBuiltinFloatTest, Modf_Error_FirstParamInt) {
+ GlobalVar("whole", ty.f32(), ast::StorageClass::kWorkgroup);
auto* call = Call("modf", 1_i, AddressOf("whole"));
WrapInFunction(call);
@@ -867,13 +1337,13 @@ TEST_F(ResolverBuiltinDataTest, Modf_Error_FirstParamInt) {
R"(error: no matching call to modf(i32, ptr<workgroup, f32, read_write>)
2 candidate functions:
- modf(f32) -> __modf_result
- modf(vecN<f32>) -> __modf_result_vecN
+ modf(T) -> __modf_result_T where: T is f32 or f16
+ modf(vecN<T>) -> __modf_result_vecN_T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, Modf_Error_SecondParamIntPtr) {
- Global("whole", ty.i32(), ast::StorageClass::kWorkgroup);
+TEST_F(ResolverBuiltinFloatTest, Modf_Error_SecondParamIntPtr) {
+ GlobalVar("whole", ty.i32(), ast::StorageClass::kWorkgroup);
auto* call = Call("modf", 1_f, AddressOf("whole"));
WrapInFunction(call);
@@ -883,12 +1353,12 @@ TEST_F(ResolverBuiltinDataTest, Modf_Error_SecondParamIntPtr) {
R"(error: no matching call to modf(f32, ptr<workgroup, i32, read_write>)
2 candidate functions:
- modf(f32) -> __modf_result
- modf(vecN<f32>) -> __modf_result_vecN
+ modf(T) -> __modf_result_T where: T is f32 or f16
+ modf(vecN<T>) -> __modf_result_vecN_T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, Modf_Error_SecondParamNotAPointer) {
+TEST_F(ResolverBuiltinFloatTest, Modf_Error_SecondParamNotAPointer) {
auto* call = Call("modf", 1_f, 1_f);
WrapInFunction(call);
@@ -897,13 +1367,13 @@ TEST_F(ResolverBuiltinDataTest, Modf_Error_SecondParamNotAPointer) {
EXPECT_EQ(r()->error(), R"(error: no matching call to modf(f32, f32)
2 candidate functions:
- modf(f32) -> __modf_result
- modf(vecN<f32>) -> __modf_result_vecN
+ modf(T) -> __modf_result_T where: T is f32 or f16
+ modf(vecN<T>) -> __modf_result_vecN_T where: T is f32 or f16
)");
}
-TEST_F(ResolverBuiltinDataTest, Modf_Error_VectorSizesDontMatch) {
- Global("whole", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
+TEST_F(ResolverBuiltinFloatTest, Modf_Error_VectorSizesDontMatch) {
+ GlobalVar("whole", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
auto* call = Call("modf", vec2<f32>(1_f, 2_f), AddressOf("whole"));
WrapInFunction(call);
@@ -913,28 +1383,28 @@ TEST_F(ResolverBuiltinDataTest, Modf_Error_VectorSizesDontMatch) {
R"(error: no matching call to modf(vec2<f32>, ptr<workgroup, vec4<f32>, read_write>)
2 candidate functions:
- modf(vecN<f32>) -> __modf_result_vecN
- modf(f32) -> __modf_result
+ modf(T) -> __modf_result_T where: T is f32 or f16
+ modf(vecN<T>) -> __modf_result_vecN_T where: T is f32 or f16
)");
}
-using ResolverBuiltinTest_SingleParam_FloatOrInt = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Float_Scalar) {
- auto param = GetParam();
-
- auto* call = Call(param.name, 1_f);
+// normalize: (vecN<T>) -> vecN<T>
+TEST_F(ResolverBuiltinFloatTest, Normalize_Vector_f32) {
+ auto* call = Call("normalize", vec3<f32>(1_f, 1_f, 3_f));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
}
-TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Float_Vector) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinFloatTest, Normalize_Vector_f16) {
+ Enable(ast::Extension::kF16);
- auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f));
+ auto* call = Call("normalize", vec3<f16>(1_h, 1_h, 3_h));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -942,649 +1412,813 @@ TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Float_Vector) {
ASSERT_NE(TypeOf(call), nullptr);
EXPECT_TRUE(TypeOf(call)->is_float_vector());
EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F16>());
}
-TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Sint_Scalar) {
- auto param = GetParam();
-
- auto* call = Call(param.name, -1_i);
+TEST_F(ResolverBuiltinFloatTest, Normalize_Error_NoParams) {
+ auto* call = Call("normalize");
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_FALSE(r()->Resolve());
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+ EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
+
+1 candidate function:
+ normalize(vecN<T>) -> vecN<T> where: T is f32 or f16
+)");
}
-TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Sint_Vector) {
- auto param = GetParam();
+} // namespace float_builtin_tests
- auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i));
- WrapInFunction(call);
+// Tests for Numeric builtins with all integer parameter
+namespace integer_builtin_tests {
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+// Testcase parameters for integer built-in having signature of (T, ...) -> T and (vecN<T>, ...) ->
+// vecN<T>, where T is i32 and u32
+struct BuiltinDataWithParamNum {
+ uint32_t args_number;
+ const char* name;
+ BuiltinType builtin;
+};
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
+ out << data.name;
+ return out;
}
-TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Uint_Scalar) {
+// Tests for integer built-ins that has signiture (T, ...) -> T and (vecN<T>, ...) -> vecN<T>
+using ResolverBuiltinTest_IntegerBuiltin_IdenticalType =
+ ResolverTestWithParam<BuiltinDataWithParamNum>;
+
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, Error_NoParams) {
auto param = GetParam();
- auto* call = Call(param.name, 1_u);
+ auto* call = Call(param.name);
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_FALSE(r()->Resolve());
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) + "()"));
}
-TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Uint_Vector) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, OneParams_Scalar_i32) {
auto param = GetParam();
- auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u));
+ auto* call = Call(param.name, 1_i);
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) + "(i32)"));
+ }
}
-TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Error_NoParams) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, OneParams_Vector_i32) {
auto param = GetParam();
- auto* call = Call(param.name);
+ auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i));
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(),
- "error: no matching call to " + std::string(param.name) +
- "()\n\n"
- "2 candidate functions:\n " +
- std::string(param.name) + "(T) -> T where: T is f32, i32 or u32\n " +
- std::string(param.name) + "(vecN<T>) -> vecN<T> where: T is f32, i32 or u32\n");
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<i32>)"));
+ }
}
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_SingleParam_FloatOrInt,
- testing::Values(BuiltinData{"abs", BuiltinType::kAbs}));
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, OneParams_Scalar_u32) {
+ auto param = GetParam();
-TEST_F(ResolverBuiltinTest, Length_Scalar) {
- auto* call = Call("length", 1_f);
+ auto* call = Call(param.name, 1_u);
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
-}
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
-TEST_F(ResolverBuiltinTest, Length_FloatVector) {
- auto* call = Call("length", vec3<f32>(1_f, 1_f, 3_f));
- WrapInFunction(call);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) + "(u32)"));
+ }
}
-using ResolverBuiltinTest_TwoParam = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_TwoParam, Scalar) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, OneParams_Vector_u32) {
auto param = GetParam();
- auto* call = Call(param.name, 1_f, 1_f);
+ auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u));
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ if (param.args_number == 1u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<u32>)"));
+ }
}
-TEST_P(ResolverBuiltinTest_TwoParam, Vector) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, TwoParams_Scalar_i32) {
auto param = GetParam();
- auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
+ auto* call = Call(param.name, 1_i, 1_i);
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(i32, i32)"));
+ }
}
-TEST_P(ResolverBuiltinTest_TwoParam, Error_NoTooManyParams) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, TwoParams_Vector_i32) {
auto param = GetParam();
- auto* call = Call(param.name, 1_i, 2_i, 3_i);
+ auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i));
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
- "(i32, i32, i32)\n\n"
- "2 candidate functions:\n " +
- std::string(param.name) + "(f32, f32) -> f32\n " +
- std::string(param.name) + "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<i32>, vec3<i32>)"));
+ }
}
-TEST_P(ResolverBuiltinTest_TwoParam, Error_NoParams) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, TwoParams_Scalar_u32) {
auto param = GetParam();
- auto* call = Call(param.name);
+ auto* call = Call(param.name, 1_u, 1_u);
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
- "()\n\n"
- "2 candidate functions:\n " +
- std::string(param.name) + "(f32, f32) -> f32\n " +
- std::string(param.name) + "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(u32, u32)"));
+ }
}
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_TwoParam,
- testing::Values(BuiltinData{"atan2", BuiltinType::kAtan2},
- BuiltinData{"pow", BuiltinType::kPow},
- BuiltinData{"step", BuiltinType::kStep}));
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, TwoParams_Vector_u32) {
+ auto param = GetParam();
-TEST_F(ResolverBuiltinTest, Distance_Scalar) {
- auto* call = Call("distance", 1_f, 1_f);
+ auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u));
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
-}
-
-TEST_F(ResolverBuiltinTest, Distance_Vector) {
- auto* call = Call("distance", vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
- WrapInFunction(call);
+ if (param.args_number == 2u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(vec3<u32>, vec3<u32>)"));
+ }
}
-TEST_F(ResolverBuiltinTest, Cross) {
- auto* call = Call("cross", vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f));
- WrapInFunction(call);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
-}
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, ThreeParams_Scalar_i32) {
+ auto param = GetParam();
-TEST_F(ResolverBuiltinTest, Cross_Error_NoArgs) {
- auto* call = Call("cross");
+ auto* call = Call(param.name, 1_i, 1_i, 1_i);
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), R"(error: no matching call to cross()
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
-1 candidate function:
- cross(vec3<f32>, vec3<f32>) -> vec3<f32>
-)");
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(i32, i32, i32)"));
+ }
}
-TEST_F(ResolverBuiltinTest, Cross_Error_Scalar) {
- auto* call = Call("cross", 1_f, 1_f);
- WrapInFunction(call);
-
- EXPECT_FALSE(r()->Resolve());
-
- EXPECT_EQ(r()->error(), R"(error: no matching call to cross(f32, f32)
-
-1 candidate function:
- cross(vec3<f32>, vec3<f32>) -> vec3<f32>
-)");
-}
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, ThreeParams_Vector_i32) {
+ auto param = GetParam();
-TEST_F(ResolverBuiltinTest, Cross_Error_Vec3Int) {
- auto* call = Call("cross", vec3<i32>(1_i, 2_i, 3_i), vec3<i32>(1_i, 2_i, 3_i));
+ auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i),
+ vec3<i32>(1_i, 1_i, 3_i));
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(),
- R"(error: no matching call to cross(vec3<i32>, vec3<i32>)
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
-1 candidate function:
- cross(vec3<f32>, vec3<f32>) -> vec3<f32>
-)");
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<i32>, vec3<i32>, vec3<i32>)"));
+ }
}
-TEST_F(ResolverBuiltinTest, Cross_Error_Vec4) {
- auto* call = Call("cross", vec4<f32>(1_f, 2_f, 3_f, 4_f), vec4<f32>(1_f, 2_f, 3_f, 4_f));
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, ThreeParams_Scalar_u32) {
+ auto param = GetParam();
+ auto* call = Call(param.name, 1_u, 1_u, 1_u);
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(),
- R"(error: no matching call to cross(vec4<f32>, vec4<f32>)
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
-1 candidate function:
- cross(vec3<f32>, vec3<f32>) -> vec3<f32>
-)");
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(u32, u32, u32)"));
+ }
}
-TEST_F(ResolverBuiltinTest, Cross_Error_TooManyParams) {
- auto* call =
- Call("cross", vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f));
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, ThreeParams_Vector_u32) {
+ auto param = GetParam();
+ auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u),
+ vec3<u32>(1_u, 1_u, 3_u));
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 3u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(),
- R"(error: no matching call to cross(vec3<f32>, vec3<f32>, vec3<f32>)
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
-1 candidate function:
- cross(vec3<f32>, vec3<f32>) -> vec3<f32>
-)");
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<u32>, vec3<u32>, vec3<u32>)"));
+ }
}
-TEST_F(ResolverBuiltinTest, Normalize) {
- auto* call = Call("normalize", vec3<f32>(1_f, 1_f, 3_f));
- WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
-}
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, FourParams_Scalar_i32) {
+ auto param = GetParam();
-TEST_F(ResolverBuiltinTest, Normalize_NoArgs) {
- auto* call = Call("normalize");
+ auto* call = Call(param.name, 1_i, 1_i, 1_i, 1_i);
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
-1 candidate function:
- normalize(vecN<f32>) -> vecN<f32>
-)");
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(i32, i32, i32, i32)"));
+ }
}
-using ResolverBuiltinTest_ThreeParam = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_ThreeParam, Scalar) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, FourParams_Vector_i32) {
auto param = GetParam();
- auto* call = Call(param.name, 1_f, 1_f, 1_f);
+ auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i),
+ vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i));
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::I32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<i32>, vec3<i32>, vec3<i32>, vec3<i32>)"));
+ }
}
-TEST_P(ResolverBuiltinTest_ThreeParam, Vector) {
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, FourParams_Scalar_u32) {
auto param = GetParam();
- auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
- vec3<f32>(1_f, 1_f, 3_f));
+ auto* call = Call(param.name, 1_u, 1_u, 1_u, 1_u);
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
+ std::string(param.name) + "(u32, u32, u32, u32)"));
+ }
}
-TEST_P(ResolverBuiltinTest_ThreeParam, Error_NoParams) {
+
+TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, FourParams_Vector_u32) {
auto param = GetParam();
- auto* call = Call(param.name);
+ auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u),
+ vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u));
WrapInFunction(call);
- EXPECT_FALSE(r()->Resolve());
+ if (param.args_number == 4u) {
+ // Parameter count matched.
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) + "()"));
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(call)->As<sem::Vector>()->type(), nullptr);
+ EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::U32>());
+ } else {
+ // Invalid parameter count.
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(),
+ HasSubstr("error: no matching call to " + std::string(param.name) +
+ "(vec3<u32>, vec3<u32>, vec3<u32>, vec3<u32>)"));
+ }
}
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_ThreeParam,
- testing::Values(BuiltinData{"mix", BuiltinType::kMix},
- BuiltinData{"smoothstep", BuiltinType::kSmoothstep},
- BuiltinData{"smoothStep", BuiltinType::kSmoothStep},
- BuiltinData{"fma", BuiltinType::kFma}));
-
-using ResolverBuiltinTest_ThreeParam_FloatOrInt = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Float_Scalar) {
- auto param = GetParam();
+INSTANTIATE_TEST_SUITE_P(
+ ResolverTest,
+ ResolverBuiltinTest_IntegerBuiltin_IdenticalType,
+ testing::Values(
+ BuiltinDataWithParamNum{1, "abs", BuiltinType::kAbs},
+ BuiltinDataWithParamNum{3, "clamp", BuiltinType::kClamp},
+ BuiltinDataWithParamNum{1, "countLeadingZeros", BuiltinType::kCountLeadingZeros},
+ BuiltinDataWithParamNum{1, "countOneBits", BuiltinType::kCountOneBits},
+ BuiltinDataWithParamNum{1, "countTrailingZeros", BuiltinType::kCountTrailingZeros},
+ // extractBits: (T, u32, u32) -> T
+ BuiltinDataWithParamNum{1, "firstLeadingBit", BuiltinType::kFirstLeadingBit},
+ BuiltinDataWithParamNum{1, "firstTrailingBit", BuiltinType::kFirstTrailingBit},
+ // insertBits: (T, T, u32, u32) -> T
+ BuiltinDataWithParamNum{2, "max", BuiltinType::kMax},
+ BuiltinDataWithParamNum{2, "min", BuiltinType::kMin},
+ BuiltinDataWithParamNum{1, "reverseBits", BuiltinType::kReverseBits}));
+
+} // namespace integer_builtin_tests
+
+// Tests for Numeric builtins with matrix parameter, i.e. "determinant" and "transpose"
+namespace matrix_builtin_tests {
+
+TEST_F(ResolverBuiltinTest, Determinant_2x2_f32) {
+ GlobalVar("var", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, 1_f, 1_f, 1_f);
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
}
-TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Float_Vector) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Determinant_2x2_f16) {
+ Enable(ast::Extension::kF16);
- auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
- vec3<f32>(1_f, 1_f, 3_f));
+ GlobalVar("var", ty.mat2x2<f16>(), ast::StorageClass::kPrivate);
+
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
}
-TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Sint_Scalar) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Determinant_3x3_f32) {
+ GlobalVar("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, 1_i, 1_i, 1_i);
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
}
-TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Sint_Vector) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Determinant_3x3_f16) {
+ Enable(ast::Extension::kF16);
- auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i),
- vec3<i32>(1_i, 1_i, 3_i));
+ GlobalVar("var", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
}
-TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Uint_Scalar) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Determinant_4x4_f32) {
+ GlobalVar("var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, 1_u, 1_u, 1_u);
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
}
-TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Uint_Vector) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Determinant_4x4_f16) {
+ Enable(ast::Extension::kF16);
- auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u),
- vec3<u32>(1_u, 1_u, 3_u));
+ GlobalVar("var", ty.mat4x4<f16>(), ast::StorageClass::kPrivate);
+
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::F16>());
}
-TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Error_NoParams) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Determinant_NotSquare) {
+ GlobalVar("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name);
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
- "()\n\n"
- "2 candidate functions:\n " +
- std::string(param.name) +
- "(T, T, T) -> T where: T is f32, i32 or u32\n " +
- std::string(param.name) +
- "(vecN<T>, vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32 "
- "or u32\n");
-}
+ EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(mat2x3<f32>)
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_ThreeParam_FloatOrInt,
- testing::Values(BuiltinData{"clamp", BuiltinType::kClamp}));
+1 candidate function:
+ determinant(matNxN<T>) -> T where: T is f32 or f16
+)");
+}
-using ResolverBuiltinTest_Int_SingleParam = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_Int_SingleParam, Scalar) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Determinant_NotMatrix) {
+ GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, 1_i);
+ auto* call = Call("determinant", "var");
WrapInFunction(call);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_FALSE(r()->Resolve());
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_integer_scalar());
+ EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(f32)
+
+1 candidate function:
+ determinant(matNxN<T>) -> T where: T is f32 or f16
+)");
}
-TEST_P(ResolverBuiltinTest_Int_SingleParam, Vector) {
- auto param = GetParam();
+} // namespace matrix_builtin_tests
- auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i));
- WrapInFunction(call);
+// Tests for Numeric builtins with float and integer vector parameter, i.e. "dot"
+namespace vector_builtin_tests {
+
+TEST_F(ResolverBuiltinTest, Dot_Vec2_f32) {
+ GlobalVar("my_var", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+
+ auto* expr = Call("dot", "my_var", "my_var");
+ WrapInFunction(expr);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(expr), nullptr);
+ EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
}
-TEST_P(ResolverBuiltinTest_Int_SingleParam, Error_NoParams) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Dot_Vec2_f16) {
+ Enable(ast::Extension::kF16);
- auto* call = Call(param.name);
- WrapInFunction(call);
+ GlobalVar("my_var", ty.vec2<f16>(), ast::StorageClass::kPrivate);
- EXPECT_FALSE(r()->Resolve());
+ auto* expr = Call("dot", "my_var", "my_var");
+ WrapInFunction(expr);
- EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
- "()\n\n"
- "2 candidate functions:\n " +
- std::string(param.name) + "(T) -> T where: T is i32 or u32\n " +
- std::string(param.name) +
- "(vecN<T>) -> vecN<T> where: T is i32 or u32\n");
-}
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_Int_SingleParam,
- testing::Values(BuiltinData{"countOneBits", BuiltinType::kCountOneBits},
- BuiltinData{"reverseBits", BuiltinType::kReverseBits}));
+ ASSERT_NE(TypeOf(expr), nullptr);
+ EXPECT_TRUE(TypeOf(expr)->Is<sem::F16>());
+}
-using ResolverBuiltinTest_FloatOrInt_TwoParam = ResolverTestWithParam<BuiltinData>;
-TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Scalar_Signed) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Dot_Vec3_i32) {
+ GlobalVar("my_var", ty.vec3<i32>(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, 1_i, 1_i);
- WrapInFunction(call);
+ auto* expr = Call("dot", "my_var", "my_var");
+ WrapInFunction(expr);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+ ASSERT_NE(TypeOf(expr), nullptr);
+ EXPECT_TRUE(TypeOf(expr)->Is<sem::I32>());
}
-TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Scalar_Unsigned) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Dot_Vec4_u32) {
+ GlobalVar("my_var", ty.vec4<u32>(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, 1_u, 1_u);
- WrapInFunction(call);
+ auto* expr = Call("dot", "my_var", "my_var");
+ WrapInFunction(expr);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+ ASSERT_NE(TypeOf(expr), nullptr);
+ EXPECT_TRUE(TypeOf(expr)->Is<sem::U32>());
}
-TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Scalar_Float) {
- auto param = GetParam();
+TEST_F(ResolverBuiltinTest, Dot_Error_Scalar) {
+ auto* expr = Call("dot", 1_f, 1_f);
+ WrapInFunction(expr);
- auto* call = Call(param.name, 1_f, 1_f);
- WrapInFunction(call);
+ EXPECT_FALSE(r()->Resolve());
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching call to dot(f32, f32)
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+1 candidate function:
+ dot(vecN<T>, vecN<T>) -> T where: T is f32, i32, u32 or f16
+)");
}
-TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Vector_Signed) {
- auto param = GetParam();
+} // namespace vector_builtin_tests
- auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i));
- WrapInFunction(call);
+// Tests for Derivative builtins
+namespace derivative_builtin_tests {
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+using ResolverBuiltinDerivativeTest = ResolverTestWithParam<std::string>;
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
-}
+TEST_P(ResolverBuiltinDerivativeTest, Scalar) {
+ auto name = GetParam();
-TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Vector_Unsigned) {
- auto param = GetParam();
+ GlobalVar("ident", ty.f32(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u));
- WrapInFunction(call);
+ auto* expr = Call(name, "ident");
+ Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
+ utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(expr), nullptr);
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
}
-TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Vector_Float) {
- auto param = GetParam();
+TEST_P(ResolverBuiltinDerivativeTest, Vector) {
+ auto name = GetParam();
+ GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
- auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
- WrapInFunction(call);
+ auto* expr = Call(name, "ident");
+ Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
+ utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->is_float_vector());
- EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+ ASSERT_NE(TypeOf(expr), nullptr);
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
}
-TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Error_NoParams) {
- auto param = GetParam();
+TEST_P(ResolverBuiltinDerivativeTest, MissingParam) {
+ auto name = GetParam();
- auto* call = Call(param.name);
- WrapInFunction(call);
+ auto* expr = Call(name);
+ WrapInFunction(expr);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
+ EXPECT_EQ(r()->error(), "error: no matching call to " + name +
"()\n\n"
"2 candidate functions:\n " +
- std::string(param.name) +
- "(T, T) -> T where: T is f32, i32 or u32\n " +
- std::string(param.name) +
- "(vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32 or u32\n");
+ name + "(f32) -> f32\n " + name + "(vecN<f32>) -> vecN<f32>\n");
}
INSTANTIATE_TEST_SUITE_P(ResolverTest,
- ResolverBuiltinTest_FloatOrInt_TwoParam,
- testing::Values(BuiltinData{"min", BuiltinType::kMin},
- BuiltinData{"max", BuiltinType::kMax}));
-
-TEST_F(ResolverBuiltinTest, Determinant_2x2) {
- Global("var", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+ ResolverBuiltinDerivativeTest,
+ testing::Values("dpdx",
+ "dpdxCoarse",
+ "dpdxFine",
+ "dpdy",
+ "dpdyCoarse",
+ "dpdyFine",
+ "fwidth",
+ "fwidthCoarse",
+ "fwidthFine"));
- auto* call = Call("determinant", "var");
- WrapInFunction(call);
+} // namespace derivative_builtin_tests
- EXPECT_TRUE(r()->Resolve()) << r()->error();
+// Tests for Texture builtins
+namespace texture_builtin_tests {
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+enum class Texture { kF32, kI32, kU32 };
+inline std::ostream& operator<<(std::ostream& out, Texture data) {
+ if (data == Texture::kF32) {
+ out << "f32";
+ } else if (data == Texture::kI32) {
+ out << "i32";
+ } else {
+ out << "u32";
+ }
+ return out;
}
-TEST_F(ResolverBuiltinTest, Determinant_3x3) {
- Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-
- auto* call = Call("determinant", "var");
- WrapInFunction(call);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+struct TextureTestParams {
+ ast::TextureDimension dim;
+ Texture type = Texture::kF32;
+ ast::TexelFormat format = ast::TexelFormat::kR32Float;
+};
+inline std::ostream& operator<<(std::ostream& out, TextureTestParams data) {
+ out << data.dim << "_" << data.type;
+ return out;
}
-TEST_F(ResolverBuiltinTest, Determinant_4x4) {
- Global("var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
-
- auto* call = Call("determinant", "var");
- WrapInFunction(call);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_NE(TypeOf(call), nullptr);
- EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
-}
+class ResolverBuiltinTest_TextureOperation : public ResolverTestWithParam<TextureTestParams> {
+ public:
+ /// Gets an appropriate type for the coords parameter depending the the
+ /// dimensionality of the texture being sampled.
+ /// @param dim dimensionality of the texture being sampled
+ /// @param scalar the scalar type
+ /// @returns a pointer to a type appropriate for the coord param
+ const ast::Type* GetCoordsType(ast::TextureDimension dim, const ast::Type* scalar) {
+ switch (dim) {
+ case ast::TextureDimension::k1d:
+ return scalar;
+ case ast::TextureDimension::k2d:
+ case ast::TextureDimension::k2dArray:
+ return ty.vec(scalar, 2);
+ case ast::TextureDimension::k3d:
+ case ast::TextureDimension::kCube:
+ case ast::TextureDimension::kCubeArray:
+ return ty.vec(scalar, 3);
+ default:
+ [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
+ }
+ return nullptr;
+ }
-TEST_F(ResolverBuiltinTest, Determinant_NotSquare) {
- Global("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+ void add_call_param(std::string name, const ast::Type* type, ExpressionList* call_params) {
+ if (type->IsAnyOf<ast::Texture, ast::Sampler>()) {
+ GlobalVar(name, type,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
- auto* call = Call("determinant", "var");
- WrapInFunction(call);
+ } else {
+ GlobalVar(name, type, ast::StorageClass::kPrivate);
+ }
- EXPECT_FALSE(r()->Resolve());
+ call_params->Push(Expr(name));
+ }
+ const ast::Type* subtype(Texture type) {
+ if (type == Texture::kF32) {
+ return ty.f32();
+ }
+ if (type == Texture::kI32) {
+ return ty.i32();
+ }
+ return ty.u32();
+ }
+};
- EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(mat2x3<f32>)
+using ResolverBuiltinTest_SampledTextureOperation = ResolverBuiltinTest_TextureOperation;
+TEST_P(ResolverBuiltinTest_SampledTextureOperation, TextureLoadSampled) {
+ auto dim = GetParam().dim;
+ auto type = GetParam().type;
-1 candidate function:
- determinant(matNxN<f32>) -> f32
-)");
-}
+ auto* s = subtype(type);
+ auto* coords_type = GetCoordsType(dim, ty.i32());
+ auto* texture_type = ty.sampled_texture(dim, s);
-TEST_F(ResolverBuiltinTest, Determinant_NotMatrix) {
- Global("var", ty.f32(), ast::StorageClass::kPrivate);
+ ExpressionList call_params;
- auto* call = Call("determinant", "var");
- WrapInFunction(call);
+ add_call_param("texture", texture_type, &call_params);
+ add_call_param("coords", coords_type, &call_params);
+ if (dim == ast::TextureDimension::k2dArray) {
+ add_call_param("array_index", ty.i32(), &call_params);
+ }
+ add_call_param("level", ty.i32(), &call_params);
- EXPECT_FALSE(r()->Resolve());
+ auto* expr = Call("textureLoad", call_params);
+ WrapInFunction(expr);
- EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(f32)
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
-1 candidate function:
- determinant(matNxN<f32>) -> f32
-)");
+ ASSERT_NE(TypeOf(expr), nullptr);
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
+ if (type == Texture::kF32) {
+ EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
+ } else if (type == Texture::kI32) {
+ EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::I32>());
+ } else {
+ EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::U32>());
+ }
+ EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
}
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+ ResolverBuiltinTest_SampledTextureOperation,
+ testing::Values(TextureTestParams{ast::TextureDimension::k1d},
+ TextureTestParams{ast::TextureDimension::k2d},
+ TextureTestParams{ast::TextureDimension::k2dArray},
+ TextureTestParams{ast::TextureDimension::k3d}));
+
using ResolverBuiltinTest_Texture = ResolverTestWithParam<ast::builtin::test::TextureOverloadCase>;
INSTANTIATE_TEST_SUITE_P(ResolverTest,
ResolverBuiltinTest_Texture,
testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
-std::string to_str(const std::string& function, const sem::ParameterList& params) {
+static std::string to_str(const std::string& function,
+ utils::VectorRef<const sem::Parameter*> params) {
std::stringstream out;
out << function << "(";
bool first = true;
@@ -1599,7 +2233,7 @@ std::string to_str(const std::string& function, const sem::ParameterList& params
return out.str();
}
-const char* expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
+static const char* expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
switch (overload) {
case ValidTextureOverload::kDimensions1d:
@@ -1839,7 +2473,8 @@ TEST_P(ResolverBuiltinTest_Texture, Call) {
auto* call = Call(param.function, param.args(this));
auto* stmt = CallStmt(call);
- Func("func", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{stmt},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1929,10 +2564,151 @@ TEST_P(ResolverBuiltinTest_Texture, Call) {
auto* target = call_sem->Target();
ASSERT_NE(target, nullptr);
- auto got = resolver::to_str(param.function, target->Parameters());
+ auto got = texture_builtin_tests::to_str(param.function, target->Parameters());
auto* expected = expected_texture_overload(param.overload);
EXPECT_EQ(got, expected);
}
+} // namespace texture_builtin_tests
+
+// Tests for Data Packing builtins
+namespace data_packing_builtin_tests {
+
+using ResolverBuiltinTest_DataPacking = ResolverTestWithParam<BuiltinData>;
+TEST_P(ResolverBuiltinTest_DataPacking, InferType) {
+ auto param = GetParam();
+
+ bool pack4 =
+ param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
+
+ auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f))
+ : Call(param.name, vec2<f32>(1_f, 2_f));
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+}
+
+TEST_P(ResolverBuiltinTest_DataPacking, Error_IncorrectParamType) {
+ auto param = GetParam();
+
+ bool pack4 =
+ param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
+
+ auto* call = pack4 ? Call(param.name, vec4<i32>(1_i, 2_i, 3_i, 4_i))
+ : Call(param.name, vec2<i32>(1_i, 2_i));
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+}
+
+TEST_P(ResolverBuiltinTest_DataPacking, Error_NoParams) {
+ auto param = GetParam();
+
+ auto* call = Call(param.name);
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+}
+
+TEST_P(ResolverBuiltinTest_DataPacking, Error_TooManyParams) {
+ auto param = GetParam();
+
+ bool pack4 =
+ param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
+
+ auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f), 1_f)
+ : Call(param.name, vec2<f32>(1_f, 2_f), 1_f);
+ WrapInFunction(call);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+}
+
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+ ResolverBuiltinTest_DataPacking,
+ testing::Values(BuiltinData{"pack4x8snorm", BuiltinType::kPack4x8snorm},
+ BuiltinData{"pack4x8unorm", BuiltinType::kPack4x8unorm},
+ BuiltinData{"pack2x16snorm", BuiltinType::kPack2x16snorm},
+ BuiltinData{"pack2x16unorm", BuiltinType::kPack2x16unorm},
+ BuiltinData{"pack2x16float",
+ BuiltinType::kPack2x16float}));
+
+} // namespace data_packing_builtin_tests
+
+// Tests for Data Unpacking builtins
+namespace data_unpacking_builtin_tests {
+
+using ResolverBuiltinTest_DataUnpacking = ResolverTestWithParam<BuiltinData>;
+TEST_P(ResolverBuiltinTest_DataUnpacking, InferType) {
+ auto param = GetParam();
+
+ bool pack4 = param.builtin == BuiltinType::kUnpack4x8snorm ||
+ param.builtin == BuiltinType::kUnpack4x8unorm;
+
+ auto* call = Call(param.name, 1_u);
+ WrapInFunction(call);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->is_float_vector());
+ if (pack4) {
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 4u);
+ } else {
+ EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 2u);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ResolverTest,
+ ResolverBuiltinTest_DataUnpacking,
+ testing::Values(BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4x8snorm},
+ BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4x8unorm},
+ BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2x16snorm},
+ BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2x16unorm},
+ BuiltinData{"unpack2x16float", BuiltinType::kUnpack2x16float}));
+
+} // namespace data_unpacking_builtin_tests
+
+// Tests for Synchronization builtins
+namespace synchronization_builtin_tests {
+
+using ResolverBuiltinTest_Barrier = ResolverTestWithParam<BuiltinData>;
+TEST_P(ResolverBuiltinTest_Barrier, InferType) {
+ auto param = GetParam();
+
+ auto* call = Call(param.name);
+ WrapInFunction(CallStmt(call));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ ASSERT_NE(TypeOf(call), nullptr);
+ EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
+}
+
+TEST_P(ResolverBuiltinTest_Barrier, Error_TooManyParams) {
+ auto param = GetParam();
+
+ auto* call = Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f), 1_f);
+ WrapInFunction(CallStmt(call));
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ResolverTest,
+ ResolverBuiltinTest_Barrier,
+ testing::Values(BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
+ BuiltinData{"workgroupBarrier", BuiltinType::kWorkgroupBarrier}));
+
+} // namespace synchronization_builtin_tests
+
} // namespace
} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/builtin_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/builtin_validation_test.cc
index ab40296c68f..83603c3da66 100644
--- a/chromium/third_party/dawn/src/tint/resolver/builtin_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/builtin_validation_test.cc
@@ -24,8 +24,8 @@ using ResolverBuiltinValidationTest = ResolverTest;
TEST_F(ResolverBuiltinValidationTest, FunctionTypeMustMatchReturnStatementType_void_fail) {
// fn func { return workgroupBarrier(); }
- Func("func", {}, ty.void_(),
- {
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(Call(Source{Source::Location{12, 34}}, "workgroupBarrier")),
});
@@ -36,10 +36,18 @@ TEST_F(ResolverBuiltinValidationTest, FunctionTypeMustMatchReturnStatementType_v
TEST_F(ResolverBuiltinValidationTest, InvalidPipelineStageDirect) {
// @compute @workgroup_size(1) fn func { return dpdx(1.0); }
- auto* dpdx =
- create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"), ast::ExpressionList{Expr(1_f)});
- Func(Source{{1, 2}}, "func", ast::VariableList{}, ty.void_(), {CallStmt(dpdx)},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
+ utils::Vector{
+ Expr(1_f),
+ });
+ Func(Source{{1, 2}}, "func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(dpdx),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "3:4 error: built-in cannot be used by compute pipeline stage");
@@ -51,16 +59,33 @@ TEST_F(ResolverBuiltinValidationTest, InvalidPipelineStageIndirect) {
// fn f2 { f1(); }
// @compute @workgroup_size(1) fn main { return f2(); }
- auto* dpdx =
- create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"), ast::ExpressionList{Expr(1_f)});
- Func(Source{{1, 2}}, "f0", {}, ty.void_(), {CallStmt(dpdx)});
+ auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
+ utils::Vector{
+ Expr(1_f),
+ });
+ Func(Source{{1, 2}}, "f0", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(dpdx),
+ });
- Func(Source{{3, 4}}, "f1", {}, ty.void_(), {CallStmt(Call("f0"))});
+ Func(Source{{3, 4}}, "f1", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("f0")),
+ });
- Func(Source{{5, 6}}, "f2", {}, ty.void_(), {CallStmt(Call("f1"))});
+ Func(Source{{5, 6}}, "f2", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("f1")),
+ });
- Func(Source{{7, 8}}, "main", {}, ty.void_(), {CallStmt(Call("f2"))},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ Func(Source{{7, 8}}, "main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("f2")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -72,27 +97,28 @@ TEST_F(ResolverBuiltinValidationTest, InvalidPipelineStageIndirect) {
}
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsFunction) {
- Func(Source{{12, 34}}, "mix", {}, ty.i32(), {});
+ Func(Source{{12, 34}}, "mix", utils::Empty, ty.i32(), {});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a function)");
}
-TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalLet) {
+TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalConst) {
GlobalConst(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a module-scope let)");
+ R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a 'const')");
}
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalVar) {
- Global(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), ast::StorageClass::kPrivate);
+ GlobalVar(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a module-scope var)");
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a module-scope 'var')");
}
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsAlias) {
@@ -104,7 +130,10 @@ TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsAlias) {
}
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsStruct) {
- Structure(Source{{12, 34}}, "mix", {Member("m", ty.i32())});
+ Structure(Source{{12, 34}}, "mix",
+ utils::Vector{
+ Member("m", ty.i32()),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -225,7 +254,7 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, Immediate) {
overload.BuildSamplerVariable(this);
auto args = overload.args(this);
- auto*& arg_to_replace = (param.position == Position::kFirst) ? args.front() : args.back();
+ auto*& arg_to_replace = (param.position == Position::kFirst) ? args.Front() : args.Back();
// BuildTextureVariable() uses a Literal for scalars, and a CallExpression for
// a vector constructor.
@@ -238,8 +267,13 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, Immediate) {
arg_to_replace = expr(Source{{12, 34}}, *this);
// Call the builtin with the constexpr argument replaced
- Func("func", {}, ty.void_(), {CallStmt(Call(overload.function, args))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call(overload.function, args)),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (expr.invalid_index == Constexpr::kValid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -250,11 +284,11 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, Immediate) {
err << "12:34 error: each component of the " << param.name
<< " argument must be at least " << param.min << " and at most " << param.max
<< ". " << param.name << " component " << expr.invalid_index << " is "
- << std::to_string(expr.values[expr.invalid_index]);
+ << std::to_string(expr.values[static_cast<size_t>(expr.invalid_index)]);
} else {
err << "12:34 error: the " << param.name << " argument must be at least " << param.min
<< " and at most " << param.max << ". " << param.name << " is "
- << std::to_string(expr.values[expr.invalid_index]);
+ << std::to_string(expr.values[static_cast<size_t>(expr.invalid_index)]);
}
EXPECT_EQ(r()->error(), err.str());
}
@@ -270,11 +304,11 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalConst) {
overload.BuildTextureVariable(this);
overload.BuildSamplerVariable(this);
- // Build the module-scope let 'G' with the offset value
+ // Build the module-scope const 'G' with the offset value
GlobalConst("G", nullptr, expr({}, *this));
auto args = overload.args(this);
- auto*& arg_to_replace = (param.position == Position::kFirst) ? args.front() : args.back();
+ auto*& arg_to_replace = (param.position == Position::kFirst) ? args.Front() : args.Back();
// Make the expression to be replaced, reachable. This keeps the resolver
// happy.
@@ -283,15 +317,19 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalConst) {
arg_to_replace = Expr(Source{{12, 34}}, "G");
// Call the builtin with the constexpr argument replaced
- Func("func", {}, ty.void_(), {CallStmt(Call(overload.function, args))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call(overload.function, args)),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
std::stringstream err;
err << "12:34 error: the " << param.name << " argument must be a const_expression";
EXPECT_EQ(r()->error(), err.str());
}
-
INSTANTIATE_TEST_SUITE_P(
Offset2D,
BuiltinTextureConstExprArgValidationTest,
@@ -378,12 +416,12 @@ using ResolverDP4aExtensionValidationTest = ResolverTest;
TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithExtension) {
// enable chromium_experimental_dp4a;
// fn func { return dot4I8Packed(1u, 2u); }
- Enable(ast::Extension::kChromiumExperimentalDP4a);
+ Enable(ast::Extension::kChromiumExperimentalDp4A);
- Func("func", {}, ty.i32(),
- {
+ Func("func", utils::Empty, ty.i32(),
+ utils::Vector{
Return(Call(Source{Source::Location{12, 34}}, "dot4I8Packed",
- ast::ExpressionList{Expr(1_u), Expr(2_u)})),
+ utils::Vector{Expr(1_u), Expr(2_u)})),
});
EXPECT_TRUE(r()->Resolve());
@@ -391,10 +429,10 @@ TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithExtension) {
TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithoutExtension) {
// fn func { return dot4I8Packed(1u, 2u); }
- Func("func", {}, ty.i32(),
- {
+ Func("func", utils::Empty, ty.i32(),
+ utils::Vector{
Return(Call(Source{Source::Location{12, 34}}, "dot4I8Packed",
- ast::ExpressionList{Expr(1_u), Expr(2_u)})),
+ utils::Vector{Expr(1_u), Expr(2_u)})),
});
EXPECT_FALSE(r()->Resolve());
@@ -406,12 +444,12 @@ TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithoutExtension) {
TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithExtension) {
// enable chromium_experimental_dp4a;
// fn func { return dot4U8Packed(1u, 2u); }
- Enable(ast::Extension::kChromiumExperimentalDP4a);
+ Enable(ast::Extension::kChromiumExperimentalDp4A);
- Func("func", {}, ty.u32(),
- {
+ Func("func", utils::Empty, ty.u32(),
+ utils::Vector{
Return(Call(Source{Source::Location{12, 34}}, "dot4U8Packed",
- ast::ExpressionList{Expr(1_u), Expr(2_u)})),
+ utils::Vector{Expr(1_u), Expr(2_u)})),
});
EXPECT_TRUE(r()->Resolve());
@@ -419,10 +457,10 @@ TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithExtension) {
TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithoutExtension) {
// fn func { return dot4U8Packed(1u, 2u); }
- Func("func", {}, ty.u32(),
- {
+ Func("func", utils::Empty, ty.u32(),
+ utils::Vector{
Return(Call(Source{Source::Location{12, 34}}, "dot4U8Packed",
- ast::ExpressionList{Expr(1_u), Expr(2_u)})),
+ utils::Vector{Expr(1_u), Expr(2_u)})),
});
EXPECT_FALSE(r()->Resolve());
diff --git a/chromium/third_party/dawn/src/tint/resolver/builtins_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/builtins_validation_test.cc
index 0c5948595e5..631890119c2 100644
--- a/chromium/third_party/dawn/src/tint/resolver/builtins_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/builtins_validation_test.cc
@@ -33,79 +33,97 @@ class ResolverBuiltinsValidationTest : public resolver::TestHelper, public testi
namespace StageTest {
struct Params {
builder::ast_type_func_ptr type;
- ast::Builtin builtin;
+ ast::BuiltinValue builtin;
ast::PipelineStage stage;
bool is_valid;
};
template <typename T>
-constexpr Params ParamsFor(ast::Builtin builtin, ast::PipelineStage stage, bool is_valid) {
+constexpr Params ParamsFor(ast::BuiltinValue builtin, ast::PipelineStage stage, bool is_valid) {
return Params{DataType<T>::AST, builtin, stage, is_valid};
}
static constexpr Params cases[] = {
- ParamsFor<vec4<f32>>(ast::Builtin::kPosition, ast::PipelineStage::kVertex, false),
- ParamsFor<vec4<f32>>(ast::Builtin::kPosition, ast::PipelineStage::kFragment, true),
- ParamsFor<vec4<f32>>(ast::Builtin::kPosition, ast::PipelineStage::kCompute, false),
-
- ParamsFor<u32>(ast::Builtin::kVertexIndex, ast::PipelineStage::kVertex, true),
- ParamsFor<u32>(ast::Builtin::kVertexIndex, ast::PipelineStage::kFragment, false),
- ParamsFor<u32>(ast::Builtin::kVertexIndex, ast::PipelineStage::kCompute, false),
-
- ParamsFor<u32>(ast::Builtin::kInstanceIndex, ast::PipelineStage::kVertex, true),
- ParamsFor<u32>(ast::Builtin::kInstanceIndex, ast::PipelineStage::kFragment, false),
- ParamsFor<u32>(ast::Builtin::kInstanceIndex, ast::PipelineStage::kCompute, false),
-
- ParamsFor<bool>(ast::Builtin::kFrontFacing, ast::PipelineStage::kVertex, false),
- ParamsFor<bool>(ast::Builtin::kFrontFacing, ast::PipelineStage::kFragment, true),
- ParamsFor<bool>(ast::Builtin::kFrontFacing, ast::PipelineStage::kCompute, false),
-
- ParamsFor<vec3<u32>>(ast::Builtin::kLocalInvocationId, ast::PipelineStage::kVertex, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kLocalInvocationId, ast::PipelineStage::kFragment, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kLocalInvocationId, ast::PipelineStage::kCompute, true),
-
- ParamsFor<u32>(ast::Builtin::kLocalInvocationIndex, ast::PipelineStage::kVertex, false),
- ParamsFor<u32>(ast::Builtin::kLocalInvocationIndex, ast::PipelineStage::kFragment, false),
- ParamsFor<u32>(ast::Builtin::kLocalInvocationIndex, ast::PipelineStage::kCompute, true),
-
- ParamsFor<vec3<u32>>(ast::Builtin::kGlobalInvocationId, ast::PipelineStage::kVertex, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kGlobalInvocationId, ast::PipelineStage::kFragment, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kGlobalInvocationId, ast::PipelineStage::kCompute, true),
-
- ParamsFor<vec3<u32>>(ast::Builtin::kWorkgroupId, ast::PipelineStage::kVertex, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kWorkgroupId, ast::PipelineStage::kFragment, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kWorkgroupId, ast::PipelineStage::kCompute, true),
-
- ParamsFor<vec3<u32>>(ast::Builtin::kNumWorkgroups, ast::PipelineStage::kVertex, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kNumWorkgroups, ast::PipelineStage::kFragment, false),
- ParamsFor<vec3<u32>>(ast::Builtin::kNumWorkgroups, ast::PipelineStage::kCompute, true),
-
- ParamsFor<u32>(ast::Builtin::kSampleIndex, ast::PipelineStage::kVertex, false),
- ParamsFor<u32>(ast::Builtin::kSampleIndex, ast::PipelineStage::kFragment, true),
- ParamsFor<u32>(ast::Builtin::kSampleIndex, ast::PipelineStage::kCompute, false),
-
- ParamsFor<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kVertex, false),
- ParamsFor<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kFragment, true),
- ParamsFor<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kCompute, false),
+ ParamsFor<vec4<f32>>(ast::BuiltinValue::kPosition, ast::PipelineStage::kVertex, false),
+ ParamsFor<vec4<f32>>(ast::BuiltinValue::kPosition, ast::PipelineStage::kFragment, true),
+ ParamsFor<vec4<f32>>(ast::BuiltinValue::kPosition, ast::PipelineStage::kCompute, false),
+
+ ParamsFor<u32>(ast::BuiltinValue::kVertexIndex, ast::PipelineStage::kVertex, true),
+ ParamsFor<u32>(ast::BuiltinValue::kVertexIndex, ast::PipelineStage::kFragment, false),
+ ParamsFor<u32>(ast::BuiltinValue::kVertexIndex, ast::PipelineStage::kCompute, false),
+
+ ParamsFor<u32>(ast::BuiltinValue::kInstanceIndex, ast::PipelineStage::kVertex, true),
+ ParamsFor<u32>(ast::BuiltinValue::kInstanceIndex, ast::PipelineStage::kFragment, false),
+ ParamsFor<u32>(ast::BuiltinValue::kInstanceIndex, ast::PipelineStage::kCompute, false),
+
+ ParamsFor<bool>(ast::BuiltinValue::kFrontFacing, ast::PipelineStage::kVertex, false),
+ ParamsFor<bool>(ast::BuiltinValue::kFrontFacing, ast::PipelineStage::kFragment, true),
+ ParamsFor<bool>(ast::BuiltinValue::kFrontFacing, ast::PipelineStage::kCompute, false),
+
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kLocalInvocationId, ast::PipelineStage::kVertex, false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kLocalInvocationId,
+ ast::PipelineStage::kFragment,
+ false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kLocalInvocationId, ast::PipelineStage::kCompute, true),
+
+ ParamsFor<u32>(ast::BuiltinValue::kLocalInvocationIndex, ast::PipelineStage::kVertex, false),
+ ParamsFor<u32>(ast::BuiltinValue::kLocalInvocationIndex, ast::PipelineStage::kFragment, false),
+ ParamsFor<u32>(ast::BuiltinValue::kLocalInvocationIndex, ast::PipelineStage::kCompute, true),
+
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+ ast::PipelineStage::kVertex,
+ false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+ ast::PipelineStage::kFragment,
+ false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+ ast::PipelineStage::kCompute,
+ true),
+
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kWorkgroupId, ast::PipelineStage::kVertex, false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kWorkgroupId, ast::PipelineStage::kFragment, false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kWorkgroupId, ast::PipelineStage::kCompute, true),
+
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kVertex, false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kFragment, false),
+ ParamsFor<vec3<u32>>(ast::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kCompute, true),
+
+ ParamsFor<u32>(ast::BuiltinValue::kSampleIndex, ast::PipelineStage::kVertex, false),
+ ParamsFor<u32>(ast::BuiltinValue::kSampleIndex, ast::PipelineStage::kFragment, true),
+ ParamsFor<u32>(ast::BuiltinValue::kSampleIndex, ast::PipelineStage::kCompute, false),
+
+ ParamsFor<u32>(ast::BuiltinValue::kSampleMask, ast::PipelineStage::kVertex, false),
+ ParamsFor<u32>(ast::BuiltinValue::kSampleMask, ast::PipelineStage::kFragment, true),
+ ParamsFor<u32>(ast::BuiltinValue::kSampleMask, ast::PipelineStage::kCompute, false),
};
using ResolverBuiltinsStageTest = ResolverTestWithParam<Params>;
TEST_P(ResolverBuiltinsStageTest, All_input) {
const Params& params = GetParam();
- auto* p = Global("p", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ auto* p = GlobalVar("p", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* input = Param("input", params.type(*this),
- ast::AttributeList{Builtin(Source{{12, 34}}, params.builtin)});
+ utils::Vector{Builtin(Source{{12, 34}}, params.builtin)});
switch (params.stage) {
case ast::PipelineStage::kVertex:
- Func("main", {input}, ty.vec4<f32>(), {Return(p)}, {Stage(ast::PipelineStage::kVertex)},
- {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
+ Func("main", utils::Vector{input}, ty.vec4<f32>(), utils::Vector{Return(p)},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)},
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+ });
break;
case ast::PipelineStage::kFragment:
- Func("main", {input}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)}, {});
+ Func("main", utils::Vector{input}, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ {});
break;
case ast::PipelineStage::kCompute:
- Func("main", {input}, ty.void_(), {},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ Func("main", utils::Vector{input}, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
break;
default:
break;
@@ -130,10 +148,23 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInput_Fail) {
// fn fs_main(
// @builtin(frag_depth) fd: f32,
// ) -> @location(0) f32 { return 1.0; }
- auto* fd = Param("fd", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
- Func("fs_main", ast::VariableList{fd}, ty.f32(), {Return(1_f)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ Func("fs_main",
+ utils::Vector{
+ Param("fd", ty.f32(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+ }),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: builtin(frag_depth) cannot be used in input of "
@@ -147,13 +178,28 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInputStruct_Fail) {
// @fragment
// fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
- auto* s = Structure(
- "MyInputs",
- {Member("frag_depth", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)})});
-
- Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* s = Structure("MyInputs",
+ utils::Vector{
+ Member("frag_depth", ty.f32(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+ }),
+ });
+
+ Func("fragShader",
+ utils::Vector{
+ Param("arg", ty.Of(s)),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: builtin(frag_depth) cannot be used in input of "
@@ -168,10 +214,17 @@ TEST_F(ResolverBuiltinsValidationTest, StructBuiltinInsideEntryPoint_Ignored) {
// @fragment
// fn fragShader() { var s : S; }
- Structure("S", {Member("idx", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)})});
-
- Func("fragShader", {}, ty.void_(), {Decl(Var("s", ty.type_name("S")))},
- {Stage(ast::PipelineStage::kFragment)});
+ Structure("S", utils::Vector{
+ Member("idx", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kVertexIndex),
+ }),
+ });
+
+ Func("fragShader", utils::Empty, ty.void_(), utils::Vector{Decl(Var("s", ty.type_name("S")))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve());
}
@@ -184,11 +237,27 @@ TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_Struct_Fail) {
// @fragment
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
- auto* m = Member("position", ty.vec4<u32>(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
- auto* s = Structure("MyInputs", {m});
- Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* s = Structure("MyInputs",
+ utils::Vector{
+ Member("position", ty.vec4<u32>(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+ }),
+ });
+ Func("fragShader",
+ utils::Vector{
+ Param("arg", ty.Of(s)),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
@@ -197,8 +266,14 @@ TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_Struct_Fail) {
TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_ReturnType_Fail) {
// @vertex
// fn main() -> @builtin(position) f32 { return 1.0; }
- Func("main", {}, ty.f32(), {Return(1_f)}, {Stage(ast::PipelineStage::kVertex)},
- {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
+ Func("main", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{Stage(ast::PipelineStage::kVertex)},
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
@@ -211,11 +286,23 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
// @fragment
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
- auto* m = Member("frag_depth", ty.i32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
- auto* s = Structure("MyInputs", {m});
- Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* s = Structure("MyInputs",
+ utils::Vector{
+ Member("frag_depth", ty.i32(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+ }),
+ });
+ Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(frag_depth) must be 'f32'");
@@ -228,12 +315,23 @@ TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
// @fragment
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
- auto* s = Structure(
- "MyInputs",
- {Member("m", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)})});
- Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* s = Structure("MyInputs",
+ utils::Vector{
+ Member("m", ty.f32(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask),
+ }),
+ });
+ Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
@@ -242,8 +340,13 @@ TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_ReturnType_Fail) {
// @fragment
// fn main() -> @builtin(sample_mask) i32 { return 1; }
- Func("main", {}, ty.i32(), {Return(1_i)}, {Stage(ast::PipelineStage::kFragment)},
- {Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
+ Func("main", utils::Empty, ty.i32(), utils::Vector{Return(1_i)},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
@@ -254,10 +357,23 @@ TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
// fn fs_main(
// @builtin(sample_mask) arg: bool
// ) -> @location(0) f32 { return 1.0; }
- auto* arg = Param("arg", ty.bool_(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
- Func("fs_main", ast::VariableList{arg}, ty.f32(), {Return(1_f)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ Func("fs_main",
+ utils::Vector{
+ Param("arg", ty.bool_(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask),
+ }),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
}
@@ -269,12 +385,23 @@ TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Struct_Fail) {
// @fragment
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
- auto* s = Structure(
- "MyInputs",
- {Member("m", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)})});
- Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* s = Structure("MyInputs",
+ utils::Vector{
+ Member("m", ty.f32(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleIndex),
+ }),
+ });
+ Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_index) must be 'u32'");
@@ -285,10 +412,23 @@ TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Fail) {
// fn fs_main(
// @builtin(sample_index) arg: bool
// ) -> @location(0) f32 { return 1.0; }
- auto* arg = Param("arg", ty.bool_(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)});
- Func("fs_main", ast::VariableList{arg}, ty.f32(), {Return(1_f)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ Func("fs_main",
+ utils::Vector{
+ Param("arg", ty.bool_(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleIndex),
+ }),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_index) must be 'u32'");
}
@@ -298,10 +438,23 @@ TEST_F(ResolverBuiltinsValidationTest, PositionIsNotF32_Fail) {
// fn fs_main(
// @builtin(kPosition) p: vec3<f32>,
// ) -> @location(0) f32 { return 1.0; }
- auto* p = Param("p", ty.vec3<f32>(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
- Func("fs_main", ast::VariableList{p}, ty.f32(), {Return(1_f)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ Func("fs_main",
+ utils::Vector{
+ Param("p", ty.vec3<f32>(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+ }),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
}
@@ -310,9 +463,17 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthIsNotF32_Fail) {
// @fragment
// fn fs_main() -> @builtin(kFragDepth) f32 { var fd: i32; return fd; }
auto* fd = Var("fd", ty.i32());
- Func("fs_main", {}, ty.i32(), {Decl(fd), Return(fd)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
+ Func("fs_main", utils::Empty, ty.i32(),
+ utils::Vector{
+ Decl(fd),
+ Return(fd),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(frag_depth) must be 'f32'");
}
@@ -323,12 +484,21 @@ TEST_F(ResolverBuiltinsValidationTest, VertexIndexIsNotU32_Fail) {
// @builtin(kVertexIndex) vi : f32,
// @builtin(kPosition) p :vec4<f32>
// ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
- auto* p = Param("p", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+ auto* p = Param("p", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
auto* vi = Param("vi", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
- Func("main", ast::VariableList{vi, p}, ty.vec4<f32>(), {Return(Expr("p"))},
- ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
- ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kVertexIndex),
+ });
+ Func("main", utils::Vector{vi, p}, ty.vec4<f32>(), utils::Vector{Return(Expr("p"))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(vertex_index) must be 'u32'");
}
@@ -339,12 +509,21 @@ TEST_F(ResolverBuiltinsValidationTest, InstanceIndexIsNotU32) {
// @builtin(kInstanceIndex) ii : f32,
// @builtin(kPosition) p :vec4<f32>
// ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
- auto* p = Param("p", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+ auto* p = Param("p", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
auto* ii = Param("ii", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kInstanceIndex)});
- Func("main", ast::VariableList{ii, p}, ty.vec4<f32>(), {Return(Expr("p"))},
- ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
- ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kInstanceIndex),
+ });
+ Func("main", utils::Vector{ii, p}, ty.vec4<f32>(), utils::Vector{Return(Expr("p"))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(instance_index) must be 'u32'");
}
@@ -357,14 +536,34 @@ TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltin_Pass) {
// @builtin(sample_index) si: u32,
// @builtin(sample_mask) sm : u32
// ) -> @builtin(frag_depth) f32 { var fd: f32; return fd; }
- auto* p = Param("p", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)});
- auto* ff = Param("ff", ty.bool_(), ast::AttributeList{Builtin(ast::Builtin::kFrontFacing)});
- auto* si = Param("si", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleIndex)});
- auto* sm = Param("sm", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleMask)});
+ auto* p = Param("p", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
+ auto* ff = Param("ff", ty.bool_(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFrontFacing),
+ });
+ auto* si = Param("si", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleIndex),
+ });
+ auto* sm = Param("sm", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleMask),
+ });
auto* var_fd = Var("fd", ty.f32());
- Func("fs_main", ast::VariableList{p, ff, si, sm}, ty.f32(), {Decl(var_fd), Return(var_fd)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
- ast::AttributeList{Builtin(ast::Builtin::kFragDepth)});
+ Func("fs_main", utils::Vector{p, ff, si, sm}, ty.f32(),
+ utils::Vector{
+ Decl(var_fd),
+ Return(var_fd),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFragDepth),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -375,18 +574,24 @@ TEST_F(ResolverBuiltinsValidationTest, VertexBuiltin_Pass) {
// @builtin(instance_index) ii : u32,
// ) -> @builtin(position) vec4<f32> { var p :vec4<f32>; return p; }
auto* vi = Param("vi", ty.u32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kVertexIndex),
+ });
auto* ii = Param("ii", ty.u32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kInstanceIndex)});
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kInstanceIndex),
+ });
auto* p = Var("p", ty.vec4<f32>());
- Func("main", ast::VariableList{vi, ii}, ty.vec4<f32>(),
- {
+ Func("main", utils::Vector{vi, ii}, ty.vec4<f32>(),
+ utils::Vector{
Decl(p),
Return(p),
},
- ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
- ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+ utils::Vector{Stage(ast::PipelineStage::kVertex)},
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -402,28 +607,41 @@ TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_Pass) {
// ) {}
auto* li_id = Param("li_id", ty.vec3<u32>(),
- ast::AttributeList{Builtin(ast::Builtin::kLocalInvocationId)});
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kLocalInvocationId),
+ });
auto* li_index = Param("li_index", ty.u32(),
- ast::AttributeList{Builtin(ast::Builtin::kLocalInvocationIndex)});
- auto* gi =
- Param("gi", ty.vec3<u32>(), ast::AttributeList{Builtin(ast::Builtin::kGlobalInvocationId)});
- auto* wi = Param("wi", ty.vec3<u32>(), ast::AttributeList{Builtin(ast::Builtin::kWorkgroupId)});
- auto* nwgs =
- Param("nwgs", ty.vec3<u32>(), ast::AttributeList{Builtin(ast::Builtin::kNumWorkgroups)});
-
- Func("main", ast::VariableList{li_id, li_index, gi, wi, nwgs}, ty.void_(), {},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kLocalInvocationIndex),
+ });
+ auto* gi = Param("gi", ty.vec3<u32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kGlobalInvocationId),
+ });
+ auto* wi = Param("wi", ty.vec3<u32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kWorkgroupId),
+ });
+ auto* nwgs = Param("nwgs", ty.vec3<u32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kNumWorkgroups),
+ });
+
+ Func("main", utils::Vector{li_id, li_index, gi, wi, nwgs}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_WorkGroupIdNotVec3U32) {
auto* wi = Param("wi", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kWorkgroupId)});
- Func("main", ast::VariableList{wi}, ty.void_(), {},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kWorkgroupId),
+ });
+ Func("main", utils::Vector{wi}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -433,10 +651,12 @@ TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_WorkGroupIdNotVec3U32) {
TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_NumWorkgroupsNotVec3U32) {
auto* nwgs = Param("nwgs", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kNumWorkgroups)});
- Func("main", ast::VariableList{nwgs}, ty.void_(), {},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kNumWorkgroups),
+ });
+ Func("main", utils::Vector{nwgs}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -445,12 +665,13 @@ TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_NumWorkgroupsNotVec3U32) {
}
TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_GlobalInvocationNotVec3U32) {
- auto* gi =
- Param("gi", ty.vec3<i32>(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kGlobalInvocationId)});
- Func("main", ast::VariableList{gi}, ty.void_(), {},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
+ auto* gi = Param("gi", ty.vec3<i32>(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kGlobalInvocationId),
+ });
+ Func("main", utils::Vector{gi}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -459,12 +680,13 @@ TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_GlobalInvocationNotVec3U32
}
TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationIndexNotU32) {
- auto* li_index =
- Param("li_index", ty.vec3<u32>(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kLocalInvocationIndex)});
- Func("main", ast::VariableList{li_index}, ty.void_(), {},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
+ auto* li_index = Param("li_index", ty.vec3<u32>(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kLocalInvocationIndex),
+ });
+ Func("main", utils::Vector{li_index}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -473,12 +695,13 @@ TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationIndexNotU32
}
TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationNotVec3U32) {
- auto* li_id =
- Param("li_id", ty.vec2<u32>(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kLocalInvocationId)});
- Func("main", ast::VariableList{li_id}, ty.void_(), {},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
+ auto* li_id = Param("li_id", ty.vec2<u32>(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kLocalInvocationId),
+ });
+ Func("main", utils::Vector{li_id}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -496,15 +719,34 @@ TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltinStruct_Pass) {
// @fragment
// fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
- auto* s = Structure(
- "MyInputs",
- {Member("position", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)}),
- Member("front_facing", ty.bool_(),
- ast::AttributeList{Builtin(ast::Builtin::kFrontFacing)}),
- Member("sample_index", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleIndex)}),
- Member("sample_mask", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleMask)})});
- Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* s = Structure("MyInputs", utils::Vector{
+ Member("position", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ }),
+ Member("front_facing", ty.bool_(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFrontFacing),
+ }),
+ Member("sample_index", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleIndex),
+ }),
+ Member("sample_mask", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleMask),
+ }),
+ });
+ Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -514,11 +756,20 @@ TEST_F(ResolverBuiltinsValidationTest, FrontFacingParamIsNotBool_Fail) {
// @builtin(front_facing) is_front: i32;
// ) -> @location(0) f32 { return 1.0; }
- auto* is_front =
- Param("is_front", ty.i32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFrontFacing)});
- Func("fs_main", ast::VariableList{is_front}, ty.f32(), {Return(1_f)},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* is_front = Param("is_front", ty.i32(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kFrontFacing),
+ });
+ Func("fs_main", utils::Vector{is_front}, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(front_facing) must be 'bool'");
@@ -531,12 +782,23 @@ TEST_F(ResolverBuiltinsValidationTest, FrontFacingMemberIsNotBool_Fail) {
// @fragment
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
- auto* s = Structure(
- "MyInputs",
- {Member("pos", ty.f32(),
- ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFrontFacing)})});
- Func("fragShader", {Param("is_front", ty.Of(s))}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ auto* s = Structure("MyInputs",
+ utils::Vector{
+ Member("pos", ty.f32(),
+ utils::Vector{
+ Builtin(Source{{12, 34}}, ast::BuiltinValue::kFrontFacing),
+ }),
+ });
+ Func("fragShader", utils::Vector{Param("is_front", ty.Of(s))}, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(front_facing) must be 'bool'");
@@ -835,13 +1097,18 @@ TEST_P(FloatAllMatching, Scalar) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(Expr(1_f));
+ params.Push(Expr(1_f));
}
auto* builtin = Call(name, params);
- Func("func", {}, ty.void_(), {CallStmt(builtin)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(builtin),
+ },
+ utils::Vector{
+ create<ast::StageAttribute>(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->Is<sem::F32>());
@@ -851,13 +1118,18 @@ TEST_P(FloatAllMatching, Vec2) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec2<f32>(1_f, 1_f));
+ params.Push(vec2<f32>(1_f, 1_f));
}
auto* builtin = Call(name, params);
- Func("func", {}, ty.void_(), {CallStmt(builtin)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(builtin),
+ },
+ utils::Vector{
+ create<ast::StageAttribute>(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -867,13 +1139,18 @@ TEST_P(FloatAllMatching, Vec3) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec3<f32>(1_f, 1_f, 1_f));
+ params.Push(vec3<f32>(1_f, 1_f, 1_f));
}
auto* builtin = Call(name, params);
- Func("func", {}, ty.void_(), {CallStmt(builtin)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(builtin),
+ },
+ utils::Vector{
+ create<ast::StageAttribute>(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -883,13 +1160,18 @@ TEST_P(FloatAllMatching, Vec4) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec4<f32>(1_f, 1_f, 1_f, 1_f));
+ params.Push(vec4<f32>(1_f, 1_f, 1_f, 1_f));
}
auto* builtin = Call(name, params);
- Func("func", {}, ty.void_(), {CallStmt(builtin)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(builtin),
+ },
+ utils::Vector{
+ create<ast::StageAttribute>(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -945,9 +1227,9 @@ TEST_P(IntegerAllMatching, ScalarUnsigned) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(Construct<u32>(1_i));
+ params.Push(Construct<u32>(1_i));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -960,9 +1242,9 @@ TEST_P(IntegerAllMatching, Vec2Unsigned) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec2<u32>(1_u, 1_u));
+ params.Push(vec2<u32>(1_u, 1_u));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -975,9 +1257,9 @@ TEST_P(IntegerAllMatching, Vec3Unsigned) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec3<u32>(1_u, 1_u, 1_u));
+ params.Push(vec3<u32>(1_u, 1_u, 1_u));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -990,9 +1272,9 @@ TEST_P(IntegerAllMatching, Vec4Unsigned) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec4<u32>(1_u, 1_u, 1_u, 1_u));
+ params.Push(vec4<u32>(1_u, 1_u, 1_u, 1_u));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -1005,9 +1287,9 @@ TEST_P(IntegerAllMatching, ScalarSigned) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(Construct<i32>(1_i));
+ params.Push(Construct<i32>(1_i));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -1020,9 +1302,9 @@ TEST_P(IntegerAllMatching, Vec2Signed) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec2<i32>(1_i, 1_i));
+ params.Push(vec2<i32>(1_i, 1_i));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -1035,9 +1317,9 @@ TEST_P(IntegerAllMatching, Vec3Signed) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec3<i32>(1_i, 1_i, 1_i));
+ params.Push(vec3<i32>(1_i, 1_i, 1_i));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -1050,9 +1332,9 @@ TEST_P(IntegerAllMatching, Vec4Signed) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec4<i32>(1_i, 1_i, 1_i, 1_i));
+ params.Push(vec4<i32>(1_i, 1_i, 1_i, 1_i));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -1077,9 +1359,9 @@ TEST_P(BooleanVectorInput, Vec2) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec2<bool>(true, true));
+ params.Push(vec2<bool>(true, true));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -1091,9 +1373,9 @@ TEST_P(BooleanVectorInput, Vec3) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec3<bool>(true, true, true));
+ params.Push(vec3<bool>(true, true, true));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
@@ -1105,9 +1387,9 @@ TEST_P(BooleanVectorInput, Vec4) {
std::string name = std::get<0>(GetParam());
uint32_t num_params = std::get<1>(GetParam());
- ast::ExpressionList params;
+ utils::Vector<const ast::Expression*, 8> params;
for (uint32_t i = 0; i < num_params; ++i) {
- params.push_back(vec4<bool>(true, true, true, true));
+ params.Push(vec4<bool>(true, true, true, true));
}
auto* builtin = Call(name, params);
WrapInFunction(builtin);
diff --git a/chromium/third_party/dawn/src/tint/resolver/call_test.cc b/chromium/third_party/dawn/src/tint/resolver/call_test.cc
index 39a6eb490cc..37aaffa09c5 100644
--- a/chromium/third_party/dawn/src/tint/resolver/call_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/call_test.cc
@@ -71,6 +71,7 @@ static constexpr Params all_param_types[] = {
ParamsFor<u32>(), //
ParamsFor<i32>(), //
ParamsFor<f32>(), //
+ ParamsFor<f16>(), //
ParamsFor<vec3<bool>>(), //
ParamsFor<vec3<i32>>(), //
ParamsFor<vec3<u32>>(), //
@@ -81,14 +82,16 @@ static constexpr Params all_param_types[] = {
};
TEST_F(ResolverCallTest, Valid) {
- ast::VariableList params;
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ utils::Vector<const ast::Parameter*, 4> params;
+ utils::Vector<const ast::Expression*, 4> args;
for (auto& p : all_param_types) {
- params.push_back(Param(Sym(), p.create_type(*this)));
- args.push_back(p.create_value(*this, 0));
+ params.Push(Param(Sym(), p.create_type(*this)));
+ args.Push(p.create_value(*this, 0));
}
- auto* func = Func("foo", std::move(params), ty.f32(), {Return(1.23_f)});
+ auto* func = Func("foo", std::move(params), ty.f32(), utils::Vector{Return(1.23_f)});
auto* call_expr = Call("foo", std::move(args));
WrapInFunction(call_expr);
@@ -101,8 +104,8 @@ TEST_F(ResolverCallTest, Valid) {
TEST_F(ResolverCallTest, OutOfOrder) {
auto* call_expr = Call("b");
- Func("a", {}, ty.void_(), {CallStmt(call_expr)});
- auto* b = Func("b", {}, ty.void_(), {});
+ Func("a", utils::Empty, ty.void_(), utils::Vector{CallStmt(call_expr)});
+ auto* b = Func("b", utils::Empty, ty.void_(), utils::Empty);
EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/chromium/third_party/dawn/src/tint/resolver/call_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/call_validation_test.cc
index 4aa63509cff..42430939bdc 100644
--- a/chromium/third_party/dawn/src/tint/resolver/call_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/call_validation_test.cc
@@ -26,7 +26,15 @@ namespace {
using ResolverCallValidationTest = ResolverTest;
TEST_F(ResolverCallValidationTest, TooFewArgs) {
- Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(), {Return()});
+ Func("foo",
+ utils::Vector{
+ Param(Sym(), ty.i32()),
+ Param(Sym(), ty.f32()),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ });
auto* call = Call(Source{{12, 34}}, "foo", 1_i);
WrapInFunction(call);
@@ -35,7 +43,15 @@ TEST_F(ResolverCallValidationTest, TooFewArgs) {
}
TEST_F(ResolverCallValidationTest, TooManyArgs) {
- Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(), {Return()});
+ Func("foo",
+ utils::Vector{
+ Param(Sym(), ty.i32()),
+ Param(Sym(), ty.f32()),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ });
auto* call = Call(Source{{12, 34}}, "foo", 1_i, 1_f, 1_f);
WrapInFunction(call);
@@ -44,7 +60,15 @@ TEST_F(ResolverCallValidationTest, TooManyArgs) {
}
TEST_F(ResolverCallValidationTest, MismatchedArgs) {
- Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(), {Return()});
+ Func("foo",
+ utils::Vector{
+ Param(Sym(), ty.i32()),
+ Param(Sym(), ty.f32()),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ });
auto* call = Call("foo", Expr(Source{{12, 34}}, true), 1_f);
WrapInFunction(call);
@@ -58,10 +82,14 @@ TEST_F(ResolverCallValidationTest, UnusedRetval) {
// fn func() -> f32 { return 1.0; }
// fn main() {func(); return; }
- Func("func", {}, ty.f32(), {Return(Expr(1_f))}, {});
+ Func("func", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(Expr(1_f)),
+ },
+ utils::Empty);
- Func("main", {}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Source{{12, 34}}, Call("func")),
Return(),
});
@@ -76,9 +104,9 @@ TEST_F(ResolverCallValidationTest, PointerArgument_VariableIdentExpr) {
// foo(&z);
// }
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
- Func("foo", {param}, ty.void_(), {});
- Func("main", {}, ty.void_(),
- {
+ Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("z", ty.i32(), Expr(1_i))),
CallStmt(Call("foo", AddressOf(Source{{12, 34}}, Expr("z")))),
});
@@ -93,9 +121,9 @@ TEST_F(ResolverCallValidationTest, PointerArgument_ConstIdentExpr) {
// foo(&z);
// }
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
- Func("foo", {param}, ty.void_(), {});
- Func("main", {}, ty.void_(),
- {
+ Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("z", ty.i32(), Expr(1_i))),
CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}}, "z")))),
});
@@ -111,11 +139,13 @@ TEST_F(ResolverCallValidationTest, PointerArgument_NotIdentExprVar) {
// var v: S;
// foo(&v.m);
// }
- auto* S = Structure("S", {Member("m", ty.i32())});
+ auto* S = Structure("S", utils::Vector{
+ Member("m", ty.i32()),
+ });
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
- Func("foo", {param}, ty.void_(), {});
- Func("main", {}, ty.void_(),
- {
+ Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("v", ty.Of(S))),
CallStmt(Call("foo", AddressOf(Source{{12, 34}}, MemberAccessor("v", "m")))),
});
@@ -133,11 +163,13 @@ TEST_F(ResolverCallValidationTest, PointerArgument_AddressOfMemberAccessor) {
// let v: S = S();
// foo(&v.m);
// }
- auto* S = Structure("S", {Member("m", ty.i32())});
+ auto* S = Structure("S", utils::Vector{
+ Member("m", ty.i32()),
+ });
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
- Func("foo", {param}, ty.void_(), {});
- Func("main", {}, ty.void_(),
- {
+ Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("v", ty.Of(S), Construct(ty.Of(S)))),
CallStmt(Call("foo", AddressOf(MemberAccessor(Source{{12, 34}}, "v", "m")))),
});
@@ -151,9 +183,19 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam) {
// fn bar(p: ptr<function, i32>) {
// foo(p);
// }
- Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(), {});
- Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(),
- ast::StatementList{CallStmt(Call("foo", Expr("p")))});
+ Func("foo",
+ utils::Vector{
+ Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
+ },
+ ty.void_(), utils::Empty);
+ Func("bar",
+ utils::Vector{
+ Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
+ },
+ ty.void_(),
+ utils::Vector{
+ CallStmt(Call("foo", Expr("p"))),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -168,15 +210,25 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
// var v: i32;
// bar(&v);
// }
- Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(), {});
- Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(),
- ast::StatementList{CallStmt(Call("foo", Expr("p")))});
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("foo",
+ utils::Vector{
+ Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
+ },
+ ty.void_(), utils::Empty);
+ Func("bar",
+ utils::Vector{
+ Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
+ },
+ ty.void_(),
+ utils::Vector{
+ CallStmt(Call("foo", Expr("p"))),
+ });
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("v", ty.i32(), Expr(1_i))),
CallStmt(Call("foo", AddressOf(Expr("v")))),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -191,17 +243,21 @@ TEST_F(ResolverCallValidationTest, LetPointer) {
// let p: ptr<function, i32> = &v;
// var c: i32 = x(p);
// }
- Func("x", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(), {});
+ Func("x",
+ utils::Vector{
+ Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
+ },
+ ty.void_(), utils::Empty);
auto* v = Var("v", ty.i32());
auto* p = Let("p", ty.pointer(ty.i32(), ast::StorageClass::kFunction), AddressOf(v));
auto* c = Var("c", ty.i32(), ast::StorageClass::kNone, Call("x", Expr(Source{{12, 34}}, p)));
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(v),
Decl(p),
Decl(c),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
EXPECT_FALSE(r()->Resolve());
@@ -218,16 +274,20 @@ TEST_F(ResolverCallValidationTest, LetPointerPrivate) {
// fn main() {
// var c: i32 = foo(p);
// }
- Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kPrivate))}, ty.void_(), {});
- auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+ Func("foo",
+ utils::Vector{
+ Param("p", ty.pointer<i32>(ast::StorageClass::kPrivate)),
+ },
+ ty.void_(), utils::Empty);
+ auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
auto* p = Let("p", ty.pointer(ty.i32(), ast::StorageClass::kPrivate), AddressOf(v));
auto* c = Var("c", ty.i32(), ast::StorageClass::kNone, Call("foo", Expr(Source{{12, 34}}, p)));
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(p),
Decl(c),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
EXPECT_FALSE(r()->Resolve());
@@ -241,8 +301,11 @@ TEST_F(ResolverCallValidationTest, CallVariable) {
// fn f() {
// v();
// }
- Global("v", ty.i32(), ast::StorageClass::kPrivate);
- Func("f", {}, ty.void_(), {CallStmt(Call(Source{{12, 34}}, "v"))});
+ GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call(Source{{12, 34}}, "v")),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(error: cannot call variable 'v'
@@ -255,9 +318,9 @@ TEST_F(ResolverCallValidationTest, CallVariableShadowsFunction) {
// var x : i32;
// x();
// }
- Func("x", {}, ty.void_(), {});
- Func("f", {}, ty.void_(),
- {
+ Func("x", utils::Empty, ty.void_(), utils::Empty);
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var(Source{{56, 78}}, "x", ty.i32())),
CallStmt(Call(Source{{12, 34}}, "x")),
});
diff --git a/chromium/third_party/dawn/src/tint/resolver/compound_assignment_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/compound_assignment_validation_test.cc
index 1ae70406b45..5edcdaad2bb 100644
--- a/chromium/third_party/dawn/src/tint/resolver/compound_assignment_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/compound_assignment_validation_test.cc
@@ -233,8 +233,8 @@ TEST_F(ResolverCompoundAssignmentValidationTest, ReadOnlyBuffer) {
// {
// a += 1i;
// }
- Global(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", 1_i, ast::BinaryOp::kAdd));
EXPECT_FALSE(r()->Resolve());
@@ -249,7 +249,7 @@ TEST_F(ResolverCompoundAssignmentValidationTest, LhsConstant) {
WrapInFunction(a, CompoundAssign(Expr(Source{{56, 78}}, "a"), 1_i, ast::BinaryOp::kAdd));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to const
+ EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to 'let'
12:34 note: 'a' is declared here:)");
}
@@ -264,7 +264,7 @@ TEST_F(ResolverCompoundAssignmentValidationTest, LhsLiteral) {
TEST_F(ResolverCompoundAssignmentValidationTest, LhsAtomic) {
// var<workgroup> a : atomic<i32>;
// a += a;
- Global(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
+ GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", "a", ast::BinaryOp::kAdd));
EXPECT_FALSE(r()->Resolve());
diff --git a/chromium/third_party/dawn/src/tint/resolver/compound_statement_test.cc b/chromium/third_party/dawn/src/tint/resolver/compound_statement_test.cc
index 0444bd33798..0a96cedd8a4 100644
--- a/chromium/third_party/dawn/src/tint/resolver/compound_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/compound_statement_test.cc
@@ -21,6 +21,7 @@
#include "src/tint/sem/if_statement.h"
#include "src/tint/sem/loop_statement.h"
#include "src/tint/sem/switch_statement.h"
+#include "src/tint/sem/while_statement.h"
using namespace tint::number_suffixes; // NOLINT
@@ -34,7 +35,7 @@ TEST_F(ResolverCompoundStatementTest, FunctionBlock) {
// var x : 32;
// }
auto* stmt = Decl(Var("x", ty.i32()));
- auto* f = Func("F", {}, ty.void_(), {stmt});
+ auto* f = Func("F", utils::Empty, ty.void_(), utils::Vector{stmt});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -56,7 +57,7 @@ TEST_F(ResolverCompoundStatementTest, Block) {
// }
auto* stmt = Decl(Var("x", ty.i32()));
auto* block = Block(stmt);
- auto* f = Func("F", {}, ty.void_(), {block});
+ auto* f = Func("F", utils::Empty, ty.void_(), utils::Vector{block});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -91,7 +92,7 @@ TEST_F(ResolverCompoundStatementTest, Loop) {
auto* brk = Break();
auto* stmt = Ignore(1_i);
auto* loop = Loop(Block(brk), Block(stmt));
- auto* f = Func("F", {}, ty.void_(), {loop});
+ auto* f = Func("F", utils::Empty, ty.void_(), utils::Vector{loop});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -154,7 +155,7 @@ TEST_F(ResolverCompoundStatementTest, Loop_EmptyContinuing) {
// }
auto* brk = Break();
auto* loop = Loop(Block(brk), Block());
- Func("F", {}, ty.void_(), {loop});
+ Func("F", utils::Empty, ty.void_(), utils::Vector{loop});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -185,7 +186,7 @@ TEST_F(ResolverCompoundStatementTest, ForLoop) {
auto* stmt = Return();
auto* body = Block(stmt);
auto* for_ = For(init, cond, cont, body);
- auto* f = Func("F", {}, ty.void_(), {for_});
+ auto* f = Func("F", utils::Empty, ty.void_(), utils::Vector{for_});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -239,6 +240,55 @@ TEST_F(ResolverCompoundStatementTest, ForLoop) {
}
}
+TEST_F(ResolverCompoundStatementTest, While) {
+ // fn F() {
+ // while (true) {
+ // return;
+ // }
+ // }
+ auto* cond = Expr(true);
+ auto* stmt = Return();
+ auto* body = Block(stmt);
+ auto* while_ = While(cond, body);
+ auto* f = Func("W", utils::Empty, ty.void_(), utils::Vector{while_});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ {
+ auto* s = Sem().Get(while_);
+ ASSERT_NE(s, nullptr);
+ EXPECT_EQ(Sem().Get(body)->Parent(), s);
+ EXPECT_TRUE(s->Is<sem::WhileStatement>());
+ EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+ EXPECT_EQ(s->Parent(), s->Block());
+ }
+ { // Condition expression's statement is the while itself
+ auto* e = Sem().Get(cond);
+ ASSERT_NE(e, nullptr);
+ auto* s = e->Stmt();
+ ASSERT_NE(s, nullptr);
+ ASSERT_TRUE(Is<sem::WhileStatement>(s));
+ ASSERT_NE(s->Parent(), nullptr);
+ EXPECT_EQ(s->Parent(), s->Block());
+ EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+ EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Block()));
+ }
+ {
+ auto* s = Sem().Get(stmt);
+ ASSERT_NE(s, nullptr);
+ ASSERT_NE(s->Block(), nullptr);
+ EXPECT_EQ(s->Parent(), s->Block());
+ EXPECT_EQ(s->Block(), s->FindFirstParent<sem::LoopBlockStatement>());
+ EXPECT_TRUE(Is<sem::WhileStatement>(s->Parent()->Parent()));
+ EXPECT_EQ(s->Block()->Parent(), s->FindFirstParent<sem::WhileStatement>());
+ ASSERT_TRUE(Is<sem::FunctionBlockStatement>(s->Block()->Parent()->Parent()));
+ EXPECT_EQ(s->Block()->Parent()->Parent(),
+ s->FindFirstParent<sem::FunctionBlockStatement>());
+ EXPECT_EQ(s->Function()->Declaration(), f);
+ EXPECT_EQ(s->Block()->Parent()->Parent()->Parent(), nullptr);
+ }
+}
+
TEST_F(ResolverCompoundStatementTest, If) {
// fn F() {
// if (cond_a) {
diff --git a/chromium/third_party/dawn/src/tint/resolver/const_eval.cc b/chromium/third_party/dawn/src/tint/resolver/const_eval.cc
index fac2c7db78d..1e66e5a36ae 100644
--- a/chromium/third_party/dawn/src/tint/resolver/const_eval.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/const_eval.cc
@@ -14,6 +14,883 @@
#include "src/tint/resolver/const_eval.h"
+#include <algorithm>
+#include <limits>
+#include <optional>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <utility>
+
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/abstract_float.h"
+#include "src/tint/sem/abstract_int.h"
+#include "src/tint/sem/array.h"
+#include "src/tint/sem/bool.h"
#include "src/tint/sem/constant.h"
+#include "src/tint/sem/f16.h"
+#include "src/tint/sem/f32.h"
+#include "src/tint/sem/i32.h"
+#include "src/tint/sem/matrix.h"
+#include "src/tint/sem/member_accessor_expression.h"
+#include "src/tint/sem/type_constructor.h"
+#include "src/tint/sem/u32.h"
+#include "src/tint/sem/vector.h"
+#include "src/tint/utils/compiler_macros.h"
+#include "src/tint/utils/map.h"
+#include "src/tint/utils/transform.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::resolver {
+
+namespace {
+
+/// Returns the first element of a parameter pack
+template <typename T>
+T First(T&& first, ...) {
+ return std::forward<T>(first);
+}
+
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_ia_iu32(F&& f, CONSTANTS&&... cs) {
+ return Switch(
+ First(cs...)->Type(), //
+ [&](const sem::AbstractInt*) { return f(cs->template As<AInt>()...); },
+ [&](const sem::I32*) { return f(cs->template As<i32>()...); },
+ [&](const sem::U32*) { return f(cs->template As<u32>()...); });
+}
+
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_fia_fi32_f16(F&& f, CONSTANTS&&... cs) {
+ return Switch(
+ First(cs...)->Type(), //
+ [&](const sem::AbstractInt*) { return f(cs->template As<AInt>()...); },
+ [&](const sem::AbstractFloat*) { return f(cs->template As<AFloat>()...); },
+ [&](const sem::F32*) { return f(cs->template As<f32>()...); },
+ [&](const sem::I32*) { return f(cs->template As<i32>()...); },
+ [&](const sem::F16*) { return f(cs->template As<f16>()...); });
+}
+
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_fia_fiu32_f16(F&& f, CONSTANTS&&... cs) {
+ return Switch(
+ First(cs...)->Type(), //
+ [&](const sem::AbstractInt*) { return f(cs->template As<AInt>()...); },
+ [&](const sem::AbstractFloat*) { return f(cs->template As<AFloat>()...); },
+ [&](const sem::F32*) { return f(cs->template As<f32>()...); },
+ [&](const sem::I32*) { return f(cs->template As<i32>()...); },
+ [&](const sem::U32*) { return f(cs->template As<u32>()...); },
+ [&](const sem::F16*) { return f(cs->template As<f16>()...); });
+}
+
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_fa_f32_f16(F&& f, CONSTANTS&&... cs) {
+ return Switch(
+ First(cs...)->Type(), //
+ [&](const sem::AbstractFloat*) { return f(cs->template As<AFloat>()...); },
+ [&](const sem::F32*) { return f(cs->template As<f32>()...); },
+ [&](const sem::F16*) { return f(cs->template As<f16>()...); });
+}
+
+/// ZeroTypeDispatch is a helper for calling the function `f`, passing a single zero-value argument
+/// of the C++ type that corresponds to the sem::Type `type`. For example, calling
+/// `ZeroTypeDispatch()` with a type of `sem::I32*` will call the function f with a single argument
+/// of `i32(0)`.
+/// @returns the value returned by calling `f`.
+/// @note `type` must be a scalar or abstract numeric type. Other types will not call `f`, and will
+/// return the zero-initialized value of the return type for `f`.
+template <typename F>
+auto ZeroTypeDispatch(const sem::Type* type, F&& f) {
+ return Switch(
+ type, //
+ [&](const sem::AbstractInt*) { return f(AInt(0)); }, //
+ [&](const sem::AbstractFloat*) { return f(AFloat(0)); }, //
+ [&](const sem::I32*) { return f(i32(0)); }, //
+ [&](const sem::U32*) { return f(u32(0)); }, //
+ [&](const sem::F32*) { return f(f32(0)); }, //
+ [&](const sem::F16*) { return f(f16(0)); }, //
+ [&](const sem::Bool*) { return f(static_cast<bool>(0)); });
+}
+
+/// @returns `value` if `T` is not a Number, otherwise ValueOf returns the inner value of the
+/// Number.
+template <typename T>
+inline auto ValueOf(T value) {
+ if constexpr (std::is_same_v<UnwrapNumber<T>, T>) {
+ return value;
+ } else {
+ return value.value;
+ }
+}
+
+/// @returns true if `value` is a positive zero.
+template <typename T>
+inline bool IsPositiveZero(T value) {
+ using N = UnwrapNumber<T>;
+ return Number<N>(value) == Number<N>(0); // Considers sign bit
+}
+
+/// Constant inherits from sem::Constant to add an private implementation method for conversion.
+struct Constant : public sem::Constant {
+ /// Convert attempts to convert the constant value to the given type. On error, Convert()
+ /// creates a new diagnostic message and returns a Failure.
+ virtual utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const = 0;
+};
+
+// Forward declaration
+const Constant* CreateComposite(ProgramBuilder& builder,
+ const sem::Type* type,
+ utils::VectorRef<const sem::Constant*> elements);
+
+/// Element holds a single scalar or abstract-numeric value.
+/// Element implements the Constant interface.
+template <typename T>
+struct Element : Constant {
+ static_assert(!std::is_same_v<UnwrapNumber<T>, T> || std::is_same_v<T, bool>,
+ "T must be a Number or bool");
+
+ Element(const sem::Type* t, T v) : type(t), value(v) {}
+ ~Element() override = default;
+ const sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override {
+ if constexpr (IsFloatingPoint<UnwrapNumber<T>>) {
+ return static_cast<AFloat>(value);
+ } else {
+ return static_cast<AInt>(value);
+ }
+ }
+ const sem::Constant* Index(size_t) const override { return nullptr; }
+ bool AllZero() const override { return IsPositiveZero(value); }
+ bool AnyZero() const override { return IsPositiveZero(value); }
+ bool AllEqual() const override { return true; }
+ size_t Hash() const override { return utils::Hash(type, ValueOf(value)); }
+
+ utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const override {
+ TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
+ if (target_ty == type) {
+ // If the types are identical, then no conversion is needed.
+ return this;
+ }
+ bool failed = false;
+ auto* res = ZeroTypeDispatch(target_ty, [&](auto zero_to) -> const Constant* {
+ // `T` is the source type, `value` is the source value.
+ // `TO` is the target type.
+ using TO = std::decay_t<decltype(zero_to)>;
+ if constexpr (std::is_same_v<TO, bool>) {
+ // [x -> bool]
+ return builder.create<Element<TO>>(target_ty, !IsPositiveZero(value));
+ } else if constexpr (std::is_same_v<T, bool>) {
+ // [bool -> x]
+ return builder.create<Element<TO>>(target_ty, TO(value ? 1 : 0));
+ } else if (auto conv = CheckedConvert<TO>(value)) {
+ // Conversion success
+ return builder.create<Element<TO>>(target_ty, conv.Get());
+ // --- Below this point are the failure cases ---
+ } else if constexpr (std::is_same_v<T, AInt> || std::is_same_v<T, AFloat>) {
+ // [abstract-numeric -> x] - materialization failure
+ std::stringstream ss;
+ ss << "value " << value << " cannot be represented as ";
+ ss << "'" << builder.FriendlyName(target_ty) << "'";
+ builder.Diagnostics().add_error(tint::diag::System::Resolver, ss.str(), source);
+ failed = true;
+ } else if constexpr (IsFloatingPoint<UnwrapNumber<TO>>) {
+ // [x -> floating-point] - number not exactly representable
+ // https://www.w3.org/TR/WGSL/#floating-point-conversion
+ switch (conv.Failure()) {
+ case ConversionFailure::kExceedsNegativeLimit:
+ return builder.create<Element<TO>>(target_ty, -TO::Inf());
+ case ConversionFailure::kExceedsPositiveLimit:
+ return builder.create<Element<TO>>(target_ty, TO::Inf());
+ }
+ } else {
+ // [x -> integer] - number not exactly representable
+ // https://www.w3.org/TR/WGSL/#floating-point-conversion
+ switch (conv.Failure()) {
+ case ConversionFailure::kExceedsNegativeLimit:
+ return builder.create<Element<TO>>(target_ty, TO::Lowest());
+ case ConversionFailure::kExceedsPositiveLimit:
+ return builder.create<Element<TO>>(target_ty, TO::Highest());
+ }
+ }
+ return nullptr; // Expression is not constant.
+ });
+ if (failed) {
+ // A diagnostic error has been raised, and resolving should abort.
+ return utils::Failure;
+ }
+ return res;
+ TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
+ }
+
+ sem::Type const* const type;
+ const T value;
+};
+
+/// Splat holds a single Constant value, duplicated as all children.
+/// Splat is used for zero-initializers, 'splat' constructors, or constructors where each element is
+/// identical. Splat may be of a vector, matrix or array type.
+/// Splat implements the Constant interface.
+struct Splat : Constant {
+ Splat(const sem::Type* t, const sem::Constant* e, size_t n) : type(t), el(e), count(n) {}
+ ~Splat() override = default;
+ const sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override { return {}; }
+ const sem::Constant* Index(size_t i) const override { return i < count ? el : nullptr; }
+ bool AllZero() const override { return el->AllZero(); }
+ bool AnyZero() const override { return el->AnyZero(); }
+ bool AllEqual() const override { return true; }
+ size_t Hash() const override { return utils::Hash(type, el->Hash(), count); }
+
+ utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const override {
+ // Convert the single splatted element type.
+ // Note: This file is the only place where `sem::Constant`s are created, so this static_cast
+ // is safe.
+ auto conv_el = static_cast<const Constant*>(el)->Convert(
+ builder, sem::Type::ElementOf(target_ty), source);
+ if (!conv_el) {
+ return utils::Failure;
+ }
+ if (!conv_el.Get()) {
+ return nullptr;
+ }
+ return builder.create<Splat>(target_ty, conv_el.Get(), count);
+ }
+
+ sem::Type const* const type;
+ const sem::Constant* el;
+ const size_t count;
+};
+
+/// Composite holds a number of mixed child Constant values.
+/// Composite may be of a vector, matrix or array type.
+/// If each element is the same type and value, then a Splat would be a more efficient constant
+/// implementation. Use CreateComposite() to create the appropriate Constant type.
+/// Composite implements the Constant interface.
+struct Composite : Constant {
+ Composite(const sem::Type* t,
+ utils::VectorRef<const sem::Constant*> els,
+ bool all_0,
+ bool any_0)
+ : type(t), elements(std::move(els)), all_zero(all_0), any_zero(any_0), hash(CalcHash()) {}
+ ~Composite() override = default;
+ const sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override { return {}; }
+ const sem::Constant* Index(size_t i) const override {
+ return i < elements.Length() ? elements[i] : nullptr;
+ }
+ bool AllZero() const override { return all_zero; }
+ bool AnyZero() const override { return any_zero; }
+ bool AllEqual() const override { return false; /* otherwise this should be a Splat */ }
+ size_t Hash() const override { return hash; }
+
+ utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const override {
+ // Convert each of the composite element types.
+ auto* el_ty = sem::Type::ElementOf(target_ty);
+ utils::Vector<const sem::Constant*, 4> conv_els;
+ conv_els.Reserve(elements.Length());
+ for (auto* el : elements) {
+ // Note: This file is the only place where `sem::Constant`s are created, so this
+ // static_cast is safe.
+ auto conv_el = static_cast<const Constant*>(el)->Convert(builder, el_ty, source);
+ if (!conv_el) {
+ return utils::Failure;
+ }
+ if (!conv_el.Get()) {
+ return nullptr;
+ }
+ conv_els.Push(conv_el.Get());
+ }
+ return CreateComposite(builder, target_ty, std::move(conv_els));
+ }
+
+ size_t CalcHash() {
+ auto h = utils::Hash(type, all_zero, any_zero);
+ for (auto* el : elements) {
+ utils::HashCombine(&h, el->Hash());
+ }
+ return h;
+ }
+
+ sem::Type const* const type;
+ const utils::Vector<const sem::Constant*, 8> elements;
+ const bool all_zero;
+ const bool any_zero;
+ const size_t hash;
+};
+
+/// CreateElement constructs and returns an Element<T>.
+template <typename T>
+const Constant* CreateElement(ProgramBuilder& builder, const sem::Type* t, T v) {
+ return builder.create<Element<T>>(t, v);
+}
+
+/// ZeroValue returns a Constant for the zero-value of the type `type`.
+const Constant* ZeroValue(ProgramBuilder& builder, const sem::Type* type) {
+ return Switch(
+ type, //
+ [&](const sem::Vector* v) -> const Constant* {
+ auto* zero_el = ZeroValue(builder, v->type());
+ return builder.create<Splat>(type, zero_el, v->Width());
+ },
+ [&](const sem::Matrix* m) -> const Constant* {
+ auto* zero_el = ZeroValue(builder, m->ColumnType());
+ return builder.create<Splat>(type, zero_el, m->columns());
+ },
+ [&](const sem::Array* a) -> const Constant* {
+ if (auto* zero_el = ZeroValue(builder, a->ElemType())) {
+ return builder.create<Splat>(type, zero_el, a->Count());
+ }
+ return nullptr;
+ },
+ [&](const sem::Struct* s) -> const Constant* {
+ std::unordered_map<const sem::Type*, const Constant*> zero_by_type;
+ utils::Vector<const sem::Constant*, 4> zeros;
+ zeros.Reserve(s->Members().size());
+ for (auto* member : s->Members()) {
+ auto* zero = utils::GetOrCreate(zero_by_type, member->Type(),
+ [&] { return ZeroValue(builder, member->Type()); });
+ if (!zero) {
+ return nullptr;
+ }
+ zeros.Push(zero);
+ }
+ if (zero_by_type.size() == 1) {
+ // All members were of the same type, so the zero value is the same for all members.
+ return builder.create<Splat>(type, zeros[0], s->Members().size());
+ }
+ return CreateComposite(builder, s, std::move(zeros));
+ },
+ [&](Default) -> const Constant* {
+ return ZeroTypeDispatch(type, [&](auto zero) -> const Constant* {
+ return CreateElement(builder, type, zero);
+ });
+ });
+}
+
+/// Equal returns true if the constants `a` and `b` are of the same type and value.
+bool Equal(const sem::Constant* a, const sem::Constant* b) {
+ if (a->Hash() != b->Hash()) {
+ return false;
+ }
+ if (a->Type() != b->Type()) {
+ return false;
+ }
+ return Switch(
+ a->Type(), //
+ [&](const sem::Vector* vec) {
+ for (size_t i = 0; i < vec->Width(); i++) {
+ if (!Equal(a->Index(i), b->Index(i))) {
+ return false;
+ }
+ }
+ return true;
+ },
+ [&](const sem::Matrix* mat) {
+ for (size_t i = 0; i < mat->columns(); i++) {
+ if (!Equal(a->Index(i), b->Index(i))) {
+ return false;
+ }
+ }
+ return true;
+ },
+ [&](const sem::Array* arr) {
+ for (size_t i = 0; i < arr->Count(); i++) {
+ if (!Equal(a->Index(i), b->Index(i))) {
+ return false;
+ }
+ }
+ return true;
+ },
+ [&](Default) { return a->Value() == b->Value(); });
+}
+
+/// CreateComposite is used to construct a constant of a vector, matrix or array type.
+/// CreateComposite examines the element values and will return either a Composite or a Splat,
+/// depending on the element types and values.
+const Constant* CreateComposite(ProgramBuilder& builder,
+ const sem::Type* type,
+ utils::VectorRef<const sem::Constant*> elements) {
+ if (elements.IsEmpty()) {
+ return nullptr;
+ }
+ bool any_zero = false;
+ bool all_zero = true;
+ bool all_equal = true;
+ auto* first = elements.Front();
+ for (auto* el : elements) {
+ if (!el) {
+ return nullptr;
+ }
+ if (!any_zero && el->AnyZero()) {
+ any_zero = true;
+ }
+ if (all_zero && !el->AllZero()) {
+ all_zero = false;
+ }
+ if (all_equal && el != first) {
+ if (!Equal(el, first)) {
+ all_equal = false;
+ }
+ }
+ }
+ if (all_equal) {
+ return builder.create<Splat>(type, elements[0], elements.Length());
+ } else {
+ return builder.create<Composite>(type, std::move(elements), all_zero, any_zero);
+ }
+}
+
+/// TransformElements constructs a new constant by applying the transformation function 'f' on each
+/// of the most deeply nested elements of 'cs'. Assumes that all constants are the same type.
+template <typename F, typename... CONSTANTS>
+const Constant* TransformElements(ProgramBuilder& builder, F&& f, CONSTANTS&&... cs) {
+ uint32_t n = 0;
+ auto* ty = First(cs...)->Type();
+ auto* el_ty = sem::Type::ElementOf(ty, &n);
+ if (el_ty == ty) {
+ return f(cs...);
+ }
+ utils::Vector<const sem::Constant*, 8> els;
+ els.Reserve(n);
+ for (uint32_t i = 0; i < n; i++) {
+ els.Push(TransformElements(builder, std::forward<F>(f), cs->Index(i)...));
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+/// TransformBinaryElements constructs a new constant by applying the transformation function 'f' on
+/// each of the most deeply nested elements of both `c0` and `c1`. Unlike TransformElements, this
+/// function handles the constants being of different types, e.g. vector-scalar, scalar-vector.
+template <typename F>
+const Constant* TransformBinaryElements(ProgramBuilder& builder,
+ F&& f,
+ const sem::Constant* c0,
+ const sem::Constant* c1) {
+ uint32_t n0 = 0, n1 = 0;
+ sem::Type::ElementOf(c0->Type(), &n0);
+ sem::Type::ElementOf(c1->Type(), &n1);
+ uint32_t max_n = std::max(n0, n1);
+ // If arity of both constants is 1, invoke callback
+ if (max_n == 1u) {
+ return f(c0, c1);
+ }
+
+ utils::Vector<const sem::Constant*, 8> els;
+ els.Reserve(max_n);
+ for (uint32_t i = 0; i < max_n; i++) {
+ auto nested_or_self = [&](auto& c, uint32_t num_elems) {
+ if (num_elems == 1) {
+ return c;
+ }
+ return c->Index(i);
+ };
+ els.Push(TransformBinaryElements(builder, std::forward<F>(f), nested_or_self(c0, n0),
+ nested_or_self(c1, n1)));
+ }
+ // Use larger type
+ auto* ty = n0 > n1 ? c0->Type() : c1->Type();
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+} // namespace
+
+ConstEval::ConstEval(ProgramBuilder& b) : builder(b) {}
+
+ConstEval::ConstantResult ConstEval::Literal(const sem::Type* ty,
+ const ast::LiteralExpression* literal) {
+ return Switch(
+ literal,
+ [&](const ast::BoolLiteralExpression* lit) {
+ return CreateElement(builder, ty, lit->value);
+ },
+ [&](const ast::IntLiteralExpression* lit) -> const Constant* {
+ switch (lit->suffix) {
+ case ast::IntLiteralExpression::Suffix::kNone:
+ return CreateElement(builder, ty, AInt(lit->value));
+ case ast::IntLiteralExpression::Suffix::kI:
+ return CreateElement(builder, ty, i32(lit->value));
+ case ast::IntLiteralExpression::Suffix::kU:
+ return CreateElement(builder, ty, u32(lit->value));
+ }
+ return nullptr;
+ },
+ [&](const ast::FloatLiteralExpression* lit) -> const Constant* {
+ switch (lit->suffix) {
+ case ast::FloatLiteralExpression::Suffix::kNone:
+ return CreateElement(builder, ty, AFloat(lit->value));
+ case ast::FloatLiteralExpression::Suffix::kF:
+ return CreateElement(builder, ty, f32(lit->value));
+ case ast::FloatLiteralExpression::Suffix::kH:
+ return CreateElement(builder, ty, f16(lit->value));
+ }
+ return nullptr;
+ });
+}
+
+ConstEval::ConstantResult ConstEval::ArrayOrStructCtor(
+ const sem::Type* ty,
+ utils::VectorRef<const sem::Expression*> args) {
+ if (args.IsEmpty()) {
+ return ZeroValue(builder, ty);
+ }
+
+ if (args.Length() == 1 && args[0]->Type() == ty) {
+ // Identity constructor.
+ return args[0]->ConstantValue();
+ }
+
+ // Multiple arguments. Must be a type constructor.
+ utils::Vector<const sem::Constant*, 4> els;
+ els.Reserve(args.Length());
+ for (auto* arg : args) {
+ els.Push(arg->ConstantValue());
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+ConstEval::ConstantResult ConstEval::Conv(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source) {
+ uint32_t el_count = 0;
+ auto* el_ty = sem::Type::ElementOf(ty, &el_count);
+ if (!el_ty) {
+ return nullptr;
+ }
+
+ if (!args[0]) {
+ return nullptr; // Single argument is not constant.
+ }
+
+ if (auto conv = Convert(ty, args[0], source)) {
+ return conv.Get();
+ }
+
+ return nullptr;
+}
+
+ConstEval::ConstantResult ConstEval::Zero(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*>,
+ const Source&) {
+ return ZeroValue(builder, ty);
+}
+
+ConstEval::ConstantResult ConstEval::Identity(const sem::Type*,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ return args[0];
+}
+
+ConstEval::ConstantResult ConstEval::VecSplat(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ if (auto* arg = args[0]) {
+ return builder.create<Splat>(ty, arg, static_cast<const sem::Vector*>(ty)->Width());
+ }
+ return nullptr;
+}
+
+ConstEval::ConstantResult ConstEval::VecCtorS(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ return CreateComposite(builder, ty, args);
+}
+
+ConstEval::ConstantResult ConstEval::VecCtorM(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ utils::Vector<const sem::Constant*, 4> els;
+ for (auto* arg : args) {
+ auto* val = arg;
+ if (!val) {
+ return nullptr;
+ }
+ auto* arg_ty = arg->Type();
+ if (auto* arg_vec = arg_ty->As<sem::Vector>()) {
+ // Extract out vector elements.
+ for (uint32_t j = 0; j < arg_vec->Width(); j++) {
+ auto* el = val->Index(j);
+ if (!el) {
+ return nullptr;
+ }
+ els.Push(el);
+ }
+ } else {
+ els.Push(val);
+ }
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+ConstEval::ConstantResult ConstEval::MatCtorS(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto* m = static_cast<const sem::Matrix*>(ty);
+
+ utils::Vector<const sem::Constant*, 4> els;
+ for (uint32_t c = 0; c < m->columns(); c++) {
+ utils::Vector<const sem::Constant*, 4> column;
+ for (uint32_t r = 0; r < m->rows(); r++) {
+ auto i = r + c * m->rows();
+ column.Push(args[i]);
+ }
+ els.Push(CreateComposite(builder, m->ColumnType(), std::move(column)));
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+ConstEval::ConstantResult ConstEval::MatCtorV(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ return CreateComposite(builder, ty, args);
+}
+
+ConstEval::ConstantResult ConstEval::Index(const sem::Expression* obj_expr,
+ const sem::Expression* idx_expr) {
+ auto obj_val = obj_expr->ConstantValue();
+ if (!obj_val) {
+ return nullptr;
+ }
+
+ auto idx_val = idx_expr->ConstantValue();
+ if (!idx_val) {
+ return nullptr;
+ }
+
+ uint32_t el_count = 0;
+ sem::Type::ElementOf(obj_val->Type(), &el_count);
+
+ AInt idx = idx_val->As<AInt>();
+ if (idx < 0 || idx >= el_count) {
+ auto clamped = std::min<AInt::type>(std::max<AInt::type>(idx, 0), el_count - 1);
+ AddWarning("index " + std::to_string(idx) + " out of bounds [0.." +
+ std::to_string(el_count - 1) + "]. Clamping index to " +
+ std::to_string(clamped),
+ idx_expr->Declaration()->source);
+ idx = clamped;
+ }
+
+ return obj_val->Index(static_cast<size_t>(idx));
+}
+
+ConstEval::ConstantResult ConstEval::MemberAccess(const sem::Expression* obj_expr,
+ const sem::StructMember* member) {
+ auto obj_val = obj_expr->ConstantValue();
+ if (!obj_val) {
+ return nullptr;
+ }
+ return obj_val->Index(static_cast<size_t>(member->Index()));
+}
+
+ConstEval::ConstantResult ConstEval::Swizzle(const sem::Type* ty,
+ const sem::Expression* vec_expr,
+ utils::VectorRef<uint32_t> indices) {
+ auto* vec_val = vec_expr->ConstantValue();
+ if (!vec_val) {
+ return nullptr;
+ }
+ if (indices.Length() == 1) {
+ return vec_val->Index(static_cast<size_t>(indices[0]));
+ } else {
+ auto values = utils::Transform<4>(
+ indices, [&](uint32_t i) { return vec_val->Index(static_cast<size_t>(i)); });
+ return CreateComposite(builder, ty, std::move(values));
+ }
+}
+
+ConstEval::ConstantResult ConstEval::Bitcast(const sem::Type*, const sem::Expression*) {
+ // TODO(crbug.com/tint/1581): Implement @const intrinsics
+ return nullptr;
+}
+
+ConstEval::ConstantResult ConstEval::OpComplement(const sem::Type*,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto transform = [&](const sem::Constant* c) {
+ auto create = [&](auto i) {
+ return CreateElement(builder, c->Type(), decltype(i)(~i.value));
+ };
+ return Dispatch_ia_iu32(create, c);
+ };
+ return TransformElements(builder, transform, args[0]);
+}
+
+ConstEval::ConstantResult ConstEval::OpUnaryMinus(const sem::Type*,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto transform = [&](const sem::Constant* c) {
+ auto create = [&](auto i) {
+ // For signed integrals, avoid C++ UB by not negating the
+ // smallest negative number. In WGSL, this operation is well
+ // defined to return the same value, see:
+ // https://gpuweb.github.io/gpuweb/wgsl/#arithmetic-expr.
+ using T = UnwrapNumber<decltype(i)>;
+ if constexpr (std::is_integral_v<T>) {
+ auto v = i.value;
+ if (v != std::numeric_limits<T>::min()) {
+ v = -v;
+ }
+ return CreateElement(builder, c->Type(), decltype(i)(v));
+ } else {
+ return CreateElement(builder, c->Type(), decltype(i)(-i.value));
+ }
+ };
+ return Dispatch_fia_fi32_f16(create, c);
+ };
+ return TransformElements(builder, transform, args[0]);
+}
+
+ConstEval::ConstantResult ConstEval::OpPlus(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source) {
+ auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
+ auto create = [&](auto i, auto j) -> const Constant* {
+ using NumberT = decltype(i);
+ using T = UnwrapNumber<NumberT>;
+
+ auto add_values = [](T lhs, T rhs) {
+ if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
+ // Ensure no UB for signed overflow
+ using UT = std::make_unsigned_t<T>;
+ return static_cast<T>(static_cast<UT>(lhs) + static_cast<UT>(rhs));
+ } else {
+ return lhs + rhs;
+ }
+ };
+
+ NumberT result;
+ if constexpr (std::is_same_v<NumberT, AInt> || std::is_same_v<NumberT, AFloat>) {
+ // Check for over/underflow for abstract values
+ if (auto r = CheckedAdd(i, j)) {
+ result = r->value;
+ } else {
+ AddError("'" + std::to_string(add_values(i.value, j.value)) +
+ "' cannot be represented as '" +
+ ty->FriendlyName(builder.Symbols()) + "'",
+ source);
+ return nullptr;
+ }
+ } else {
+ result = add_values(i.value, j.value);
+ }
+ return CreateElement(builder, c0->Type(), result);
+ };
+ return Dispatch_fia_fiu32_f16(create, c0, c1);
+ };
+
+ auto r = TransformBinaryElements(builder, transform, args[0], args[1]);
+ if (builder.Diagnostics().contains_errors()) {
+ return utils::Failure;
+ }
+ return r;
+}
+
+ConstEval::ConstantResult ConstEval::OpMinus(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source) {
+ auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
+ auto create = [&](auto i, auto j) -> const Constant* {
+ using NumberT = decltype(i);
+ using T = UnwrapNumber<NumberT>;
+
+ auto subtract_values = [](T lhs, T rhs) {
+ if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
+ // Ensure no UB for signed underflow
+ using UT = std::make_unsigned_t<T>;
+ return static_cast<T>(static_cast<UT>(lhs) - static_cast<UT>(rhs));
+ } else {
+ return lhs - rhs;
+ }
+ };
+
+ NumberT result;
+ if constexpr (std::is_same_v<NumberT, AInt> || std::is_same_v<NumberT, AFloat>) {
+ // Check for over/underflow for abstract values
+ if (auto r = CheckedSub(i, j)) {
+ result = r->value;
+ } else {
+ AddError("'" + std::to_string(subtract_values(i.value, j.value)) +
+ "' cannot be represented as '" +
+ ty->FriendlyName(builder.Symbols()) + "'",
+ source);
+ return nullptr;
+ }
+ } else {
+ result = subtract_values(i.value, j.value);
+ }
+ return CreateElement(builder, c0->Type(), result);
+ };
+ return Dispatch_fia_fiu32_f16(create, c0, c1);
+ };
+
+ auto r = TransformBinaryElements(builder, transform, args[0], args[1]);
+ if (builder.Diagnostics().contains_errors()) {
+ return utils::Failure;
+ }
+ return r;
+}
+
+ConstEval::ConstantResult ConstEval::atan2(const sem::Type*,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
+ auto create = [&](auto i, auto j) {
+ return CreateElement(builder, c0->Type(), decltype(i)(std::atan2(i.value, j.value)));
+ };
+ return Dispatch_fa_f32_f16(create, c0, c1);
+ };
+ return TransformElements(builder, transform, args[0], args[1]);
+}
+
+ConstEval::ConstantResult ConstEval::clamp(const sem::Type*,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto transform = [&](const sem::Constant* c0, const sem::Constant* c1,
+ const sem::Constant* c2) {
+ auto create = [&](auto e, auto low, auto high) {
+ return CreateElement(builder, c0->Type(),
+ decltype(e)(std::min(std::max(e, low), high)));
+ };
+ return Dispatch_fia_fiu32_f16(create, c0, c1, c2);
+ };
+ return TransformElements(builder, transform, args[0], args[1], args[2]);
+}
+
+utils::Result<const sem::Constant*> ConstEval::Convert(const sem::Type* target_ty,
+ const sem::Constant* value,
+ const Source& source) {
+ if (value->Type() == target_ty) {
+ return value;
+ }
+ auto conv = static_cast<const Constant*>(value)->Convert(builder, target_ty, source);
+ if (!conv) {
+ return utils::Failure;
+ }
+ return conv.Get();
+}
+
+void ConstEval::AddError(const std::string& msg, const Source& source) const {
+ builder.Diagnostics().add_error(diag::System::Resolver, msg, source);
+}
+
+void ConstEval::AddWarning(const std::string& msg, const Source& source) const {
+ builder.Diagnostics().add_warning(diag::System::Resolver, msg, source);
+}
-namespace tint::resolver::const_eval {} // namespace tint::resolver::const_eval
+} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/const_eval.h b/chromium/third_party/dawn/src/tint/resolver/const_eval.h
index 89bb3da8de4..9cd38d7054b 100644
--- a/chromium/third_party/dawn/src/tint/resolver/const_eval.h
+++ b/chromium/third_party/dawn/src/tint/resolver/const_eval.h
@@ -16,22 +16,252 @@
#define SRC_TINT_RESOLVER_CONST_EVAL_H_
#include <stddef.h>
+#include <string>
+
+#include "src/tint/utils/result.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint {
class ProgramBuilder;
+class Source;
} // namespace tint
-
-// Forward declarations
+namespace tint::ast {
+class LiteralExpression;
+} // namespace tint::ast
namespace tint::sem {
class Constant;
+class Expression;
+class StructMember;
+class Type;
} // namespace tint::sem
-namespace tint::resolver::const_eval {
+namespace tint::resolver {
+
+/// ConstEval performs shader creation-time (constant expression) expression evaluation.
+/// Methods are called from the resolver, either directly or via member-function pointers indexed by
+/// the IntrinsicTable. All child-expression nodes are guaranteed to have been already resolved
+/// before calling a method to evaluate an expression's value.
+class ConstEval {
+ public:
+ /// The result type of a method that may raise a diagnostic error and the caller should abort
+ /// resolving. Can be one of three distinct values:
+ /// * A non-null sem::Constant pointer. Returned when a expression resolves to a creation time
+ /// value.
+ /// * A null sem::Constant pointer. Returned when a expression cannot resolve to a creation time
+ /// value, but is otherwise legal.
+ /// * `utils::Failure`. Returned when there was a resolver error. In this situation the method
+ /// will have already reported a diagnostic error message, and the caller should abort
+ /// resolving.
+ using ConstantResult = utils::Result<const sem::Constant*>;
+
+ /// Typedef for a constant evaluation function
+ using Function = ConstantResult (ConstEval::*)(const sem::Type* result_ty,
+ utils::VectorRef<const sem::Constant*>,
+ const Source&);
+
+ /// Constructor
+ /// @param b the program builder
+ explicit ConstEval(ProgramBuilder& b);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constant value evaluation methods, to be called directly from Resolver
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /// @param ty the target type - must be an array or constructor
+ /// @param args the input arguments
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult ArrayOrStructCtor(const sem::Type* ty,
+ utils::VectorRef<const sem::Expression*> args);
+
+ /// @param ty the target type
+ /// @param expr the input expression
+ /// @return the bit-cast of the given expression to the given type, or null if the value cannot
+ /// be calculated
+ ConstantResult Bitcast(const sem::Type* ty, const sem::Expression* expr);
+
+ /// @param obj the object being indexed
+ /// @param idx the index expression
+ /// @return the result of the index, or null if the value cannot be calculated
+ ConstantResult Index(const sem::Expression* obj, const sem::Expression* idx);
+
+ /// @param ty the result type
+ /// @param lit the literal AST node
+ /// @return the constant value of the literal
+ ConstantResult Literal(const sem::Type* ty, const ast::LiteralExpression* lit);
+
+ /// @param obj the object being accessed
+ /// @param member the member
+ /// @return the result of the member access, or null if the value cannot be calculated
+ ConstantResult MemberAccess(const sem::Expression* obj, const sem::StructMember* member);
+
+ /// @param ty the result type
+ /// @param vector the vector being swizzled
+ /// @param indices the swizzle indices
+ /// @return the result of the swizzle, or null if the value cannot be calculated
+ ConstantResult Swizzle(const sem::Type* ty,
+ const sem::Expression* vector,
+ utils::VectorRef<uint32_t> indices);
+
+ /// Convert the `value` to `target_type`
+ /// @param ty the result type
+ /// @param value the value being converted
+ /// @param source the source location of the conversion
+ /// @return the converted value, or null if the value cannot be calculated
+ ConstantResult Convert(const sem::Type* ty, const sem::Constant* value, const Source& source);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constant value evaluation methods, to be indirectly called via the intrinsic table
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /// Type conversion
+ /// @param ty the result type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the converted value, or null if the value cannot be calculated
+ ConstantResult Conv(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Zero value type constructor
+ /// @param ty the result type
+ /// @param args the input arguments (no arguments provided)
+ /// @param source the source location of the conversion
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult Zero(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Identity value type constructor
+ /// @param ty the result type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult Identity(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Vector splat constructor
+ /// @param ty the vector type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult VecSplat(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Vector constructor using scalars
+ /// @param ty the vector type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult VecCtorS(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Vector constructor using a mix of scalars and smaller vectors
+ /// @param ty the vector type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult VecCtorM(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Matrix constructor using scalar values
+ /// @param ty the matrix type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult MatCtorS(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Matrix constructor using column vectors
+ /// @param ty the matrix type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the constructed value, or null if the value cannot be calculated
+ ConstantResult MatCtorV(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////////////////
+
+ /// Complement operator '~'
+ /// @param ty the integer type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ ConstantResult OpComplement(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Unary minus operator '-'
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ ConstantResult OpUnaryMinus(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////////////////
+
+ /// Plus operator '+'
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ ConstantResult OpPlus(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// Minus operator '-'
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ ConstantResult OpMinus(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Builtins
+ ////////////////////////////////////////////////////////////////////////////
+
+ /// atan2 builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ ConstantResult atan2(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// clamp builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ ConstantResult clamp(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ private:
+ /// Adds the given error message to the diagnostics
+ void AddError(const std::string& msg, const Source& source) const;
+
+ /// Adds the given warning message to the diagnostics
+ void AddWarning(const std::string& msg, const Source& source) const;
-/// Typedef for a constant evaluation function
-using Function = sem::Constant(ProgramBuilder& builder, const sem::Constant* args, size_t num_args);
+ ProgramBuilder& builder;
+};
-} // namespace tint::resolver::const_eval
+} // namespace tint::resolver
#endif // SRC_TINT_RESOLVER_CONST_EVAL_H_
diff --git a/chromium/third_party/dawn/src/tint/resolver/const_eval_test.cc b/chromium/third_party/dawn/src/tint/resolver/const_eval_test.cc
new file mode 100644
index 00000000000..1509b5d3c1b
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/resolver/const_eval_test.cc
@@ -0,0 +1,3507 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cmath>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/builtin_type.h"
+#include "src/tint/sem/expression.h"
+#include "src/tint/sem/index_accessor_expression.h"
+#include "src/tint/sem/member_accessor_expression.h"
+#include "src/tint/sem/test_helper.h"
+#include "src/tint/utils/transform.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+template <typename T>
+const auto kPi = T(UnwrapNumber<T>(3.14159265358979323846));
+
+template <typename T>
+const auto kPiOver2 = T(UnwrapNumber<T>(1.57079632679489661923));
+
+template <typename T>
+const auto kPiOver4 = T(UnwrapNumber<T>(0.785398163397448309616));
+
+template <typename T>
+const auto k3PiOver4 = T(UnwrapNumber<T>(2.356194490192344928846));
+
+template <typename T>
+constexpr auto Negate(const Number<T>& v) {
+ if constexpr (std::is_integral_v<T>) {
+ if constexpr (std::is_signed_v<T>) {
+ // For signed integrals, avoid C++ UB by not negating the smallest negative number. In
+ // WGSL, this operation is well defined to return the same value, see:
+ // https://gpuweb.github.io/gpuweb/wgsl/#arithmetic-expr.
+ if (v == std::numeric_limits<T>::min()) {
+ return v;
+ }
+ return -v;
+
+ } else {
+ // Allow negating unsigned values
+ using ST = std::make_signed_t<T>;
+ auto as_signed = Number<ST>{static_cast<ST>(v)};
+ return Number<T>{static_cast<T>(Negate(as_signed))};
+ }
+ } else {
+ // float case
+ return -v;
+ }
+}
+
+template <typename T>
+auto Abs(const Number<T>& v) {
+ if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
+ return v;
+ } else {
+ return Number<T>(std::abs(v));
+ }
+}
+
+// Concats any number of std::vectors
+template <typename Vec, typename... Vecs>
+[[nodiscard]] auto Concat(Vec&& v1, Vecs&&... vs) {
+ auto total_size = v1.size() + (vs.size() + ...);
+ v1.reserve(total_size);
+ (std::move(vs.begin(), vs.end(), std::back_inserter(v1)), ...);
+ return std::move(v1);
+}
+
+using ResolverConstEvalTest = ResolverTest;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Construction
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST_F(ResolverConstEvalTest, Scalar_i32) {
+ auto* expr = Expr(99_i);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ EXPECT_TRUE(sem->Type()->Is<sem::I32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<AInt>(), 99);
+}
+
+TEST_F(ResolverConstEvalTest, Scalar_u32) {
+ auto* expr = Expr(99_u);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ EXPECT_TRUE(sem->Type()->Is<sem::U32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<AInt>(), 99u);
+}
+
+TEST_F(ResolverConstEvalTest, Scalar_f32) {
+ auto* expr = Expr(9.9_f);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ EXPECT_TRUE(sem->Type()->Is<sem::F32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<AFloat>().value, 9.9f);
+}
+
+TEST_F(ResolverConstEvalTest, Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = Expr(9.9_h);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ EXPECT_TRUE(sem->Type()->Is<sem::F16>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ // 9.9 is not exactly representable by f16, and should be quantized to 9.8984375
+ EXPECT_EQ(sem->ConstantValue()->As<AFloat>(), 9.8984375f);
+}
+
+TEST_F(ResolverConstEvalTest, Scalar_bool) {
+ auto* expr = Expr(true);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ EXPECT_TRUE(sem->Type()->Is<sem::Bool>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<bool>(), true);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_i32) {
+ auto* expr = vec3<i32>();
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 0);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 0);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 0);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_u32) {
+ auto* expr = vec3<u32>();
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::U32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 0u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 0u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 0u);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_f32) {
+ auto* expr = vec3<f32>();
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 0._a);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>();
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 0._a);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_bool) {
+ auto* expr = vec3<bool>();
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), false);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Splat_i32) {
+ auto* expr = vec3<i32>(99_i);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 99);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 99);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 99);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Splat_u32) {
+ auto* expr = vec3<u32>(99_u);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::U32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 99u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 99u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 99u);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Splat_f32) {
+ auto* expr = vec3<f32>(9.9_f);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 9.9f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 9.9f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 9.9f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Splat_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(9.9_h);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ // 9.9 is not exactly representable by f16, and should be quantized to 9.8984375
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 9.8984375f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 9.8984375f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 9.8984375f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Splat_bool) {
+ auto* expr = vec3<bool>(true);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_i32) {
+ auto* expr = vec3<i32>(1_i, 2_i, 3_i);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_u32) {
+ auto* expr = vec3<u32>(1_u, 2_u, 3_u);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::U32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_f32) {
+ auto* expr = vec3<f32>(1_f, 2_f, 3_f);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(1_h, 2_h, 3_h);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_bool) {
+ auto* expr = vec3<bool>(true, false, true);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_i32) {
+ auto* expr = vec3<i32>(1_i, vec2<i32>(2_i, 3_i));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_u32) {
+ auto* expr = vec3<u32>(vec2<u32>(1_u, 2_u), 3_u);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::U32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32) {
+ auto* expr = vec3<f32>(1_f, vec2<f32>(2_f, 3_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_all_10) {
+ auto* expr = vec3<f32>(10_f, vec2<f32>(10_f, 10_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 10_f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_all_positive_0) {
+ auto* expr = vec3<f32>(0_f, vec2<f32>(0_f, 0_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 0_f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_all_negative_0) {
+ auto* expr = vec3<f32>(vec2<f32>(-0_f, -0_f), -0_f);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), -0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), -0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), -0_f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_mixed_sign_0) {
+ auto* expr = vec3<f32>(0_f, vec2<f32>(-0_f, 0_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), -0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 0_f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_10) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(10_h, vec2<f16>(10_h, 10_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), 10_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), 10_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), 10_h);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_positive_0) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(0_h, vec2<f16>(0_h, 0_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), 0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), 0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), 0_h);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_negative_0) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(vec2<f16>(-0_h, -0_h), -0_h);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), -0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), -0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), -0_h);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_mixed_sign_0) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(0_h, vec2<f16>(-0_h, 0_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), 0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), -0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), 0_h);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_bool) {
+ auto* expr = vec3<bool>(vec2<bool>(true, false), true);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_all_true) {
+ auto* expr = vec3<bool>(true, vec2<bool>(true, true));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_all_false) {
+ auto* expr = vec3<bool>(false, vec2<bool>(false, false));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), false);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_f32_to_i32) {
+ auto* expr = vec3<i32>(vec3<f32>(1.1_f, 2.2_f, 3.3_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_u32_to_f32) {
+ auto* expr = vec3<f32>(vec3<u32>(10_u, 20_u, 30_u));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 10.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 20.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 30.f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_f16_to_i32) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<i32>(vec3<f16>(1.1_h, 2.2_h, 3.3_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3_i);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_u32_to_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(vec3<u32>(10_u, 20_u, 30_u));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 10.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 20.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 30.f);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_i32) {
+ auto* expr = vec3<i32>(vec3<f32>(1e10_f, -1e20_f, 1e30_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), i32::Highest());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), i32::Lowest());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), i32::Highest());
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_u32) {
+ auto* expr = vec3<u32>(vec3<f32>(1e10_f, -1e20_f, 1e30_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::U32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), u32::Highest());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), u32::Lowest());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), u32::Highest());
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(vec3<f32>(1e10_f, -1e20_f, 1e30_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ constexpr auto kInfinity = std::numeric_limits<double>::infinity();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), kInfinity);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), -kInfinity);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), kInfinity);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = vec3<f16>(vec3<f32>(1e-20_f, -2e-30_f, 3e-40_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 0.0);
+ EXPECT_FALSE(std::signbit(sem->ConstantValue()->Index(0)->As<AFloat>().value));
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), -0.0);
+ EXPECT_TRUE(std::signbit(sem->ConstantValue()->Index(1)->As<AFloat>().value));
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 0.0);
+ EXPECT_FALSE(std::signbit(sem->ConstantValue()->Index(2)->As<AFloat>().value));
+}
+
+TEST_F(ResolverConstEvalTest, Mat2x3_ZeroInit_f32) {
+ auto* expr = mat2x3<f32>();
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* mat = sem->Type()->As<sem::Matrix>();
+ ASSERT_NE(mat, nullptr);
+ EXPECT_TRUE(mat->type()->Is<sem::F32>());
+ EXPECT_EQ(mat->columns(), 2u);
+ EXPECT_EQ(mat->rows(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 0._f);
+}
+
+TEST_F(ResolverConstEvalTest, Mat2x3_ZeroInit_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = mat2x3<f16>();
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* mat = sem->Type()->As<sem::Matrix>();
+ ASSERT_NE(mat, nullptr);
+ EXPECT_TRUE(mat->type()->Is<sem::F16>());
+ EXPECT_EQ(mat->columns(), 2u);
+ EXPECT_EQ(mat->rows(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f16>(), 0._h);
+}
+
+TEST_F(ResolverConstEvalTest, Mat3x2_Construct_Scalars_af) {
+ auto* expr = Construct(ty.mat(nullptr, 3, 2), 1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* mat = sem->Type()->As<sem::Matrix>();
+ ASSERT_NE(mat, nullptr);
+ EXPECT_TRUE(mat->type()->Is<sem::F32>());
+ EXPECT_EQ(mat->columns(), 3u);
+ EXPECT_EQ(mat->rows(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<AFloat>(), 1._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<AFloat>(), 2._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<AFloat>(), 3._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<AFloat>(), 4._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(0)->As<AFloat>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(1)->As<AFloat>(), 6._a);
+}
+
+TEST_F(ResolverConstEvalTest, Mat3x2_Construct_Columns_af) {
+ auto* expr = Construct(ty.mat(nullptr, 3, 2), //
+ vec(nullptr, 2u, 1.0_a, 2.0_a), //
+ vec(nullptr, 2u, 3.0_a, 4.0_a), //
+ vec(nullptr, 2u, 5.0_a, 6.0_a));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* mat = sem->Type()->As<sem::Matrix>();
+ ASSERT_NE(mat, nullptr);
+ EXPECT_TRUE(mat->type()->Is<sem::F32>());
+ EXPECT_EQ(mat->columns(), 3u);
+ EXPECT_EQ(mat->rows(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<AFloat>(), 1._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<AFloat>(), 2._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<AFloat>(), 3._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<AFloat>(), 4._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(0)->As<AFloat>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(1)->As<AFloat>(), 6._a);
+}
+
+TEST_F(ResolverConstEvalTest, Array_i32_Zero) {
+ auto* expr = Construct(ty.array<i32, 4>());
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::I32>());
+ EXPECT_EQ(arr->Count(), 4u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<i32>(), 0_i);
+}
+
+TEST_F(ResolverConstEvalTest, Array_f32_Zero) {
+ auto* expr = Construct(ty.array<f32, 4>());
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::F32>());
+ EXPECT_EQ(arr->Count(), 4u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<f32>(), 0_f);
+}
+
+TEST_F(ResolverConstEvalTest, Array_vec3_f32_Zero) {
+ auto* expr = Construct(ty.array(ty.vec3<f32>(), 2_u));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::Vector>());
+ EXPECT_EQ(arr->Count(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 0_f);
+}
+
+TEST_F(ResolverConstEvalTest, Array_Struct_f32_Zero) {
+ Structure("S", utils::Vector{
+ Member("m1", ty.f32()),
+ Member("m2", ty.f32()),
+ });
+ auto* expr = Construct(ty.array(ty.type_name("S"), 2_u));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::Struct>());
+ EXPECT_EQ(arr->Count(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 0_f);
+}
+
+TEST_F(ResolverConstEvalTest, Array_i32_Elements) {
+ auto* expr = Construct(ty.array<i32, 4>(), 10_i, 20_i, 30_i, 40_i);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::I32>());
+ EXPECT_EQ(arr->Count(), 4u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<i32>(), 10_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<i32>(), 20_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<i32>(), 30_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<i32>(), 40_i);
+}
+
+TEST_F(ResolverConstEvalTest, Array_f32_Elements) {
+ auto* expr = Construct(ty.array<f32, 4>(), 10_f, 20_f, 30_f, 40_f);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::F32>());
+ EXPECT_EQ(arr->Count(), 4u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 20_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 30_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<f32>(), 40_f);
+}
+
+TEST_F(ResolverConstEvalTest, Array_vec3_f32_Elements) {
+ auto* expr = Construct(ty.array(ty.vec3<f32>(), 2_u), //
+ vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::Vector>());
+ EXPECT_EQ(arr->Count(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 1_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 2_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 3_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 4_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 5_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 6_f);
+}
+
+TEST_F(ResolverConstEvalTest, Array_Struct_f32_Elements) {
+ Structure("S", utils::Vector{
+ Member("m1", ty.f32()),
+ Member("m2", ty.f32()),
+ });
+ auto* expr = Construct(ty.array(ty.type_name("S"), 2_u), //
+ Construct(ty.type_name("S"), 1_f, 2_f), //
+ Construct(ty.type_name("S"), 3_f, 4_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* arr = sem->Type()->As<sem::Array>();
+ ASSERT_NE(arr, nullptr);
+ EXPECT_TRUE(arr->ElemType()->Is<sem::Struct>());
+ EXPECT_EQ(arr->Count(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 1_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 2_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 3_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 4_f);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_I32s_ZeroInit) {
+ Structure(
+ "S", utils::Vector{Member("m1", ty.i32()), Member("m2", ty.i32()), Member("m3", ty.i32())});
+ auto* expr = Construct(ty.type_name("S"));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 3u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::I32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::I32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->Is<sem::I32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<i32>(), 0_i);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_MixedScalars_ZeroInit) {
+ Enable(ast::Extension::kF16);
+
+ Structure("S", utils::Vector{
+ Member("m1", ty.i32()),
+ Member("m2", ty.u32()),
+ Member("m3", ty.f32()),
+ Member("m4", ty.f16()),
+ Member("m5", ty.bool_()),
+ });
+ auto* expr = Construct(ty.type_name("S"));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 5u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::I32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::U32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<u32>(), 0_u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->Is<sem::F32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->Type()->Is<sem::F16>());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->Type()->Is<sem::Bool>());
+ EXPECT_EQ(sem->ConstantValue()->Index(4)->As<bool>(), false);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_VectorF32s_ZeroInit) {
+ Structure("S", utils::Vector{
+ Member("m1", ty.vec3<f32>()),
+ Member("m2", ty.vec3<f32>()),
+ Member("m3", ty.vec3<f32>()),
+ });
+ auto* expr = Construct(ty.type_name("S"));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 3u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(0)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(1)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(2)->As<f32>(), 0._f);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_MixedVectors_ZeroInit) {
+ Enable(ast::Extension::kF16);
+
+ Structure("S", utils::Vector{
+ Member("m1", ty.vec2<i32>()),
+ Member("m2", ty.vec3<u32>()),
+ Member("m3", ty.vec4<f32>()),
+ Member("m4", ty.vec3<f16>()),
+ Member("m5", ty.vec2<bool>()),
+ });
+ auto* expr = Construct(ty.type_name("S"));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 5u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<i32>(), 0_i);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<u32>(), 0_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<u32>(), 0_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<u32>(), 0_u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(0)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(1)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(2)->As<f32>(), 0._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(3)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->Type()->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->Index(0)->As<f16>(), 0._h);
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->Index(1)->As<f16>(), 0._h);
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->Index(2)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_EQ(sem->ConstantValue()->Index(4)->Index(0)->As<bool>(), false);
+ EXPECT_EQ(sem->ConstantValue()->Index(4)->Index(1)->As<bool>(), false);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_Struct_ZeroInit) {
+ Structure("Inner", utils::Vector{
+ Member("m1", ty.i32()),
+ Member("m2", ty.u32()),
+ Member("m3", ty.f32()),
+ });
+
+ Structure("Outer", utils::Vector{
+ Member("m1", ty.type_name("Inner")),
+ Member("m2", ty.type_name("Inner")),
+ });
+ auto* expr = Construct(ty.type_name("Outer"));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 2u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Struct>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<i32>(), 0_i);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<u32>(), 0_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 0_f);
+
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Struct>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<i32>(), 0_i);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<u32>(), 0_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 0_f);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_MixedScalars_Construct) {
+ Enable(ast::Extension::kF16);
+
+ Structure("S", utils::Vector{
+ Member("m1", ty.i32()),
+ Member("m2", ty.u32()),
+ Member("m3", ty.f32()),
+ Member("m4", ty.f16()),
+ Member("m5", ty.bool_()),
+ });
+ auto* expr = Construct(ty.type_name("S"), 1_i, 2_u, 3_f, 4_h, false);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 5u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::I32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<i32>(), 1_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::U32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<u32>(), 2_u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->Is<sem::F32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 3._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->Type()->Is<sem::F16>());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<f16>(), 4._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->Type()->Is<sem::Bool>());
+ EXPECT_EQ(sem->ConstantValue()->Index(4)->As<bool>(), false);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_MixedVectors_Construct) {
+ Enable(ast::Extension::kF16);
+
+ Structure("S", utils::Vector{
+ Member("m1", ty.vec2<i32>()),
+ Member("m2", ty.vec3<u32>()),
+ Member("m3", ty.vec4<f32>()),
+ Member("m4", ty.vec3<f16>()),
+ Member("m5", ty.vec2<bool>()),
+ });
+ auto* expr = Construct(ty.type_name("S"), vec2<i32>(1_i), vec3<u32>(2_u), vec4<f32>(3_f),
+ vec3<f16>(4_h), vec2<bool>(false));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 5u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<i32>(), 1_i);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<i32>(), 1_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<u32>(), 2_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<u32>(), 2_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<u32>(), 2_u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(0)->As<f32>(), 3._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(1)->As<f32>(), 3._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(2)->As<f32>(), 3._f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(3)->As<f32>(), 3._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->Type()->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->Index(0)->As<f16>(), 4._h);
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->Index(1)->As<f16>(), 4._h);
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->Index(2)->As<f16>(), 4._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(4)->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_EQ(sem->ConstantValue()->Index(4)->Index(0)->As<bool>(), false);
+ EXPECT_EQ(sem->ConstantValue()->Index(4)->Index(1)->As<bool>(), false);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_Struct_Construct) {
+ Structure("Inner", utils::Vector{
+ Member("m1", ty.i32()),
+ Member("m2", ty.u32()),
+ Member("m3", ty.f32()),
+ });
+
+ Structure("Outer", utils::Vector{
+ Member("m1", ty.type_name("Inner")),
+ Member("m2", ty.type_name("Inner")),
+ });
+ auto* expr = Construct(ty.type_name("Outer"), //
+ Construct(ty.type_name("Inner"), 1_i, 2_u, 3_f),
+ Construct(ty.type_name("Inner"), 4_i, 0_u, 6_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 2u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Struct>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<i32>(), 1_i);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<u32>(), 2_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 3_f);
+
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Struct>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<i32>(), 4_i);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<u32>(), 0_u);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 6_f);
+}
+
+TEST_F(ResolverConstEvalTest, Struct_Array_Construct) {
+ Structure("S", utils::Vector{
+ Member("m1", ty.array<i32, 2>()),
+ Member("m2", ty.array<f32, 3>()),
+ });
+ auto* expr = Construct(ty.type_name("S"), //
+ Construct(ty.array<i32, 2>(), 1_i, 2_i),
+ Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* str = sem->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 2u);
+ ASSERT_NE(sem->ConstantValue(), nullptr);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Array>());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<i32>(), 1_i);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<u32>(), 2_i);
+
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Array>());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<i32>(), 1_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<u32>(), 2_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 3_f);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Indexing
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST_F(ResolverConstEvalTest, Vec3_Index) {
+ auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), 2_i);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ ASSERT_TRUE(sem->Type()->Is<sem::I32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 3_i);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Index_OOB_High) {
+ auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, 3_i));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 warning: index 3 out of bounds [0..2]. Clamping index to 2");
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ ASSERT_TRUE(sem->Type()->Is<sem::I32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 3_i);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Index_OOB_Low) {
+ auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, -3_i));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 warning: index -3 out of bounds [0..2]. Clamping index to 0");
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ ASSERT_TRUE(sem->Type()->Is<sem::I32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 1_i);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Swizzle_Scalar) {
+ auto* expr = MemberAccessor(vec3<i32>(1_i, 2_i, 3_i), "y");
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ ASSERT_TRUE(sem->Type()->Is<sem::I32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 2_i);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Swizzle_Vector) {
+ auto* expr = MemberAccessor(vec3<i32>(1_i, 2_i, 3_i), "zx");
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_EQ(vec->Width(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 3._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 1._a);
+}
+
+TEST_F(ResolverConstEvalTest, Vec3_Swizzle_Chain) {
+ auto* expr = // (1, 2, 3) -> (2, 3, 1) -> (3, 2) -> 2
+ MemberAccessor(MemberAccessor(MemberAccessor(vec3<i32>(1_i, 2_i, 3_i), "gbr"), "yx"), "y");
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ ASSERT_TRUE(sem->Type()->Is<sem::I32>());
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 2_i);
+}
+
+TEST_F(ResolverConstEvalTest, Mat3x2_Index) {
+ auto* expr = IndexAccessor(
+ mat3x2<f32>(vec2<f32>(1._a, 2._a), vec2<f32>(3._a, 4._a), vec2<f32>(5._a, 6._a)), 2_i);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_EQ(vec->Width(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 6._a);
+}
+
+TEST_F(ResolverConstEvalTest, Mat3x2_Index_OOB_High) {
+ auto* expr = IndexAccessor(
+ mat3x2<f32>(vec2<f32>(1._a, 2._a), vec2<f32>(3._a, 4._a), vec2<f32>(5._a, 6._a)),
+ Expr(Source{{12, 34}}, 3_i));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 warning: index 3 out of bounds [0..2]. Clamping index to 2");
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_EQ(vec->Width(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 6._a);
+}
+
+TEST_F(ResolverConstEvalTest, Mat3x2_Index_OOB_Low) {
+ auto* expr = IndexAccessor(
+ mat3x2<f32>(vec2<f32>(1._a, 2._a), vec2<f32>(3._a, 4._a), vec2<f32>(5._a, 6._a)),
+ Expr(Source{{12, 34}}, -3_i));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 warning: index -3 out of bounds [0..2]. Clamping index to 0");
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_EQ(vec->Width(), 2u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 1._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 2._a);
+}
+
+TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index) {
+ auto* expr = IndexAccessor(Construct(ty.array(ty.vec3<f32>(), 2_u), //
+ vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f)),
+ 1_i);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 4_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 5_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 6_f);
+}
+
+TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_High) {
+ auto* expr = IndexAccessor(Construct(ty.array(ty.vec3<f32>(), 2_u), //
+ vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f)),
+ Expr(Source{{12, 34}}, 2_i));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 warning: index 2 out of bounds [0..1]. Clamping index to 1");
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 4_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 5_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 6_f);
+}
+
+TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_Low) {
+ auto* expr = IndexAccessor(Construct(ty.array(ty.vec3<f32>(), 2_u), //
+ vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f)),
+ Expr(Source{{12, 34}}, -2_i));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 warning: index -2 out of bounds [0..1]. Clamping index to 0");
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 1_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 2_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 3_f);
+}
+
+TEST_F(ResolverConstEvalTest, ChainedIndex) {
+ auto* arr_expr = Construct(ty.array(ty.mat2x3<f32>(), 2_u), // array<mat2x3<f32>, 2u>
+ mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), //
+ vec3<f32>(4_f, 5_f, 6_f)), //
+ mat2x3<f32>(vec3<f32>(7_f, 0_f, 9_f), //
+ vec3<f32>(10_f, 11_f, 12_f)));
+
+ auto* mat_expr = IndexAccessor(arr_expr, 1_i); // arr[1]
+ auto* vec_expr = IndexAccessor(mat_expr, 0_i); // arr[1][0]
+ auto* f32_expr = IndexAccessor(vec_expr, 2_i); // arr[1][0][2]
+ WrapInFunction(f32_expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ {
+ auto* mat = Sem().Get(mat_expr);
+ EXPECT_NE(mat, nullptr);
+ auto* ty = mat->Type()->As<sem::Matrix>();
+ ASSERT_NE(mat->Type(), nullptr);
+ EXPECT_TRUE(ty->ColumnType()->Is<sem::Vector>());
+ EXPECT_EQ(ty->columns(), 2u);
+ EXPECT_EQ(ty->rows(), 3u);
+ EXPECT_EQ(mat->ConstantValue()->Type(), mat->Type());
+ EXPECT_FALSE(mat->ConstantValue()->AllEqual());
+ EXPECT_TRUE(mat->ConstantValue()->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(0)->As<f32>(), 7_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(2)->As<f32>(), 9_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(0)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(1)->As<f32>(), 11_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(2)->As<f32>(), 12_f);
+ }
+ {
+ auto* vec = Sem().Get(vec_expr);
+ EXPECT_NE(vec, nullptr);
+ auto* ty = vec->Type()->As<sem::Vector>();
+ ASSERT_NE(vec->Type(), nullptr);
+ EXPECT_TRUE(ty->type()->Is<sem::F32>());
+ EXPECT_EQ(ty->Width(), 3u);
+ EXPECT_EQ(vec->ConstantValue()->Type(), vec->Type());
+ EXPECT_FALSE(vec->ConstantValue()->AllEqual());
+ EXPECT_TRUE(vec->ConstantValue()->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(0)->As<f32>(), 7_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(2)->As<f32>(), 9_f);
+ }
+ {
+ auto* f = Sem().Get(f32_expr);
+ EXPECT_NE(f, nullptr);
+ EXPECT_TRUE(f->Type()->Is<sem::F32>());
+ EXPECT_EQ(f->ConstantValue()->Type(), f->Type());
+ EXPECT_TRUE(f->ConstantValue()->AllEqual());
+ EXPECT_FALSE(f->ConstantValue()->AnyZero());
+ EXPECT_FALSE(f->ConstantValue()->AllZero());
+ EXPECT_EQ(f->ConstantValue()->As<f32>(), 9_f);
+ }
+}
+
+TEST_F(ResolverConstEvalTest, ChainedIndex_OOB) {
+ auto* arr_expr = Construct(ty.array(ty.mat2x3<f32>(), 2_u), // array<mat2x3<f32>, 2u>
+ mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), //
+ vec3<f32>(4_f, 5_f, 6_f)), //
+ mat2x3<f32>(vec3<f32>(7_f, 8_f, 9_f), //
+ vec3<f32>(10_f, 11_f, 12_f)));
+
+ auto* mat_expr = IndexAccessor(arr_expr, Expr(Source{{1, 2}}, -3_i)); // arr[3]
+ auto* vec_expr = IndexAccessor(mat_expr, Expr(Source{{3, 4}}, -2_i)); // arr[3][-2]
+ auto* f32_expr = IndexAccessor(vec_expr, Expr(Source{{5, 6}}, 4_i)); // arr[3][-2][4]
+ WrapInFunction(f32_expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), R"(1:2 warning: index -3 out of bounds [0..1]. Clamping index to 0
+3:4 warning: index -2 out of bounds [0..1]. Clamping index to 0
+5:6 warning: index 4 out of bounds [0..2]. Clamping index to 2)");
+
+ {
+ auto* mat = Sem().Get(mat_expr);
+ EXPECT_NE(mat, nullptr);
+ auto* ty = mat->Type()->As<sem::Matrix>();
+ ASSERT_NE(mat->Type(), nullptr);
+ EXPECT_TRUE(ty->ColumnType()->Is<sem::Vector>());
+ EXPECT_EQ(ty->columns(), 2u);
+ EXPECT_EQ(ty->rows(), 3u);
+ EXPECT_EQ(mat->ConstantValue()->Type(), mat->Type());
+ EXPECT_FALSE(mat->ConstantValue()->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(0)->As<f32>(), 1_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(1)->As<f32>(), 2_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(2)->As<f32>(), 3_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(0)->As<f32>(), 4_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(1)->As<f32>(), 5_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(2)->As<f32>(), 6_f);
+ }
+ {
+ auto* vec = Sem().Get(vec_expr);
+ EXPECT_NE(vec, nullptr);
+ auto* ty = vec->Type()->As<sem::Vector>();
+ ASSERT_NE(vec->Type(), nullptr);
+ EXPECT_TRUE(ty->type()->Is<sem::F32>());
+ EXPECT_EQ(ty->Width(), 3u);
+ EXPECT_EQ(vec->ConstantValue()->Type(), vec->Type());
+ EXPECT_FALSE(vec->ConstantValue()->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(0)->As<f32>(), 1_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(1)->As<f32>(), 2_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(2)->As<f32>(), 3_f);
+ }
+ {
+ auto* f = Sem().Get(f32_expr);
+ EXPECT_NE(f, nullptr);
+ EXPECT_TRUE(f->Type()->Is<sem::F32>());
+ EXPECT_EQ(f->ConstantValue()->Type(), f->Type());
+ EXPECT_TRUE(f->ConstantValue()->AllEqual());
+ EXPECT_FALSE(f->ConstantValue()->AnyZero());
+ EXPECT_FALSE(f->ConstantValue()->AllZero());
+ EXPECT_EQ(f->ConstantValue()->As<f32>(), 3_f);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Member accessing
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST_F(ResolverConstEvalTest, MemberAccess) {
+ Structure("Inner", utils::Vector{
+ Member("i1", ty.i32()),
+ Member("i2", ty.u32()),
+ Member("i3", ty.f32()),
+ });
+
+ Structure("Outer", utils::Vector{
+ Member("o1", ty.type_name("Inner")),
+ Member("o2", ty.type_name("Inner")),
+ });
+ auto* outer_expr = Construct(ty.type_name("Outer"), //
+ Construct(ty.type_name("Inner"), 1_i, 2_u, 3_f),
+ Construct(ty.type_name("Inner")));
+ auto* o1_expr = MemberAccessor(outer_expr, "o1");
+ auto* i2_expr = MemberAccessor(o1_expr, "i2");
+ WrapInFunction(i2_expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* outer = Sem().Get(outer_expr);
+ ASSERT_NE(outer, nullptr);
+ auto* str = outer->Type()->As<sem::Struct>();
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Members().size(), 2u);
+ ASSERT_NE(outer->ConstantValue(), nullptr);
+ EXPECT_TYPE(outer->ConstantValue()->Type(), outer->Type());
+ EXPECT_FALSE(outer->ConstantValue()->AllEqual());
+ EXPECT_TRUE(outer->ConstantValue()->AnyZero());
+ EXPECT_FALSE(outer->ConstantValue()->AllZero());
+
+ auto* o1 = Sem().Get(o1_expr);
+ ASSERT_NE(o1->ConstantValue(), nullptr);
+ EXPECT_FALSE(o1->ConstantValue()->AllEqual());
+ EXPECT_FALSE(o1->ConstantValue()->AnyZero());
+ EXPECT_FALSE(o1->ConstantValue()->AllZero());
+ EXPECT_TRUE(o1->ConstantValue()->Type()->Is<sem::Struct>());
+ EXPECT_EQ(o1->ConstantValue()->Index(0)->As<i32>(), 1_i);
+ EXPECT_EQ(o1->ConstantValue()->Index(1)->As<u32>(), 2_u);
+ EXPECT_EQ(o1->ConstantValue()->Index(2)->As<f32>(), 3_f);
+
+ auto* i2 = Sem().Get(i2_expr);
+ ASSERT_NE(i2->ConstantValue(), nullptr);
+ EXPECT_TRUE(i2->ConstantValue()->AllEqual());
+ EXPECT_FALSE(i2->ConstantValue()->AnyZero());
+ EXPECT_FALSE(i2->ConstantValue()->AllZero());
+ EXPECT_TRUE(i2->ConstantValue()->Type()->Is<sem::U32>());
+ EXPECT_EQ(i2->ConstantValue()->As<u32>(), 2_u);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Unary op
+////////////////////////////////////////////////////////////////////////////////////////////////////
+namespace unary_op {
+
+template <typename T>
+struct Values {
+ T input;
+ T expect;
+};
+
+struct Case {
+ std::variant<Values<AInt>, Values<AFloat>, Values<u32>, Values<i32>, Values<f32>, Values<f16>>
+ values;
+};
+
+static std::ostream& operator<<(std::ostream& o, const Case& c) {
+ std::visit([&](auto&& v) { o << v.input; }, c.values);
+ return o;
+}
+
+template <typename T>
+Case C(T input, T expect) {
+ return Case{Values<T>{input, expect}};
+}
+
+using ResolverConstEvalUnaryOpTest = ResolverTestWithParam<std::tuple<ast::UnaryOp, Case>>;
+
+TEST_P(ResolverConstEvalUnaryOpTest, Test) {
+ Enable(ast::Extension::kF16);
+
+ auto op = std::get<0>(GetParam());
+ auto c = std::get<1>(GetParam());
+ std::visit(
+ [&](auto&& values) {
+ using T = decltype(values.expect);
+ auto* expr = create<ast::UnaryOpExpression>(op, Expr(values.input));
+ GlobalConst("C", nullptr, expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ const sem::Constant* value = sem->ConstantValue();
+ ASSERT_NE(value, nullptr);
+ EXPECT_TYPE(value->Type(), sem->Type());
+ EXPECT_EQ(value->As<T>(), values.expect);
+
+ if constexpr (IsInteger<UnwrapNumber<T>>) {
+ // Check that the constant's integer doesn't contain unexpected data in the MSBs
+ // that are outside of the bit-width of T.
+ EXPECT_EQ(value->As<AInt>(), AInt(values.expect));
+ }
+ },
+ c.values);
+}
+INSTANTIATE_TEST_SUITE_P(Complement,
+ ResolverConstEvalUnaryOpTest,
+ testing::Combine(testing::Values(ast::UnaryOp::kComplement),
+ testing::ValuesIn({
+ // AInt
+ C(0_a, 0xffffffffffffffff_a),
+ C(0xffffffffffffffff_a, 0_a),
+ C(0xf0f0f0f0f0f0f0f0_a, 0x0f0f0f0f0f0f0f0f_a),
+ C(0xaaaaaaaaaaaaaaaa_a, 0x5555555555555555_a),
+ C(0x5555555555555555_a, 0xaaaaaaaaaaaaaaaa_a),
+ // u32
+ C(0_u, 0xffffffff_u),
+ C(0xffffffff_u, 0_u),
+ C(0xf0f0f0f0_u, 0x0f0f0f0f_u),
+ C(0xaaaaaaaa_u, 0x55555555_u),
+ C(0x55555555_u, 0xaaaaaaaa_u),
+ // i32
+ C(0_i, -1_i),
+ C(-1_i, 0_i),
+ C(1_i, -2_i),
+ C(-2_i, 1_i),
+ C(2_i, -3_i),
+ C(-3_i, 2_i),
+ })));
+
+INSTANTIATE_TEST_SUITE_P(Negation,
+ ResolverConstEvalUnaryOpTest,
+ testing::Combine(testing::Values(ast::UnaryOp::kNegation),
+ testing::ValuesIn({
+ // AInt
+ C(0_a, -0_a),
+ C(-0_a, 0_a),
+ C(1_a, -1_a),
+ C(-1_a, 1_a),
+ C(AInt::Highest(), -AInt::Highest()),
+ C(-AInt::Highest(), AInt::Highest()),
+ C(AInt::Lowest(), Negate(AInt::Lowest())),
+ C(Negate(AInt::Lowest()), AInt::Lowest()),
+ // i32
+ C(0_i, -0_i),
+ C(-0_i, 0_i),
+ C(1_i, -1_i),
+ C(-1_i, 1_i),
+ C(i32::Highest(), -i32::Highest()),
+ C(-i32::Highest(), i32::Highest()),
+ C(i32::Lowest(), Negate(i32::Lowest())),
+ C(Negate(i32::Lowest()), i32::Lowest()),
+ // AFloat
+ C(0.0_a, -0.0_a),
+ C(-0.0_a, 0.0_a),
+ C(1.0_a, -1.0_a),
+ C(-1.0_a, 1.0_a),
+ C(AFloat::Highest(), -AFloat::Highest()),
+ C(-AFloat::Highest(), AFloat::Highest()),
+ C(AFloat::Lowest(), Negate(AFloat::Lowest())),
+ C(Negate(AFloat::Lowest()), AFloat::Lowest()),
+ // f32
+ C(0.0_f, -0.0_f),
+ C(-0.0_f, 0.0_f),
+ C(1.0_f, -1.0_f),
+ C(-1.0_f, 1.0_f),
+ C(f32::Highest(), -f32::Highest()),
+ C(-f32::Highest(), f32::Highest()),
+ C(f32::Lowest(), Negate(f32::Lowest())),
+ C(Negate(f32::Lowest()), f32::Lowest()),
+ // f16
+ C(0.0_h, -0.0_h),
+ C(-0.0_h, 0.0_h),
+ C(1.0_h, -1.0_h),
+ C(-1.0_h, 1.0_h),
+ C(f16::Highest(), -f16::Highest()),
+ C(-f16::Highest(), f16::Highest()),
+ C(f16::Lowest(), Negate(f16::Lowest())),
+ C(Negate(f16::Lowest()), f16::Lowest()),
+ })));
+
+// Make sure UBSan doesn't trip on C++'s undefined behaviour of negating the smallest negative
+// number.
+TEST_F(ResolverConstEvalTest, UnaryNegateLowestAbstract) {
+ // const break_me = -(-9223372036854775808);
+ auto* c = GlobalConst("break_me", nullptr, Negation(Negation(Expr(9223372036854775808_a))));
+ (void)c;
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ auto* sem = Sem().Get(c);
+ EXPECT_EQ(sem->ConstantValue()->As<AInt>(), 9223372036854775808_a);
+}
+
+} // namespace unary_op
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Binary op
+////////////////////////////////////////////////////////////////////////////////////////////////////
+namespace binary_op {
+
+using Types = std::variant<AInt, AFloat, u32, i32, f32, f16>;
+
+struct Case {
+ Types lhs;
+ Types rhs;
+ Types expected;
+ bool is_overflow;
+};
+
+static std::ostream& operator<<(std::ostream& o, const Case& c) {
+ std::visit(
+ [&](auto&& lhs, auto&& rhs, auto&& expected) {
+ o << "lhs: " << lhs << ", rhs: " << rhs << ", expected: " << expected;
+ },
+ c.lhs, c.rhs, c.expected);
+ return o;
+}
+
+template <typename T, typename U, typename V>
+Case C(T lhs, U rhs, V expected, bool is_overflow = false) {
+ return Case{lhs, rhs, expected, is_overflow};
+}
+
+using ResolverConstEvalBinaryOpTest = ResolverTestWithParam<std::tuple<ast::BinaryOp, Case>>;
+TEST_P(ResolverConstEvalBinaryOpTest, Test) {
+ Enable(ast::Extension::kF16);
+
+ auto op = std::get<0>(GetParam());
+ auto c = std::get<1>(GetParam());
+ std::visit(
+ [&](auto&& lhs, auto&& rhs, auto&& expected) {
+ using T = std::decay_t<decltype(expected)>;
+
+ if constexpr (std::is_same_v<T, AInt> || std::is_same_v<T, AFloat>) {
+ if (c.is_overflow) {
+ return;
+ }
+ }
+
+ auto* expr = create<ast::BinaryExpression>(op, Expr(lhs), Expr(rhs));
+ GlobalConst("C", nullptr, expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ const sem::Constant* value = sem->ConstantValue();
+ ASSERT_NE(value, nullptr);
+ EXPECT_TYPE(value->Type(), sem->Type());
+ EXPECT_EQ(value->As<T>(), expected);
+
+ if constexpr (IsInteger<UnwrapNumber<T>>) {
+ // Check that the constant's integer doesn't contain unexpected data in the MSBs
+ // that are outside of the bit-width of T.
+ EXPECT_EQ(value->As<AInt>(), AInt(expected));
+ }
+ },
+ c.lhs, c.rhs, c.expected);
+}
+
+INSTANTIATE_TEST_SUITE_P(MixedAbstractArgs,
+ ResolverConstEvalBinaryOpTest,
+ testing::Combine(testing::Values(ast::BinaryOp::kAdd),
+ testing::ValuesIn(std::vector{
+ // Mixed abstract type args
+ C(1_a, 2.3_a, 3.3_a),
+ C(2.3_a, 1_a, 3.3_a),
+ })));
+
+template <typename T>
+std::vector<Case> OpAddIntCases() {
+ static_assert(IsInteger<UnwrapNumber<T>>);
+ return {
+ C(T{0}, T{0}, T{0}),
+ C(T{1}, T{2}, T{3}),
+ C(T::Lowest(), T{1}, T{T::Lowest() + 1}),
+ C(T::Highest(), Negate(T{1}), T{T::Highest() - 1}),
+ C(T::Lowest(), T::Highest(), Negate(T{1})),
+ C(T::Highest(), T{1}, T::Lowest(), true),
+ C(T::Lowest(), Negate(T{1}), T::Highest(), true),
+ };
+}
+template <typename T>
+std::vector<Case> OpAddFloatCases() {
+ static_assert(IsFloatingPoint<UnwrapNumber<T>>);
+ return {
+ C(T{0}, T{0}, T{0}),
+ C(T{1}, T{2}, T{3}),
+ C(T::Lowest(), T{1}, T{T::Lowest() + 1}),
+ C(T::Highest(), Negate(T{1}), T{T::Highest() - 1}),
+ C(T::Lowest(), T::Highest(), T{0}),
+ C(T::Highest(), T::Highest(), T::Inf(), true),
+ C(T::Lowest(), Negate(T::Highest()), -T::Inf(), true),
+ };
+}
+INSTANTIATE_TEST_SUITE_P(Add,
+ ResolverConstEvalBinaryOpTest,
+ testing::Combine(testing::Values(ast::BinaryOp::kAdd),
+ testing::ValuesIn(Concat( //
+ OpAddIntCases<AInt>(),
+ OpAddIntCases<i32>(),
+ OpAddIntCases<u32>(),
+ OpAddFloatCases<AFloat>(),
+ OpAddFloatCases<f32>(),
+ OpAddFloatCases<f16>()))));
+
+template <typename T>
+std::vector<Case> OpSubIntCases() {
+ static_assert(IsInteger<UnwrapNumber<T>>);
+ return {
+ C(T{0}, T{0}, T{0}),
+ C(T{3}, T{2}, T{1}),
+ C(T{T::Lowest() + 1}, T{1}, T::Lowest()),
+ C(T{T::Highest() - 1}, Negate(T{1}), T::Highest()),
+ C(Negate(T{1}), T::Highest(), T::Lowest()),
+ C(T::Lowest(), T{1}, T::Highest(), true),
+ C(T::Highest(), Negate(T{1}), T::Lowest(), true),
+ };
+}
+template <typename T>
+std::vector<Case> OpSubFloatCases() {
+ static_assert(IsFloatingPoint<UnwrapNumber<T>>);
+ return {
+ C(T{0}, T{0}, T{0}),
+ C(T{3}, T{2}, T{1}),
+ C(T::Highest(), T{1}, T{T::Highest() - 1}),
+ C(T::Lowest(), Negate(T{1}), T{T::Lowest() + 1}),
+ C(T{0}, T::Highest(), T::Lowest()),
+ C(T::Highest(), Negate(T::Highest()), T::Inf(), true),
+ C(T::Lowest(), T::Highest(), -T::Inf(), true),
+ };
+}
+INSTANTIATE_TEST_SUITE_P(Sub,
+ ResolverConstEvalBinaryOpTest,
+ testing::Combine(testing::Values(ast::BinaryOp::kSubtract),
+ testing::ValuesIn(Concat( //
+ OpSubIntCases<AInt>(),
+ OpSubIntCases<i32>(),
+ OpSubIntCases<u32>(),
+ OpSubFloatCases<AFloat>(),
+ OpSubFloatCases<f32>(),
+ OpSubFloatCases<f16>()))));
+
+TEST_F(ResolverConstEvalTest, BinaryAbstractAddOverflow_AInt) {
+ GlobalConst("c", nullptr, Add(Source{{1, 1}}, Expr(AInt::Highest()), 1_a));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "1:1 error: '-9223372036854775808' cannot be represented as 'abstract-int'");
+}
+
+TEST_F(ResolverConstEvalTest, BinaryAbstractAddUnderflow_AInt) {
+ GlobalConst("c", nullptr, Add(Source{{1, 1}}, Expr(AInt::Lowest()), -1_a));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "1:1 error: '9223372036854775807' cannot be represented as 'abstract-int'");
+}
+
+TEST_F(ResolverConstEvalTest, BinaryAbstractAddOverflow_AFloat) {
+ GlobalConst("c", nullptr, Add(Source{{1, 1}}, Expr(AFloat::Highest()), AFloat::Highest()));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "1:1 error: 'inf' cannot be represented as 'abstract-float'");
+}
+
+TEST_F(ResolverConstEvalTest, BinaryAbstractAddUnderflow_AFloat) {
+ GlobalConst("c", nullptr, Add(Source{{1, 1}}, Expr(AFloat::Lowest()), AFloat::Lowest()));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "1:1 error: '-inf' cannot be represented as 'abstract-float'");
+}
+
+TEST_F(ResolverConstEvalTest, BinaryAbstractMixed_ScalarScalar) {
+ auto* a = Const("a", nullptr, Expr(1_a)); // AInt
+ auto* b = Const("b", nullptr, Expr(2.3_a)); // AFloat
+ auto* c = Add(Expr("a"), Expr("b"));
+ WrapInFunction(a, b, c);
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ auto* sem = Sem().Get(c);
+ ASSERT_TRUE(sem);
+ ASSERT_TRUE(sem->ConstantValue());
+ auto result = sem->ConstantValue()->As<AFloat>();
+ EXPECT_EQ(result, 3.3f);
+}
+
+TEST_F(ResolverConstEvalTest, BinaryAbstractMixed_ScalarVector) {
+ auto* a = Const("a", nullptr, Expr(1_a)); // AInt
+ auto* b = Const("b", nullptr, Construct(ty.vec(nullptr, 3), Expr(2.3_a))); // AFloat
+ auto* c = Add(Expr("a"), Expr("b"));
+ WrapInFunction(a, b, c);
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ auto* sem = Sem().Get(c);
+ ASSERT_TRUE(sem);
+ ASSERT_TRUE(sem->ConstantValue());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 3.3f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 3.3f);
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.3f);
+}
+
+} // namespace binary_op
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Builtin
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace builtin {
+
+using Types = std::variant<AInt, AFloat, u32, i32, f32, f16>;
+
+struct Case {
+ utils::Vector<Types, 8> args;
+ Types result;
+ bool result_pos_or_neg;
+};
+
+static std::ostream& operator<<(std::ostream& o, const Case& c) {
+ for (auto& a : c.args) {
+ std::visit([&](auto&& v) { o << v << ((&a != &c.args.Back()) ? " " : ""); }, a);
+ }
+ return o;
+}
+
+template <typename T>
+Case C(std::initializer_list<Types> args, T result, bool result_pos_or_neg = false) {
+ return Case{std::move(args), std::move(result), result_pos_or_neg};
+}
+
+using ResolverConstEvalBuiltinTest = ResolverTestWithParam<std::tuple<sem::BuiltinType, Case>>;
+
+TEST_P(ResolverConstEvalBuiltinTest, Test) {
+ Enable(ast::Extension::kF16);
+
+ auto builtin = std::get<0>(GetParam());
+ auto c = std::get<1>(GetParam());
+
+ utils::Vector<const ast::Expression*, 8> args;
+ for (auto& a : c.args) {
+ std::visit([&](auto&& v) { args.Push(Expr(v)); }, a);
+ }
+
+ std::visit(
+ [&](auto&& result) {
+ using T = std::decay_t<decltype(result)>;
+ auto* expr = Call(sem::str(builtin), std::move(args));
+
+ GlobalConst("C", nullptr, expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ const sem::Constant* value = sem->ConstantValue();
+ ASSERT_NE(value, nullptr);
+ EXPECT_TYPE(value->Type(), sem->Type());
+
+ auto actual = value->As<T>();
+
+ if constexpr (IsFloatingPoint<UnwrapNumber<T>>) {
+ if (std::isnan(result)) {
+ EXPECT_TRUE(std::isnan(actual));
+ } else {
+ EXPECT_FLOAT_EQ(c.result_pos_or_neg ? Abs(actual) : actual, result);
+ }
+ } else {
+ EXPECT_EQ(c.result_pos_or_neg ? Abs(actual) : actual, result);
+ }
+
+ if constexpr (IsInteger<UnwrapNumber<T>>) {
+ // Check that the constant's integer doesn't contain unexpected data in the MSBs
+ // that are outside of the bit-width of T.
+ EXPECT_EQ(value->As<AInt>(), AInt(result));
+ }
+ },
+ c.result);
+}
+
+template <typename T, bool finite_only>
+std::vector<Case> Atan2Cases() {
+ std::vector<Case> cases = {
+ // If y is +/-0 and x is negative or -0, +/-PI is returned
+ C({T(0.0), -T(0.0)}, kPi<T>, true),
+
+ // If y is +/-0 and x is positive or +0, +/-0 is returned
+ C({T(0.0), T(0.0)}, T(0.0), true),
+
+ // If x is +/-0 and y is negative, -PI/2 is returned
+ C({-T(1.0), T(0.0)}, -kPiOver2<T>),
+ C({-T(1.0), -T(0.0)}, -kPiOver2<T>),
+
+ // If x is +/-0 and y is positive, +PI/2 is returned
+ C({T(1.0), T(0.0)}, kPiOver2<T>),
+ C({T(1.0), -T(0.0)}, kPiOver2<T>),
+ };
+
+ if constexpr (!finite_only) {
+ std::vector<Case> non_finite_cases = {
+ // If y is +/-INF and x is finite, +/-PI/2 is returned
+ C({T::Inf(), T(0.0)}, kPiOver2<T>, true),
+ C({-T::Inf(), T(0.0)}, kPiOver2<T>, true),
+
+ // If y is +/-INF and x is -INF, +/-3PI/4 is returned
+ C({T::Inf(), -T::Inf()}, k3PiOver4<T>, true),
+ C({-T::Inf(), -T::Inf()}, k3PiOver4<T>, true),
+
+ // If y is +/-INF and x is +INF, +/-PI/4 is returned
+ C({T::Inf(), T::Inf()}, kPiOver4<T>, true),
+ C({-T::Inf(), T::Inf()}, kPiOver4<T>, true),
+
+ // If x is -INF and y is finite and positive, +PI is returned
+ C({T(0.0), -T::Inf()}, kPi<T>),
+
+ // If x is -INF and y is finite and negative, -PI is returned
+ C({-T(0.0), -T::Inf()}, -kPi<T>),
+
+ // If x is +INF and y is finite and positive, +0 is returned
+ C({T(0.0), T::Inf()}, T(0.0)),
+
+ // If x is +INF and y is finite and negative, -0 is returned
+ C({-T(0.0), T::Inf()}, -T(0.0)),
+
+ // If either x is NaN or y is NaN, NaN is returned
+ C({T::NaN(), T(0.0)}, T::NaN()),
+ C({T(0.0), T::NaN()}, T::NaN()),
+ C({T::NaN(), T::NaN()}, T::NaN()),
+ };
+
+ cases = Concat(cases, non_finite_cases);
+ }
+
+ return cases;
+}
+
+INSTANTIATE_TEST_SUITE_P( //
+ MixedAbstractArgs,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kAtan2),
+ testing::ValuesIn(std::vector{
+ C({1_a, 1.0_a}, 0.78539819_a),
+ C({1.0_a, 1_a}, 0.78539819_a),
+ })));
+
+INSTANTIATE_TEST_SUITE_P( //
+ Atan2,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kAtan2),
+ testing::ValuesIn(Concat(Atan2Cases<AFloat, true>(), //
+ Atan2Cases<f32, false>(),
+ Atan2Cases<f16, false>()))));
+
+template <typename T>
+std::vector<Case> ClampCases() {
+ return {
+ C({T(0), T(0), T(0)}, T(0)),
+ C({T(0), T(42), T::Highest()}, T(42)),
+ C({T::Lowest(), T(0), T(42)}, T(0)),
+ C({T(0), T::Lowest(), T::Highest()}, T(0)),
+ C({T(0), T::Highest(), T::Lowest()}, T::Lowest()),
+ C({T::Highest(), T::Highest(), T::Highest()}, T::Highest()),
+ C({T::Lowest(), T::Lowest(), T::Lowest()}, T::Lowest()),
+ C({T::Highest(), T::Lowest(), T::Highest()}, T::Highest()),
+ C({T::Lowest(), T::Lowest(), T::Highest()}, T::Lowest()),
+ };
+}
+
+INSTANTIATE_TEST_SUITE_P( //
+ Clamp,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kClamp),
+ testing::ValuesIn(Concat(ClampCases<AInt>(), //
+ ClampCases<i32>(),
+ ClampCases<u32>(),
+ ClampCases<AFloat>(),
+ ClampCases<f32>(),
+ ClampCases<f16>()))));
+
+} // namespace builtin
+
+} // namespace
+} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/control_block_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/control_block_validation_test.cc
index a5ba7ca0fb9..9b0d2899bdc 100644
--- a/chromium/third_party/dawn/src/tint/resolver/control_block_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/control_block_validation_test.cc
@@ -213,8 +213,8 @@ TEST_F(ResolverControlBlockValidationTest, SwitchConditionTypeMustMatchSelectorT
// }
auto* var = Var("a", ty.i32(), Expr(2_i));
- auto* block = Block(Decl(var), Switch("a", //
- Case(Source{{12, 34}}, {Expr(1_u)}), //
+ auto* block = Block(Decl(var), Switch("a", //
+ Case(Source{{12, 34}}, utils::Vector{Expr(1_u)}), //
DefaultCase()));
WrapInFunction(block);
@@ -232,9 +232,9 @@ TEST_F(ResolverControlBlockValidationTest, SwitchConditionTypeMustMatchSelectorT
// }
auto* var = Var("a", ty.u32(), Expr(2_u));
- auto* block = Block(Decl(var), //
- Switch("a", //
- Case(Source{{12, 34}}, {Expr(-1_i)}), //
+ auto* block = Block(Decl(var), //
+ Switch("a", //
+ Case(Source{{12, 34}}, utils::Vector{Expr(-1_i)}), //
DefaultCase()));
WrapInFunction(block);
@@ -256,7 +256,7 @@ TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorValueUint_Fail)
auto* block = Block(Decl(var), //
Switch("a", //
Case(Expr(0_u)),
- Case({
+ Case(utils::Vector{
Expr(Source{{12, 34}}, 2_u),
Expr(3_u),
Expr(Source{{56, 78}}, 2_u),
@@ -282,7 +282,7 @@ TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorValueSint_Fail)
auto* block = Block(Decl(var), //
Switch("a", //
Case(Expr(Source{{12, 34}}, -10_i)),
- Case({
+ Case(utils::Vector{
Expr(0_i),
Expr(1_i),
Expr(2_i),
diff --git a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc
index 5618fbab499..3ac3a677f5b 100644
--- a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc
@@ -13,11 +13,9 @@
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/intrinsic-gen
+// File generated by tools/src/cmd/gen
// using the template:
// src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
-// and the intrinsic defintion file:
-// src/tint/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
@@ -36,6 +34,8 @@ const char* str(CtorConvIntrinsic i) {
return "u32";
case CtorConvIntrinsic::kF32:
return "f32";
+ case CtorConvIntrinsic::kF16:
+ return "f16";
case CtorConvIntrinsic::kBool:
return "bool";
case CtorConvIntrinsic::kVec2:
@@ -67,4 +67,3 @@ const char* str(CtorConvIntrinsic i) {
}
} // namespace tint::resolver
-
diff --git a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
index ac98c4d22e6..00ac21beee4 100644
--- a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
+++ b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
@@ -1,9 +1,12 @@
{{- /*
--------------------------------------------------------------------------------
-Template file for use with tools/builtin-gen to generate ctor_conv_intrinsic.cc
+Template file for use with tools/src/cmd/gen to generate ctor_conv_intrinsic.cc
+
+To update the generated file, run:
+ ./tools/run gen
See:
-* tools/cmd/intrinsic-gen/gen for structures used by this template
+* tools/src/cmd/gen for structures used by this template
* https://golang.org/pkg/text/template/ for documentation on the template syntax
--------------------------------------------------------------------------------
*/ -}}
@@ -16,7 +19,7 @@ const char* str(CtorConvIntrinsic i) {
switch (i) {
case CtorConvIntrinsic::kNone:
return "<none>";
-{{- range .Sem.ConstructorsAndConverters }}
+{{- range Sem.ConstructorsAndConverters }}
case CtorConvIntrinsic::k{{Title .Name}}:
return "{{.Name}}";
{{- end }}
@@ -25,4 +28,3 @@ const char* str(CtorConvIntrinsic i) {
}
} // namespace tint::resolver
-
diff --git a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h
index 7c686583038..4ee1c79e99f 100644
--- a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h
+++ b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h
@@ -13,11 +13,9 @@
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/intrinsic-gen
+// File generated by tools/src/cmd/gen
// using the template:
// src/tint/resolver/ctor_conv_intrinsic.h.tmpl
-// and the intrinsic defintion file:
-// src/tint/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
@@ -36,6 +34,7 @@ enum class CtorConvIntrinsic {
kI32,
kU32,
kF32,
+ kF16,
kBool,
kVec2,
kVec3,
diff --git a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h.tmpl b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
index 9c0da258050..349f93907eb 100644
--- a/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
+++ b/chromium/third_party/dawn/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
@@ -1,9 +1,12 @@
{{- /*
--------------------------------------------------------------------------------
-Template file for use with tools/builtin-gen to generate ctor_conv_intrinsic.h
+Template file for use with tools/src/cmd/gen to generate ctor_conv_intrinsic.h
+
+To update the generated file, run:
+ ./tools/run gen
See:
-* tools/cmd/intrinsic-gen/gen for structures used by this template
+* tools/src/cmd/gen for structures used by this template
* https://golang.org/pkg/text/template/ for documentation on the template syntax
--------------------------------------------------------------------------------
*/ -}}
@@ -19,7 +22,7 @@ namespace tint::resolver {
/// declared in the intrinsic table.
enum class CtorConvIntrinsic {
kNone = -1,
-{{- range .Sem.ConstructorsAndConverters }}
+{{- range Sem.ConstructorsAndConverters }}
k{{Title .Name}},
{{- end }}
};
diff --git a/chromium/third_party/dawn/src/tint/resolver/dependency_graph.cc b/chromium/third_party/dawn/src/tint/resolver/dependency_graph.cc
index 7e668997c68..823dcada11d 100644
--- a/chromium/third_party/dawn/src/tint/resolver/dependency_graph.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/dependency_graph.cc
@@ -19,12 +19,58 @@
#include <utility>
#include <vector>
+#include "src/tint/ast/alias.h"
+#include "src/tint/ast/array.h"
+#include "src/tint/ast/assignment_statement.h"
+#include "src/tint/ast/atomic.h"
+#include "src/tint/ast/block_statement.h"
+#include "src/tint/ast/bool.h"
+#include "src/tint/ast/break_statement.h"
+#include "src/tint/ast/call_statement.h"
+#include "src/tint/ast/compound_assignment_statement.h"
#include "src/tint/ast/continue_statement.h"
+#include "src/tint/ast/depth_multisampled_texture.h"
+#include "src/tint/ast/depth_texture.h"
#include "src/tint/ast/discard_statement.h"
+#include "src/tint/ast/external_texture.h"
+#include "src/tint/ast/f16.h"
+#include "src/tint/ast/f32.h"
#include "src/tint/ast/fallthrough_statement.h"
+#include "src/tint/ast/for_loop_statement.h"
+#include "src/tint/ast/i32.h"
+#include "src/tint/ast/id_attribute.h"
+#include "src/tint/ast/if_statement.h"
+#include "src/tint/ast/increment_decrement_statement.h"
+#include "src/tint/ast/internal_attribute.h"
+#include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/ast/invariant_attribute.h"
+#include "src/tint/ast/location_attribute.h"
+#include "src/tint/ast/loop_statement.h"
+#include "src/tint/ast/matrix.h"
+#include "src/tint/ast/multisampled_texture.h"
+#include "src/tint/ast/pointer.h"
+#include "src/tint/ast/return_statement.h"
+#include "src/tint/ast/sampled_texture.h"
+#include "src/tint/ast/stage_attribute.h"
+#include "src/tint/ast/storage_texture.h"
+#include "src/tint/ast/stride_attribute.h"
+#include "src/tint/ast/struct.h"
+#include "src/tint/ast/struct_member_align_attribute.h"
+#include "src/tint/ast/struct_member_offset_attribute.h"
+#include "src/tint/ast/struct_member_size_attribute.h"
+#include "src/tint/ast/switch_statement.h"
#include "src/tint/ast/traverse_expressions.h"
+#include "src/tint/ast/type_name.h"
+#include "src/tint/ast/u32.h"
+#include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/ast/vector.h"
+#include "src/tint/ast/void.h"
+#include "src/tint/ast/while_statement.h"
+#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/scope_stack.h"
#include "src/tint/sem/builtin.h"
+#include "src/tint/symbol_table.h"
+#include "src/tint/utils/block_allocator.h"
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
@@ -158,6 +204,7 @@ class DependencyScanner {
[&](const ast::Enable*) {
// Enable directives do not effect the dependency graph.
},
+ [&](const ast::StaticAssert* assertion) { TraverseExpression(assertion->condition); },
[&](Default) { UnhandledNode(diagnostics_, global->node); });
}
@@ -191,7 +238,7 @@ class DependencyScanner {
/// Traverses the statements, performing symbol resolution and determining
/// global dependencies.
- void TraverseStatements(const ast::StatementList& stmts) {
+ void TraverseStatements(utils::VectorRef<const ast::Statement*> stmts) {
for (auto* s : stmts) {
TraverseStatement(s);
}
@@ -263,6 +310,13 @@ class DependencyScanner {
TraverseExpression(v->variable->constructor);
Declare(v->variable->symbol, v->variable);
},
+ [&](const ast::WhileStatement* w) {
+ scope_stack_.Push();
+ TINT_DEFER(scope_stack_.Pop());
+ TraverseExpression(w->condition);
+ TraverseStatement(w->body);
+ },
+ [&](const ast::StaticAssert* assertion) { TraverseExpression(assertion->condition); },
[&](Default) {
if (!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
ast::DiscardStatement, ast::FallthroughStatement>()) {
@@ -352,7 +406,7 @@ class DependencyScanner {
/// Traverses the attribute list, performing symbol resolution and
/// determining global dependencies.
- void TraverseAttributes(const ast::AttributeList& attrs) {
+ void TraverseAttributes(utils::VectorRef<const ast::Attribute*> attrs) {
for (auto* attr : attrs) {
TraverseAttribute(attr);
}
@@ -435,6 +489,10 @@ struct DependencyAnalysis {
/// #diagnostics.
/// @returns true if analysis found no errors, otherwise false.
bool Run(const ast::Module& module) {
+ // Reserve container memory
+ graph_.resolved_symbols.reserve(module.GlobalDeclarations().Length());
+ sorted_.Reserve(module.GlobalDeclarations().Length());
+
// Collect all the named globals from the AST module
GatherGlobals(module);
@@ -447,7 +505,7 @@ struct DependencyAnalysis {
// Dump the dependency graph if TINT_DUMP_DEPENDENCY_GRAPH is non-zero
DumpDependencyGraph();
- graph_.ordered_globals = std::move(sorted_);
+ graph_.ordered_globals = sorted_.Release();
return !diagnostics_.contains_errors();
}
@@ -463,6 +521,8 @@ struct DependencyAnalysis {
[&](const ast::TypeDecl* td) { return td->name; },
[&](const ast::Function* func) { return func->symbol; },
[&](const ast::Variable* var) { return var->symbol; },
+ [&](const ast::Enable*) { return Symbol(); },
+ [&](const ast::StaticAssert*) { return Symbol(); },
[&](Default) {
UnhandledNode(diagnostics_, node);
return Symbol{};
@@ -481,11 +541,12 @@ struct DependencyAnalysis {
/// declaration
std::string KindOf(const ast::Node* node) {
return Switch(
- node, //
- [&](const ast::Struct*) { return "struct"; },
- [&](const ast::Alias*) { return "alias"; },
- [&](const ast::Function*) { return "function"; },
- [&](const ast::Variable* var) { return var->is_const ? "let" : "var"; },
+ node, //
+ [&](const ast::Struct*) { return "struct"; }, //
+ [&](const ast::Alias*) { return "alias"; }, //
+ [&](const ast::Function*) { return "function"; }, //
+ [&](const ast::Variable* v) { return v->Kind(); }, //
+ [&](const ast::StaticAssert*) { return "static_assert"; }, //
[&](Default) {
UnhandledNode(diagnostics_, node);
return "<error>";
@@ -497,9 +558,8 @@ struct DependencyAnalysis {
void GatherGlobals(const ast::Module& module) {
for (auto* node : module.GlobalDeclarations()) {
auto* global = allocator_.Create(node);
- // Enable directives do not form a symbol. Skip them.
- if (!node->Is<ast::Enable>()) {
- globals_.emplace(SymbolOf(node), global);
+ if (auto symbol = SymbolOf(node); symbol.IsValid()) {
+ globals_.emplace(symbol, global);
}
declaration_order_.emplace_back(global);
}
@@ -569,33 +629,43 @@ struct DependencyAnalysis {
return; // This code assumes there are no undeclared identifiers.
}
- std::unordered_set<const Global*> visited;
+ // Make sure all 'enable' directives go before any other global declarations.
for (auto* global : declaration_order_) {
- utils::UniqueVector<const Global*> stack;
+ if (auto* enable = global->node->As<ast::Enable>()) {
+ sorted_.Add(enable);
+ }
+ }
+
+ for (auto* global : declaration_order_) {
+ if (global->node->Is<ast::Enable>()) {
+ // Skip 'enable' directives here, as they are already added.
+ continue;
+ }
+ utils::UniqueVector<const Global*, 8> stack;
TraverseDependencies(
global,
[&](const Global* g) { // Enter
- if (!stack.add(g)) {
- CyclicDependencyFound(g, stack);
+ if (!stack.Add(g)) {
+ CyclicDependencyFound(g, stack.Release());
return false;
}
- if (sorted_.contains(g->node)) {
+ if (sorted_.Contains(g->node)) {
// Visited this global already.
// stack was pushed, but exit() will not be called when we return
// false, so pop here.
- stack.pop_back();
+ stack.Pop();
return false;
}
return true;
},
[&](const Global* g) { // Exit. Only called if Enter returned true.
- sorted_.add(g->node);
- stack.pop_back();
+ sorted_.Add(g->node);
+ stack.Pop();
});
- sorted_.add(global->node);
+ sorted_.Add(global->node);
- if (!stack.empty()) {
+ if (!stack.IsEmpty()) {
// Each stack.push() must have a corresponding stack.pop_back().
TINT_ICE(Resolver, diagnostics_)
<< "stack not empty after returning from TraverseDependencies()";
@@ -621,12 +691,12 @@ struct DependencyAnalysis {
/// @param root is the global that starts the cyclic dependency, which must be
/// found in `stack`.
/// @param stack is the global dependency stack that contains a loop.
- void CyclicDependencyFound(const Global* root, const std::vector<const Global*>& stack) {
+ void CyclicDependencyFound(const Global* root, utils::VectorRef<const Global*> stack) {
std::stringstream msg;
msg << "cyclic dependency found: ";
constexpr size_t kLoopNotStarted = ~0u;
size_t loop_start = kLoopNotStarted;
- for (size_t i = 0; i < stack.size(); i++) {
+ for (size_t i = 0; i < stack.Length(); i++) {
auto* e = stack[i];
if (loop_start == kLoopNotStarted && e == root) {
loop_start = i;
@@ -637,9 +707,9 @@ struct DependencyAnalysis {
}
msg << "'" << NameOf(root->node) << "'";
AddError(diagnostics_, msg.str(), root->node->source);
- for (size_t i = loop_start; i < stack.size(); i++) {
+ for (size_t i = loop_start; i < stack.Length(); i++) {
auto* from = stack[i];
- auto* to = (i + 1 < stack.size()) ? stack[i + 1] : stack[loop_start];
+ auto* to = (i + 1 < stack.Length()) ? stack[i + 1] : stack[loop_start];
auto info = DepInfoFor(from, to);
AddNote(diagnostics_,
KindOf(from->node) + " '" + NameOf(from->node) + "' " + info.action + " " +
@@ -694,7 +764,7 @@ struct DependencyAnalysis {
std::vector<Global*> declaration_order_;
/// Globals in sorted dependency order. Populated by SortGlobals().
- utils::UniqueVector<const ast::Node*> sorted_;
+ utils::UniqueVector<const ast::Node*, 64> sorted_;
};
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/resolver/dependency_graph.h b/chromium/third_party/dawn/src/tint/resolver/dependency_graph.h
index 0554817ebce..9f5ddc56466 100644
--- a/chromium/third_party/dawn/src/tint/resolver/dependency_graph.h
+++ b/chromium/third_party/dawn/src/tint/resolver/dependency_graph.h
@@ -46,7 +46,7 @@ struct DependencyGraph {
DependencyGraph& output);
/// All globals in dependency-sorted order.
- std::vector<const ast::Node*> ordered_globals;
+ utils::Vector<const ast::Node*, 32> ordered_globals;
/// Map of ast::IdentifierExpression or ast::TypeName to a type, function, or
/// variable that declares the symbol.
diff --git a/chromium/third_party/dawn/src/tint/resolver/dependency_graph_test.cc b/chromium/third_party/dawn/src/tint/resolver/dependency_graph_test.cc
index 82b0a69b682..7a8110b7da0 100644
--- a/chromium/third_party/dawn/src/tint/resolver/dependency_graph_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/dependency_graph_test.cc
@@ -113,12 +113,12 @@ enum class SymbolUseKind {
GlobalVarSampledTexElemType,
GlobalVarMultisampledTexElemType,
GlobalVarValue,
- GlobalLetType,
- GlobalLetArrayElemType,
- GlobalLetArraySizeValue,
- GlobalLetVectorElemType,
- GlobalLetMatrixElemType,
- GlobalLetValue,
+ GlobalConstType,
+ GlobalConstArrayElemType,
+ GlobalConstArraySizeValue,
+ GlobalConstVectorElemType,
+ GlobalConstMatrixElemType,
+ GlobalConstValue,
AliasType,
StructMemberType,
CallFunction,
@@ -146,11 +146,11 @@ static constexpr SymbolUseKind kTypeUseKinds[] = {
SymbolUseKind::GlobalVarMatrixElemType,
SymbolUseKind::GlobalVarSampledTexElemType,
SymbolUseKind::GlobalVarMultisampledTexElemType,
- SymbolUseKind::GlobalLetType,
- SymbolUseKind::GlobalLetArrayElemType,
- SymbolUseKind::GlobalLetArraySizeValue,
- SymbolUseKind::GlobalLetVectorElemType,
- SymbolUseKind::GlobalLetMatrixElemType,
+ SymbolUseKind::GlobalConstType,
+ SymbolUseKind::GlobalConstArrayElemType,
+ SymbolUseKind::GlobalConstArraySizeValue,
+ SymbolUseKind::GlobalConstVectorElemType,
+ SymbolUseKind::GlobalConstMatrixElemType,
SymbolUseKind::AliasType,
SymbolUseKind::StructMemberType,
SymbolUseKind::ParameterType,
@@ -165,7 +165,7 @@ static constexpr SymbolUseKind kTypeUseKinds[] = {
};
static constexpr SymbolUseKind kValueUseKinds[] = {
- SymbolUseKind::GlobalVarValue, SymbolUseKind::GlobalLetValue,
+ SymbolUseKind::GlobalVarValue, SymbolUseKind::GlobalConstValue,
SymbolUseKind::LocalVarValue, SymbolUseKind::LocalLetValue,
SymbolUseKind::NestedLocalVarValue, SymbolUseKind::NestedLocalLetValue,
SymbolUseKind::WorkgroupSizeValue,
@@ -182,7 +182,7 @@ std::ostream& operator<<(std::ostream& out, SymbolDeclKind kind) {
case SymbolDeclKind::GlobalVar:
return out << "global var";
case SymbolDeclKind::GlobalConst:
- return out << "global let";
+ return out << "global const";
case SymbolDeclKind::Alias:
return out << "alias";
case SymbolDeclKind::Struct:
@@ -223,18 +223,18 @@ std::ostream& operator<<(std::ostream& out, SymbolUseKind kind) {
return out << "global var sampled_texture element type";
case SymbolUseKind::GlobalVarMultisampledTexElemType:
return out << "global var multisampled_texture element type";
- case SymbolUseKind::GlobalLetType:
- return out << "global let type";
- case SymbolUseKind::GlobalLetValue:
- return out << "global let value";
- case SymbolUseKind::GlobalLetArrayElemType:
- return out << "global let array element type";
- case SymbolUseKind::GlobalLetArraySizeValue:
- return out << "global let array size value";
- case SymbolUseKind::GlobalLetVectorElemType:
- return out << "global let vector element type";
- case SymbolUseKind::GlobalLetMatrixElemType:
- return out << "global let matrix element type";
+ case SymbolUseKind::GlobalConstType:
+ return out << "global const type";
+ case SymbolUseKind::GlobalConstValue:
+ return out << "global const value";
+ case SymbolUseKind::GlobalConstArrayElemType:
+ return out << "global const array element type";
+ case SymbolUseKind::GlobalConstArraySizeValue:
+ return out << "global const array size value";
+ case SymbolUseKind::GlobalConstVectorElemType:
+ return out << "global const vector element type";
+ case SymbolUseKind::GlobalConstMatrixElemType:
+ return out << "global const matrix element type";
case SymbolUseKind::AliasType:
return out << "alias type";
case SymbolUseKind::StructMemberType:
@@ -282,10 +282,10 @@ std::string DiagString(SymbolUseKind kind) {
case SymbolUseKind::GlobalVarMatrixElemType:
case SymbolUseKind::GlobalVarSampledTexElemType:
case SymbolUseKind::GlobalVarMultisampledTexElemType:
- case SymbolUseKind::GlobalLetType:
- case SymbolUseKind::GlobalLetArrayElemType:
- case SymbolUseKind::GlobalLetVectorElemType:
- case SymbolUseKind::GlobalLetMatrixElemType:
+ case SymbolUseKind::GlobalConstType:
+ case SymbolUseKind::GlobalConstArrayElemType:
+ case SymbolUseKind::GlobalConstVectorElemType:
+ case SymbolUseKind::GlobalConstMatrixElemType:
case SymbolUseKind::AliasType:
case SymbolUseKind::StructMemberType:
case SymbolUseKind::ParameterType:
@@ -299,8 +299,8 @@ std::string DiagString(SymbolUseKind kind) {
return "type";
case SymbolUseKind::GlobalVarValue:
case SymbolUseKind::GlobalVarArraySizeValue:
- case SymbolUseKind::GlobalLetValue:
- case SymbolUseKind::GlobalLetArraySizeValue:
+ case SymbolUseKind::GlobalConstValue:
+ case SymbolUseKind::GlobalConstArraySizeValue:
case SymbolUseKind::LocalVarValue:
case SymbolUseKind::LocalVarArraySizeValue:
case SymbolUseKind::LocalLetValue:
@@ -349,12 +349,12 @@ int ScopeDepth(SymbolUseKind kind) {
case SymbolUseKind::GlobalVarMatrixElemType:
case SymbolUseKind::GlobalVarSampledTexElemType:
case SymbolUseKind::GlobalVarMultisampledTexElemType:
- case SymbolUseKind::GlobalLetType:
- case SymbolUseKind::GlobalLetValue:
- case SymbolUseKind::GlobalLetArrayElemType:
- case SymbolUseKind::GlobalLetArraySizeValue:
- case SymbolUseKind::GlobalLetVectorElemType:
- case SymbolUseKind::GlobalLetMatrixElemType:
+ case SymbolUseKind::GlobalConstType:
+ case SymbolUseKind::GlobalConstValue:
+ case SymbolUseKind::GlobalConstArrayElemType:
+ case SymbolUseKind::GlobalConstArraySizeValue:
+ case SymbolUseKind::GlobalConstVectorElemType:
+ case SymbolUseKind::GlobalConstMatrixElemType:
case SymbolUseKind::AliasType:
case SymbolUseKind::StructMemberType:
case SymbolUseKind::WorkgroupSizeValue:
@@ -384,13 +384,13 @@ struct SymbolTestHelper {
/// The program builder
ProgramBuilder* const builder;
/// Parameters to a function that may need to be built
- std::vector<const ast::Variable*> parameters;
+ utils::Vector<const ast::Parameter*, 8> parameters;
/// Shallow function var / let declaration statements
- std::vector<const ast::Statement*> statements;
+ utils::Vector<const ast::Statement*, 8> statements;
/// Nested function local var / let declaration statements
- std::vector<const ast::Statement*> nested_statements;
+ utils::Vector<const ast::Statement*, 8> nested_statements;
/// Function attributes
- ast::AttributeList func_attrs;
+ utils::Vector<const ast::Attribute*, 8> func_attrs;
/// Constructor
/// @param builder the program builder
@@ -425,38 +425,38 @@ const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind, Symbol symbol, Sourc
auto& b = *builder;
switch (kind) {
case SymbolDeclKind::GlobalVar:
- return b.Global(source, symbol, b.ty.i32(), ast::StorageClass::kPrivate);
+ return b.GlobalVar(source, symbol, b.ty.i32(), ast::StorageClass::kPrivate);
case SymbolDeclKind::GlobalConst:
return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1_i));
case SymbolDeclKind::Alias:
return b.Alias(source, symbol, b.ty.i32());
case SymbolDeclKind::Struct:
- return b.Structure(source, symbol, {b.Member("m", b.ty.i32())});
+ return b.Structure(source, symbol, utils::Vector{b.Member("m", b.ty.i32())});
case SymbolDeclKind::Function:
- return b.Func(source, symbol, {}, b.ty.void_(), {});
+ return b.Func(source, symbol, utils::Empty, b.ty.void_(), utils::Empty);
case SymbolDeclKind::Parameter: {
auto* node = b.Param(source, symbol, b.ty.i32());
- parameters.emplace_back(node);
+ parameters.Push(node);
return node;
}
case SymbolDeclKind::LocalVar: {
auto* node = b.Var(source, symbol, b.ty.i32());
- statements.emplace_back(b.Decl(node));
+ statements.Push(b.Decl(node));
return node;
}
case SymbolDeclKind::LocalLet: {
auto* node = b.Let(source, symbol, b.ty.i32(), b.Expr(1_i));
- statements.emplace_back(b.Decl(node));
+ statements.Push(b.Decl(node));
return node;
}
case SymbolDeclKind::NestedLocalVar: {
auto* node = b.Var(source, symbol, b.ty.i32());
- nested_statements.emplace_back(b.Decl(node));
+ nested_statements.Push(b.Decl(node));
return node;
}
case SymbolDeclKind::NestedLocalLet: {
auto* node = b.Let(source, symbol, b.ty.i32(), b.Expr(1_i));
- nested_statements.emplace_back(b.Decl(node));
+ nested_statements.Push(b.Decl(node));
return node;
}
}
@@ -468,70 +468,70 @@ const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source
switch (kind) {
case SymbolUseKind::GlobalVarType: {
auto* node = b.ty.type_name(source, symbol);
- b.Global(b.Sym(), node, ast::StorageClass::kPrivate);
+ b.GlobalVar(b.Sym(), node, ast::StorageClass::kPrivate);
return node;
}
case SymbolUseKind::GlobalVarArrayElemType: {
auto* node = b.ty.type_name(source, symbol);
- b.Global(b.Sym(), b.ty.array(node, 4_i), ast::StorageClass::kPrivate);
+ b.GlobalVar(b.Sym(), b.ty.array(node, 4_i), ast::StorageClass::kPrivate);
return node;
}
case SymbolUseKind::GlobalVarArraySizeValue: {
auto* node = b.Expr(source, symbol);
- b.Global(b.Sym(), b.ty.array(b.ty.i32(), node), ast::StorageClass::kPrivate);
+ b.GlobalVar(b.Sym(), b.ty.array(b.ty.i32(), node), ast::StorageClass::kPrivate);
return node;
}
case SymbolUseKind::GlobalVarVectorElemType: {
auto* node = b.ty.type_name(source, symbol);
- b.Global(b.Sym(), b.ty.vec3(node), ast::StorageClass::kPrivate);
+ b.GlobalVar(b.Sym(), b.ty.vec3(node), ast::StorageClass::kPrivate);
return node;
}
case SymbolUseKind::GlobalVarMatrixElemType: {
auto* node = b.ty.type_name(source, symbol);
- b.Global(b.Sym(), b.ty.mat3x4(node), ast::StorageClass::kPrivate);
+ b.GlobalVar(b.Sym(), b.ty.mat3x4(node), ast::StorageClass::kPrivate);
return node;
}
case SymbolUseKind::GlobalVarSampledTexElemType: {
auto* node = b.ty.type_name(source, symbol);
- b.Global(b.Sym(), b.ty.sampled_texture(ast::TextureDimension::k2d, node));
+ b.GlobalVar(b.Sym(), b.ty.sampled_texture(ast::TextureDimension::k2d, node));
return node;
}
case SymbolUseKind::GlobalVarMultisampledTexElemType: {
auto* node = b.ty.type_name(source, symbol);
- b.Global(b.Sym(), b.ty.multisampled_texture(ast::TextureDimension::k2d, node));
+ b.GlobalVar(b.Sym(), b.ty.multisampled_texture(ast::TextureDimension::k2d, node));
return node;
}
case SymbolUseKind::GlobalVarValue: {
auto* node = b.Expr(source, symbol);
- b.Global(b.Sym(), b.ty.i32(), ast::StorageClass::kPrivate, node);
+ b.GlobalVar(b.Sym(), b.ty.i32(), ast::StorageClass::kPrivate, node);
return node;
}
- case SymbolUseKind::GlobalLetType: {
+ case SymbolUseKind::GlobalConstType: {
auto* node = b.ty.type_name(source, symbol);
b.GlobalConst(b.Sym(), node, b.Expr(1_i));
return node;
}
- case SymbolUseKind::GlobalLetArrayElemType: {
+ case SymbolUseKind::GlobalConstArrayElemType: {
auto* node = b.ty.type_name(source, symbol);
b.GlobalConst(b.Sym(), b.ty.array(node, 4_i), b.Expr(1_i));
return node;
}
- case SymbolUseKind::GlobalLetArraySizeValue: {
+ case SymbolUseKind::GlobalConstArraySizeValue: {
auto* node = b.Expr(source, symbol);
b.GlobalConst(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i));
return node;
}
- case SymbolUseKind::GlobalLetVectorElemType: {
+ case SymbolUseKind::GlobalConstVectorElemType: {
auto* node = b.ty.type_name(source, symbol);
b.GlobalConst(b.Sym(), b.ty.vec3(node), b.Expr(1_i));
return node;
}
- case SymbolUseKind::GlobalLetMatrixElemType: {
+ case SymbolUseKind::GlobalConstMatrixElemType: {
auto* node = b.ty.type_name(source, symbol);
b.GlobalConst(b.Sym(), b.ty.mat3x4(node), b.Expr(1_i));
return node;
}
- case SymbolUseKind::GlobalLetValue: {
+ case SymbolUseKind::GlobalConstValue: {
auto* node = b.Expr(source, symbol);
b.GlobalConst(b.Sym(), b.ty.i32(), node);
return node;
@@ -543,83 +543,82 @@ const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source
}
case SymbolUseKind::StructMemberType: {
auto* node = b.ty.type_name(source, symbol);
- b.Structure(b.Sym(), {b.Member("m", node)});
+ b.Structure(b.Sym(), utils::Vector{b.Member("m", node)});
return node;
}
case SymbolUseKind::CallFunction: {
auto* node = b.Expr(source, symbol);
- statements.emplace_back(b.CallStmt(b.Call(node)));
+ statements.Push(b.CallStmt(b.Call(node)));
return node;
}
case SymbolUseKind::ParameterType: {
auto* node = b.ty.type_name(source, symbol);
- parameters.emplace_back(b.Param(b.Sym(), node));
+ parameters.Push(b.Param(b.Sym(), node));
return node;
}
case SymbolUseKind::LocalVarType: {
auto* node = b.ty.type_name(source, symbol);
- statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
+ statements.Push(b.Decl(b.Var(b.Sym(), node)));
return node;
}
case SymbolUseKind::LocalVarArrayElemType: {
auto* node = b.ty.type_name(source, symbol);
- statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.array(node, 4_u), b.Expr(1_i))));
+ statements.Push(b.Decl(b.Var(b.Sym(), b.ty.array(node, 4_u), b.Expr(1_i))));
return node;
}
case SymbolUseKind::LocalVarArraySizeValue: {
auto* node = b.Expr(source, symbol);
- statements.emplace_back(
- b.Decl(b.Var(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i))));
+ statements.Push(b.Decl(b.Var(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i))));
return node;
}
case SymbolUseKind::LocalVarVectorElemType: {
auto* node = b.ty.type_name(source, symbol);
- statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.vec3(node))));
+ statements.Push(b.Decl(b.Var(b.Sym(), b.ty.vec3(node))));
return node;
}
case SymbolUseKind::LocalVarMatrixElemType: {
auto* node = b.ty.type_name(source, symbol);
- statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.mat3x4(node))));
+ statements.Push(b.Decl(b.Var(b.Sym(), b.ty.mat3x4(node))));
return node;
}
case SymbolUseKind::LocalVarValue: {
auto* node = b.Expr(source, symbol);
- statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
+ statements.Push(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
return node;
}
case SymbolUseKind::LocalLetType: {
auto* node = b.ty.type_name(source, symbol);
- statements.emplace_back(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
+ statements.Push(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
return node;
}
case SymbolUseKind::LocalLetValue: {
auto* node = b.Expr(source, symbol);
- statements.emplace_back(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
+ statements.Push(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
return node;
}
case SymbolUseKind::NestedLocalVarType: {
auto* node = b.ty.type_name(source, symbol);
- nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
+ nested_statements.Push(b.Decl(b.Var(b.Sym(), node)));
return node;
}
case SymbolUseKind::NestedLocalVarValue: {
auto* node = b.Expr(source, symbol);
- nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
+ nested_statements.Push(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
return node;
}
case SymbolUseKind::NestedLocalLetType: {
auto* node = b.ty.type_name(source, symbol);
- nested_statements.emplace_back(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
+ nested_statements.Push(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
return node;
}
case SymbolUseKind::NestedLocalLetValue: {
auto* node = b.Expr(source, symbol);
- nested_statements.emplace_back(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
+ nested_statements.Push(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
return node;
}
case SymbolUseKind::WorkgroupSizeValue: {
auto* node = b.Expr(source, symbol);
- func_attrs.emplace_back(b.WorkgroupSize(1_i, node, 2_i));
+ func_attrs.Push(b.WorkgroupSize(1_i, node, 2_i));
return node;
}
}
@@ -628,15 +627,15 @@ const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source
void SymbolTestHelper::Build() {
auto& b = *builder;
- if (!nested_statements.empty()) {
- statements.emplace_back(b.Block(nested_statements));
- nested_statements.clear();
+ if (!nested_statements.IsEmpty()) {
+ statements.Push(b.Block(nested_statements));
+ nested_statements.Clear();
}
- if (!parameters.empty() || !statements.empty() || !func_attrs.empty()) {
+ if (!parameters.IsEmpty() || !statements.IsEmpty() || !func_attrs.IsEmpty()) {
b.Func("func", parameters, b.ty.void_(), statements, func_attrs);
- parameters.clear();
- statements.clear();
- func_attrs.clear();
+ parameters.Clear();
+ statements.Clear();
+ func_attrs.Clear();
}
}
@@ -651,8 +650,8 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, FuncCall) {
// fn A() { B(); }
// fn B() {}
- Func("A", {}, ty.void_(), {CallStmt(Call(Expr(Source{{12, 34}}, "B")))});
- Func(Source{{56, 78}}, "B", {}, ty.void_(), {Return()});
+ Func("A", utils::Empty, ty.void_(), utils::Vector{CallStmt(Call(Expr(Source{{12, 34}}, "B")))});
+ Func(Source{{56, 78}}, "B", utils::Empty, ty.void_(), utils::Vector{Return()});
Build();
}
@@ -663,7 +662,8 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeConstructed) {
// }
// type T = i32;
- Func("F", {}, ty.void_(), {Block(Ignore(Construct(ty.type_name(Source{{12, 34}}, "T"))))});
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{Block(Ignore(Construct(ty.type_name(Source{{12, 34}}, "T"))))});
Alias(Source{{56, 78}}, "T", ty.i32());
Build();
@@ -675,7 +675,8 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByLocal) {
// }
// type T = i32;
- Func("F", {}, ty.void_(), {Block(Decl(Var("v", ty.type_name(Source{{12, 34}}, "T"))))});
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{Block(Decl(Var("v", ty.type_name(Source{{12, 34}}, "T"))))});
Alias(Source{{56, 78}}, "T", ty.i32());
Build();
@@ -685,7 +686,8 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByParam) {
// fn F(p : T) {}
// type T = i32;
- Func("F", {Param("p", ty.type_name(Source{{12, 34}}, "T"))}, ty.void_(), {});
+ Func("F", utils::Vector{Param("p", ty.type_name(Source{{12, 34}}, "T"))}, ty.void_(),
+ utils::Empty);
Alias(Source{{56, 78}}, "T", ty.i32());
Build();
@@ -695,7 +697,7 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedAsReturnType) {
// fn F() -> T {}
// type T = i32;
- Func("F", {}, ty.type_name(Source{{12, 34}}, "T"), {});
+ Func("F", utils::Empty, ty.type_name(Source{{12, 34}}, "T"), utils::Empty);
Alias(Source{{56, 78}}, "T", ty.i32());
Build();
@@ -705,7 +707,7 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeByStructMember) {
// struct S { m : T };
// type T = i32;
- Structure("S", {Member("m", ty.type_name(Source{{12, 34}}, "T"))});
+ Structure("S", utils::Vector{Member("m", ty.type_name(Source{{12, 34}}, "T"))});
Alias(Source{{56, 78}}, "T", ty.i32());
Build();
@@ -717,10 +719,12 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, VarUsed) {
// }
// var G: f32 = 2.1;
- Func("F", ast::VariableList{}, ty.void_(),
- {Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14_f))});
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{
+ Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14_f)),
+ });
- Global(Source{{56, 78}}, "G", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
+ GlobalVar(Source{{56, 78}}, "G", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
Build();
}
@@ -770,7 +774,7 @@ using ResolverDependencyGraphDeclSelfUse = ResolverDependencyGraphTest;
TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalVar) {
const Symbol symbol = Sym("SYMBOL");
- Global(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i));
+ GlobalVar(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i));
Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
12:34 note: var 'SYMBOL' references var 'SYMBOL' here)");
}
@@ -779,7 +783,7 @@ TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalConst) {
const Symbol symbol = Sym("SYMBOL");
GlobalConst(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i));
Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
-12:34 note: let 'SYMBOL' references let 'SYMBOL' here)");
+12:34 note: const 'SYMBOL' references const 'SYMBOL' here)");
}
TEST_F(ResolverDependencyGraphDeclSelfUse, LocalVar) {
@@ -806,8 +810,8 @@ using ResolverDependencyGraphCyclicRefTest = ResolverDependencyGraphTest;
TEST_F(ResolverDependencyGraphCyclicRefTest, DirectCall) {
// fn main() { main(); }
- Func(Source{{12, 34}}, "main", {}, ty.void_(),
- {CallStmt(Call(Expr(Source{{56, 78}}, "main")))});
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.void_(),
+ utils::Vector{CallStmt(Call(Expr(Source{{56, 78}}, "main")))});
Build(R"(12:34 error: cyclic dependency found: 'main' -> 'main'
56:78 note: function 'main' calls function 'main' here)");
@@ -820,15 +824,18 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, IndirectCall) {
// 4: fn c() { d(); }
// 5: fn b() { c(); }
- Func(Source{{1, 1}}, "a", {}, ty.void_(), {CallStmt(Call(Expr(Source{{1, 10}}, "b")))});
- Func(Source{{2, 1}}, "e", {}, ty.void_(), {});
- Func(Source{{3, 1}}, "d", {}, ty.void_(),
- {
+ Func(Source{{1, 1}}, "a", utils::Empty, ty.void_(),
+ utils::Vector{CallStmt(Call(Expr(Source{{1, 10}}, "b")))});
+ Func(Source{{2, 1}}, "e", utils::Empty, ty.void_(), utils::Empty);
+ Func(Source{{3, 1}}, "d", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call(Expr(Source{{3, 10}}, "e"))),
CallStmt(Call(Expr(Source{{3, 10}}, "b"))),
});
- Func(Source{{4, 1}}, "c", {}, ty.void_(), {CallStmt(Call(Expr(Source{{4, 10}}, "d")))});
- Func(Source{{5, 1}}, "b", {}, ty.void_(), {CallStmt(Call(Expr(Source{{5, 10}}, "c")))});
+ Func(Source{{4, 1}}, "c", utils::Empty, ty.void_(),
+ utils::Vector{CallStmt(Call(Expr(Source{{4, 10}}, "d")))});
+ Func(Source{{5, 1}}, "b", utils::Empty, ty.void_(),
+ utils::Vector{CallStmt(Call(Expr(Source{{5, 10}}, "c")))});
Build(R"(5:1 error: cyclic dependency found: 'b' -> 'c' -> 'd' -> 'b'
5:10 note: function 'b' calls function 'c' here
@@ -869,7 +876,8 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, Struct_Direct) {
// a: S;
// };
- Structure(Source{{12, 34}}, "S", {Member("a", ty.type_name(Source{{56, 78}}, "S"))});
+ Structure(Source{{12, 34}}, "S",
+ utils::Vector{Member("a", ty.type_name(Source{{56, 78}}, "S"))});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -882,9 +890,9 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, Struct_Indirect) {
// 2: struct X { y: Y; };
// 3: struct Z { x: X; };
- Structure(Source{{1, 1}}, "Y", {Member("z", ty.type_name(Source{{1, 10}}, "Z"))});
- Structure(Source{{2, 1}}, "X", {Member("y", ty.type_name(Source{{2, 10}}, "Y"))});
- Structure(Source{{3, 1}}, "Z", {Member("x", ty.type_name(Source{{3, 10}}, "X"))});
+ Structure(Source{{1, 1}}, "Y", utils::Vector{Member("z", ty.type_name(Source{{1, 10}}, "Z"))});
+ Structure(Source{{2, 1}}, "X", utils::Vector{Member("y", ty.type_name(Source{{2, 10}}, "Y"))});
+ Structure(Source{{3, 1}}, "Z", utils::Vector{Member("x", ty.type_name(Source{{3, 10}}, "X"))});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -897,7 +905,7 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, Struct_Indirect) {
TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Direct) {
// var<private> V : i32 = V;
- Global(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
+ GlobalVar(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -905,7 +913,7 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Direct) {
56:78 note: var 'V' references var 'V' here)");
}
-TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Direct) {
+TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalConst_Direct) {
// let V : i32 = V;
GlobalConst(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
@@ -913,7 +921,7 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Direct) {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: cyclic dependency found: 'V' -> 'V'
-56:78 note: let 'V' references let 'V' here)");
+56:78 note: const 'V' references const 'V' here)");
}
TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Indirect) {
@@ -921,9 +929,9 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Indirect) {
// 2: var<private> X : i32 = Y;
// 3: var<private> Z : i32 = X;
- Global(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
- Global(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
- Global(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
+ GlobalVar(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
+ GlobalVar(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
+ GlobalVar(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -933,10 +941,10 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Indirect) {
2:10 note: var 'X' references var 'Y' here)");
}
-TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Indirect) {
- // 1: let Y : i32 = Z;
- // 2: let X : i32 = Y;
- // 3: let Z : i32 = X;
+TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalConst_Indirect) {
+ // 1: const Y : i32 = Z;
+ // 2: const X : i32 = Y;
+ // 3: const Z : i32 = X;
GlobalConst(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
GlobalConst(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
@@ -945,9 +953,9 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Indirect) {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
-1:10 note: let 'Y' references let 'Z' here
-3:10 note: let 'Z' references let 'X' here
-2:10 note: let 'X' references let 'Y' here)");
+1:10 note: const 'Y' references const 'Z' here
+3:10 note: const 'Z' references const 'X' here
+2:10 note: const 'X' references const 'Y' here)");
}
TEST_F(ResolverDependencyGraphCyclicRefTest, Mixed_RecursiveDependencies) {
@@ -956,13 +964,13 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, Mixed_RecursiveDependencies) {
// 3: struct S { a : A };
// 4: var Z = L;
// 5: type R = A;
- // 6: let L : S = Z;
+ // 6: const L : S = Z;
- Func(Source{{1, 1}}, "F", {}, ty.type_name(Source{{1, 5}}, "R"),
- {Return(Expr(Source{{1, 10}}, "Z"))});
+ Func(Source{{1, 1}}, "F", utils::Empty, ty.type_name(Source{{1, 5}}, "R"),
+ utils::Vector{Return(Expr(Source{{1, 10}}, "Z"))});
Alias(Source{{2, 1}}, "A", ty.type_name(Source{{2, 10}}, "S"));
- Structure(Source{{3, 1}}, "S", {Member("a", ty.type_name(Source{{3, 10}}, "A"))});
- Global(Source{{4, 1}}, "Z", nullptr, Expr(Source{{4, 10}}, "L"));
+ Structure(Source{{3, 1}}, "S", utils::Vector{Member("a", ty.type_name(Source{{3, 10}}, "A"))});
+ GlobalVar(Source{{4, 1}}, "Z", nullptr, Expr(Source{{4, 10}}, "L"));
Alias(Source{{5, 1}}, "R", ty.type_name(Source{{5, 10}}, "A"));
GlobalConst(Source{{6, 1}}, "L", ty.type_name(Source{{5, 5}}, "S"), Expr(Source{{5, 10}}, "Z"));
@@ -972,8 +980,8 @@ TEST_F(ResolverDependencyGraphCyclicRefTest, Mixed_RecursiveDependencies) {
2:10 note: alias 'A' references struct 'S' here
3:10 note: struct 'S' references alias 'A' here
4:1 error: cyclic dependency found: 'Z' -> 'L' -> 'Z'
-4:10 note: var 'Z' references let 'L' here
-5:10 note: let 'L' references var 'Z' here)");
+4:10 note: var 'Z' references const 'L' here
+5:10 note: const 'L' references var 'Z' here)");
}
} // namespace recursive_tests
@@ -1037,7 +1045,7 @@ TEST_P(ResolverDependencyGraphOrderedGlobalsTest, InOrder) {
helper.Add(use_kind, symbol, Source{{56, 78}});
helper.Build();
- ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
+ ASSERT_EQ(AST().GlobalDeclarations().Length(), 2u);
auto* decl = AST().GlobalDeclarations()[0];
auto* use = AST().GlobalDeclarations()[1];
@@ -1057,7 +1065,7 @@ TEST_P(ResolverDependencyGraphOrderedGlobalsTest, OutOfOrder) {
helper.Add(decl_kind, symbol, Source{{12, 34}});
helper.Build();
- ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
+ ASSERT_EQ(AST().GlobalDeclarations().Length(), 2u);
auto* use = AST().GlobalDeclarations()[0];
auto* decl = AST().GlobalDeclarations()[1];
@@ -1078,6 +1086,20 @@ INSTANTIATE_TEST_SUITE_P(Functions,
ResolverDependencyGraphOrderedGlobalsTest,
testing::Combine(testing::ValuesIn(kFuncDeclKinds),
testing::ValuesIn(kFuncUseKinds)));
+
+TEST_F(ResolverDependencyGraphOrderedGlobalsTest, EnableFirst) {
+ // Test that enable nodes always go before any other global declaration.
+ // Although all enable directives in a valid WGSL program must go before any other global
+ // declaration, a transform may produce such a AST tree that has some declarations before enable
+ // nodes. DependencyGraph should deal with these cases.
+ auto* var_1 = GlobalVar("SYMBOL1", ty.i32(), nullptr);
+ auto* enable_1 = Enable(ast::Extension::kF16);
+ auto* var_2 = GlobalVar("SYMBOL2", ty.f32(), nullptr);
+ auto* enable_2 = Enable(ast::Extension::kF16);
+
+ EXPECT_THAT(AST().GlobalDeclarations(), ElementsAre(var_1, enable_1, var_2, enable_2));
+ EXPECT_THAT(Build().ordered_globals, ElementsAre(enable_1, enable_2, var_1, var_2));
+}
} // namespace ordered_globals
////////////////////////////////////////////////////////////////////////////////
@@ -1148,9 +1170,9 @@ TEST_P(ResolverDependencyShadowTest, Test) {
SymbolTestHelper helper(this);
auto* outer = helper.Add(outer_kind, symbol, Source{{12, 34}});
helper.Add(inner_kind, symbol, Source{{56, 78}});
- auto* inner_var = helper.nested_statements.size()
+ auto* inner_var = helper.nested_statements.Length()
? helper.nested_statements[0]->As<ast::VariableDeclStatement>()->variable
- : helper.statements.size()
+ : helper.statements.Length()
? helper.statements[0]->As<ast::VariableDeclStatement>()->variable
: helper.parameters[0];
helper.Build();
@@ -1185,9 +1207,9 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
const auto type_sym = Sym("TYPE");
const auto func_sym = Sym("FUNC");
- const auto* value_decl = Global(value_sym, ty.i32(), ast::StorageClass::kPrivate);
+ const auto* value_decl = GlobalVar(value_sym, ty.i32(), ast::StorageClass::kPrivate);
const auto* type_decl = Alias(type_sym, ty.i32());
- const auto* func_decl = Func(func_sym, {}, ty.void_(), {});
+ const auto* func_decl = Func(func_sym, utils::Empty, ty.void_(), utils::Empty);
struct SymbolUse {
const ast::Node* decl = nullptr;
@@ -1195,10 +1217,10 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
std::string where;
};
- std::vector<SymbolUse> symbol_uses;
+ utils::Vector<SymbolUse, 64> symbol_uses;
auto add_use = [&](const ast::Node* decl, auto* use, int line, const char* kind) {
- symbol_uses.emplace_back(
+ symbol_uses.Push(
SymbolUse{decl, use, std::string(__FILE__) + ":" + std::to_string(line) + ": " + kind});
return use;
};
@@ -1207,13 +1229,13 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
#define F add_use(func_decl, Expr(func_sym), __LINE__, "F()")
Alias(Sym(), T);
- Structure(Sym(), {Member(Sym(), T)});
- Global(Sym(), T, V);
+ Structure(Sym(), utils::Vector{Member(Sym(), T)});
+ GlobalVar(Sym(), T, V);
GlobalConst(Sym(), T, V);
- Func(Sym(), //
- {Param(Sym(), T)}, //
- T, // Return type
- {
+ Func(Sym(), //
+ utils::Vector{Param(Sym(), T)}, //
+ T, // Return type
+ utils::Vector{
Decl(Var(Sym(), T, V)), //
Decl(Let(Sym(), T, V)), //
CallStmt(Call(F, V)), //
@@ -1229,6 +1251,9 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
Assign(V, V), //
Block( //
Assign(V, V))), //
+ While(Equal(V, V), //
+ Block( //
+ Assign(V, V))), //
Loop(Block(Assign(V, V)), //
Block(Assign(V, V))), //
Switch(V, //
@@ -1242,24 +1267,24 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
Discard(), //
}); //
// Exercise type traversal
- Global(Sym(), ty.atomic(T));
- Global(Sym(), ty.bool_());
- Global(Sym(), ty.i32());
- Global(Sym(), ty.u32());
- Global(Sym(), ty.f32());
- Global(Sym(), ty.array(T, V, 4));
- Global(Sym(), ty.vec3(T));
- Global(Sym(), ty.mat3x2(T));
- Global(Sym(), ty.pointer(T, ast::StorageClass::kPrivate));
- Global(Sym(), ty.sampled_texture(ast::TextureDimension::k2d, T));
- Global(Sym(), ty.depth_texture(ast::TextureDimension::k2d));
- Global(Sym(), ty.depth_multisampled_texture(ast::TextureDimension::k2d));
- Global(Sym(), ty.external_texture());
- Global(Sym(), ty.multisampled_texture(ast::TextureDimension::k2d, T));
- Global(Sym(), ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
- ast::Access::kRead)); //
- Global(Sym(), ty.sampler(ast::SamplerKind::kSampler));
- Func(Sym(), {}, ty.void_(), {});
+ GlobalVar(Sym(), ty.atomic(T));
+ GlobalVar(Sym(), ty.bool_());
+ GlobalVar(Sym(), ty.i32());
+ GlobalVar(Sym(), ty.u32());
+ GlobalVar(Sym(), ty.f32());
+ GlobalVar(Sym(), ty.array(T, V, 4));
+ GlobalVar(Sym(), ty.vec3(T));
+ GlobalVar(Sym(), ty.mat3x2(T));
+ GlobalVar(Sym(), ty.pointer(T, ast::StorageClass::kPrivate));
+ GlobalVar(Sym(), ty.sampled_texture(ast::TextureDimension::k2d, T));
+ GlobalVar(Sym(), ty.depth_texture(ast::TextureDimension::k2d));
+ GlobalVar(Sym(), ty.depth_multisampled_texture(ast::TextureDimension::k2d));
+ GlobalVar(Sym(), ty.external_texture());
+ GlobalVar(Sym(), ty.multisampled_texture(ast::TextureDimension::k2d, T));
+ GlobalVar(Sym(), ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+ ast::Access::kRead)); //
+ GlobalVar(Sym(), ty.sampler(ast::SamplerKind::kSampler));
+ Func(Sym(), utils::Empty, ty.void_(), utils::Empty);
#undef V
#undef T
#undef F
@@ -1272,8 +1297,8 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
}
TEST_F(ResolverDependencyGraphTraversalTest, InferredType) {
- // Check that the nullptr of the var / let type doesn't make things explode
- Global("a", nullptr, Expr(1_i));
+ // Check that the nullptr of the var / const / let type doesn't make things explode
+ GlobalVar("a", nullptr, Expr(1_i));
GlobalConst("b", nullptr, Expr(1_i));
WrapInFunction(Var("c", nullptr, Expr(1_i)), //
Let("d", nullptr, Expr(1_i)));
@@ -1284,10 +1309,10 @@ TEST_F(ResolverDependencyGraphTraversalTest, InferredType) {
// DependencyAnalysis::SortGlobals(), found by clusterfuzz.
// See: crbug.com/chromium/1273451
TEST_F(ResolverDependencyGraphTraversalTest, chromium_1273451) {
- Structure("A", {Member("a", ty.i32())});
- Structure("B", {Member("b", ty.i32())});
- Func("f", {Param("a", ty.type_name("A"))}, ty.type_name("B"),
- {
+ Structure("A", utils::Vector{Member("a", ty.i32())});
+ Structure("B", utils::Vector{Member("b", ty.i32())});
+ Func("f", utils::Vector{Param("a", ty.type_name("A"))}, ty.type_name("B"),
+ utils::Vector{
Return(Construct(ty.type_name("B"))),
});
Build();
diff --git a/chromium/third_party/dawn/src/tint/resolver/entry_point_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/entry_point_validation_test.cc
index 5e5df15e3fd..d997912576f 100644
--- a/chromium/third_party/dawn/src/tint/resolver/entry_point_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/entry_point_validation_test.cc
@@ -49,8 +49,16 @@ class ResolverEntryPointValidationTest : public TestHelper, public testing::Test
TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
// @fragment
// fn main() -> @location(0) f32 { return 1.0; }
- Func(Source{{12, 34}}, "main", {}, ty.f32(), {Return(1_f)},
- {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(1_f),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -58,8 +66,16 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Builtin) {
// @vertex
// fn main() -> @builtin(position) vec4<f32> { return vec4<f32>(); }
- Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -69,8 +85,13 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Missing) {
// fn main() -> f32 {
// return 1.0;
// }
- Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- {Stage(ast::PipelineStage::kVertex)});
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: missing entry point IO attribute on return type");
@@ -81,9 +102,17 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Multiple) {
// fn main() -> @location(0) @builtin(position) vec4<f32> {
// return vec4<f32>();
// }
- Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- {Stage(ast::PipelineStage::kVertex)},
- {Location(Source{{13, 43}}, 0), Builtin(Source{{14, 52}}, ast::Builtin::kPosition)});
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{
+ Return(Construct(ty.vec4<f32>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Location(Source{{13, 43}}, 0),
+ Builtin(Source{{14, 52}}, ast::BuiltinValue::kPosition),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
@@ -99,11 +128,18 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
// fn main() -> Output {
// return Output();
// }
- auto* output =
- Structure("Output", {Member("a", ty.f32(), {Location(0)}),
- Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* output = Structure(
+ "Output", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{Location(0)}),
+ Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -116,12 +152,20 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMultipleAttribu
// fn main() -> Output {
// return Output();
// }
- auto* output =
- Structure("Output", {Member("a", ty.f32(),
- {Location(Source{{13, 43}}, 0),
- Builtin(Source{{14, 52}}, ast::Builtin::kFragDepth)})});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* output = Structure(
+ "Output",
+ utils::Vector{
+ Member("a", ty.f32(),
+ utils::Vector{Location(Source{{13, 43}}, 0),
+ Builtin(Source{{14, 52}}, ast::BuiltinValue::kFragDepth)}),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
@@ -138,10 +182,18 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMissingAttribut
// fn main() -> Output {
// return Output();
// }
- auto* output = Structure("Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
- Member(Source{{14, 52}}, "b", ty.f32(), {})});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* output =
+ Structure("Output", utils::Vector{
+ Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0)}),
+ Member(Source{{14, 52}}, "b", ty.f32(), {}),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -158,11 +210,18 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
// fn main() -> Output {
// return Output();
// }
- auto* output =
- Structure("Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
- Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* output = Structure(
+ "Output", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
+ Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -174,8 +233,18 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Location) {
// @fragment
// fn main(@location(0) param : f32) {}
- auto* param = Param("param", ty.f32(), {Location(0)});
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ auto* param = Param("param", ty.f32(),
+ utils::Vector{
+ Location(0),
+ });
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -184,7 +253,14 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Missing) {
// @fragment
// fn main(param : f32) {}
auto* param = Param(Source{{13, 43}}, "param", ty.vec4<f32>());
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "13:43 error: missing entry point IO attribute on parameter");
@@ -193,10 +269,19 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Missing) {
TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
// @fragment
// fn main(@location(0) @builtin(sample_index) param : u32) {}
- auto* param = Param(
- "param", ty.u32(),
- {Location(Source{{13, 43}}, 0), Builtin(Source{{14, 52}}, ast::Builtin::kSampleIndex)});
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ auto* param = Param("param", ty.u32(),
+ utils::Vector{
+ Location(Source{{13, 43}}, 0),
+ Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex),
+ });
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
@@ -210,11 +295,20 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
// };
// @fragment
// fn main(param : Input) {}
- auto* input =
- Structure("Input", {Member("a", ty.f32(), {Location(0)}),
- Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
+ auto* input = Structure(
+ "Input", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{Location(0)}),
+ Member("b", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+ });
auto* param = Param("param", ty.Of(input));
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -225,12 +319,22 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_MemberMultipleAttribut
// };
// @fragment
// fn main(param : Input) {}
- auto* input =
- Structure("Input", {Member("a", ty.u32(),
- {Location(Source{{13, 43}}, 0),
- Builtin(Source{{14, 52}}, ast::Builtin::kSampleIndex)})});
+ auto* input = Structure(
+ "Input",
+ utils::Vector{
+ Member("a", ty.u32(),
+ utils::Vector{Location(Source{{13, 43}}, 0),
+ Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex)}),
+ });
auto* param = Param("param", ty.Of(input));
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
@@ -245,10 +349,20 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_MemberMissingAttribute
// };
// @fragment
// fn main(param : Input) {}
- auto* input = Structure("Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
- Member(Source{{14, 52}}, "b", ty.f32(), {})});
+ auto* input =
+ Structure("Input", utils::Vector{
+ Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0)}),
+ Member(Source{{14, 52}}, "b", ty.f32(), {}),
+ });
auto* param = Param("param", ty.Of(input));
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(14:52 error: missing entry point IO attribute
@@ -259,10 +373,23 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_DuplicateBuiltins) {
// @fragment
// fn main(@builtin(sample_index) param_a : u32,
// @builtin(sample_index) param_b : u32) {}
- auto* param_a = Param("param_a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
- auto* param_b = Param("param_b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
- Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* param_a = Param("param_a", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleIndex),
+ });
+ auto* param_b = Param("param_b", ty.u32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleIndex),
+ });
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param_a,
+ param_b,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -279,14 +406,27 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
// };
// @fragment
// fn main(param_a : InputA, param_b : InputB) {}
- auto* input_a =
- Structure("InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
- auto* input_b =
- Structure("InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
+ auto* input_a = Structure(
+ "InputA",
+ utils::Vector{
+ Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+ });
+ auto* input_b = Structure(
+ "InputB",
+ utils::Vector{
+ Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+ });
auto* param_a = Param("param_a", ty.Of(input_a));
auto* param_b = Param("param_b", ty.Of(input_b));
- Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param_a,
+ param_b,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -298,7 +438,10 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
TEST_F(ResolverEntryPointValidationTest, VertexShaderMustReturnPosition) {
// @vertex
// fn main() {}
- Func(Source{{12, 34}}, "main", {}, ty.void_(), {}, {Stage(ast::PipelineStage::kVertex)});
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -306,6 +449,135 @@ TEST_F(ResolverEntryPointValidationTest, VertexShaderMustReturnPosition) {
"in its return type");
}
+TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithEnable) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> a : u32;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant);
+
+ EXPECT_TRUE(r()->Resolve());
+}
+
+TEST_F(ResolverEntryPointValidationTest, PushConstantDisallowedWithoutEnable) {
+ // var<push_constant> a : u32;
+ GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::StorageClass::kPushConstant);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "1:2 error: use of variable storage class 'push_constant' requires enabling "
+ "extension 'chromium_experimental_push_constant'");
+}
+
+TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithIgnoreStorageClassAttribute) {
+ // var<push_constant> a : u32; // With ast::DisabledValidation::kIgnoreStorageClass
+ GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant,
+ utils::Vector{Disable(ast::DisabledValidation::kIgnoreStorageClass)});
+
+ EXPECT_TRUE(r()->Resolve());
+}
+
+TEST_F(ResolverEntryPointValidationTest, PushConstantOneVariableUsedInEntryPoint) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> a : u32;
+ // @compute @workgroup_size(1) fn main() {
+ // _ = a;
+ // }
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant);
+
+ Func("main", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Expr(1_i))});
+
+ EXPECT_TRUE(r()->Resolve());
+}
+
+TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInEntryPoint) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> a : u32;
+ // var<push_constant> b : u32;
+ // @compute @workgroup_size(1) fn main() {
+ // _ = a;
+ // _ = b;
+ // }
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::StorageClass::kPushConstant);
+ GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::StorageClass::kPushConstant);
+
+ Func(Source{{5, 6}}, "main", {}, ty.void_(),
+ utils::Vector{Assign(Phony(), "a"), Assign(Phony(), "b")},
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Expr(1_i))});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(5:6 error: entry point 'main' uses two different 'push_constant' variables.
+3:4 note: first 'push_constant' variable declaration is here
+1:2 note: second 'push_constant' variable declaration is here)");
+}
+
+TEST_F(ResolverEntryPointValidationTest,
+ PushConstantTwoVariablesUsedInEntryPointWithFunctionGraph) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> a : u32;
+ // var<push_constant> b : u32;
+ // fn uses_a() {
+ // _ = a;
+ // }
+ // fn uses_b() {
+ // _ = b;
+ // }
+ // @compute @workgroup_size(1) fn main() {
+ // uses_a();
+ // uses_b();
+ // }
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::StorageClass::kPushConstant);
+ GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::StorageClass::kPushConstant);
+
+ Func(Source{{5, 6}}, "uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")});
+ Func(Source{{7, 8}}, "uses_b", {}, ty.void_(), utils::Vector{Assign(Phony(), "b")});
+
+ Func(Source{{9, 10}}, "main", {}, ty.void_(),
+ utils::Vector{CallStmt(Call("uses_a")), CallStmt(Call("uses_b"))},
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Expr(1_i))});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(9:10 error: entry point 'main' uses two different 'push_constant' variables.
+3:4 note: first 'push_constant' variable declaration is here
+7:8 note: called by function 'uses_b'
+9:10 note: called by entry point 'main'
+1:2 note: second 'push_constant' variable declaration is here
+5:6 note: called by function 'uses_a'
+9:10 note: called by entry point 'main')");
+}
+
+TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInDifferentEntryPoint) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> a : u32;
+ // var<push_constant> b : u32;
+ // @compute @workgroup_size(1) fn uses_a() {
+ // _ = a;
+ // }
+ // @compute @workgroup_size(1) fn uses_b() {
+ // _ = a;
+ // }
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant);
+ GlobalVar("b", ty.u32(), ast::StorageClass::kPushConstant);
+
+ Func("uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Expr(1_i))});
+ Func("uses_b", {}, ty.void_(), utils::Vector{Assign(Phony(), "b")},
+ utils::Vector{Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Expr(1_i))});
+
+ EXPECT_TRUE(r()->Resolve());
+}
+
namespace TypeValidationTests {
struct Params {
builder::ast_type_func_ptr create_ast_type;
@@ -334,14 +606,39 @@ static constexpr Params cases[] = {
ParamsFor<alias<i32>>(true), //
ParamsFor<alias<u32>>(true), //
ParamsFor<alias<bool>>(false), //
+ // Currently entry point IO of f16 types are not implemented yet.
+ // TODO(tint:1473, tint:1502): Change f16 and vecN<f16> cases to valid after f16 is supported in
+ // entry point IO.
+ ParamsFor<f16>(false), //
+ ParamsFor<vec2<f16>>(false), //
+ ParamsFor<vec3<f16>>(false), //
+ ParamsFor<vec4<f16>>(false), //
+ ParamsFor<mat2x2<f16>>(false), //
+ ParamsFor<mat3x3<f16>>(false), //
+ ParamsFor<mat4x4<f16>>(false), //
+ ParamsFor<alias<f16>>(false), //
};
TEST_P(TypeValidationTest, BareInputs) {
// @fragment
// fn main(@location(0) @interpolate(flat) a : *) {}
auto params = GetParam();
- auto* a = Param("a", params.create_ast_type(*this), {Location(0), Flat()});
- Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+
+ Enable(ast::Extension::kF16);
+
+ auto* a = Param("a", params.create_ast_type(*this),
+ utils::Vector{
+ Location(0),
+ Flat(),
+ });
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ a,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -357,10 +654,22 @@ TEST_P(TypeValidationTest, StructInputs) {
// @fragment
// fn main(a : Input) {}
auto params = GetParam();
- auto* input =
- Structure("Input", {Member("a", params.create_ast_type(*this), {Location(0), Flat()})});
+
+ Enable(ast::Extension::kF16);
+
+ auto* input = Structure(
+ "Input", utils::Vector{
+ Member("a", params.create_ast_type(*this), utils::Vector{Location(0), Flat()}),
+ });
auto* a = Param("a", ty.Of(input), {});
- Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ a,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -375,9 +684,19 @@ TEST_P(TypeValidationTest, BareOutputs) {
// return *();
// }
auto params = GetParam();
- Func(Source{{12, 34}}, "main", {}, params.create_ast_type(*this),
- {Return(Construct(params.create_ast_type(*this)))}, {Stage(ast::PipelineStage::kFragment)},
- {Location(0)});
+
+ Enable(ast::Extension::kF16);
+
+ Func(Source{{12, 34}}, "main", utils::Empty, params.create_ast_type(*this),
+ utils::Vector{
+ Return(Construct(params.create_ast_type(*this))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(0),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -395,9 +714,20 @@ TEST_P(TypeValidationTest, StructOutputs) {
// return Output();
// }
auto params = GetParam();
- auto* output = Structure("Output", {Member("a", params.create_ast_type(*this), {Location(0)})});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+
+ Enable(ast::Extension::kF16);
+
+ auto* output = Structure(
+ "Output", utils::Vector{
+ Member("a", params.create_ast_type(*this), utils::Vector{Location(0)}),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -419,8 +749,19 @@ TEST_F(LocationAttributeTests, Pass) {
// @fragment
// fn frag_main(@location(0) @interpolate(flat) a: i32) {}
- auto* p = Param(Source{{12, 34}}, "a", ty.i32(), {Location(0), Flat()});
- Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ auto* p = Param(Source{{12, 34}}, "a", ty.i32(),
+ utils::Vector{
+ Location(0),
+ Flat(),
+ });
+ Func("frag_main",
+ utils::Vector{
+ p,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -429,8 +770,18 @@ TEST_F(LocationAttributeTests, BadType_Input_bool) {
// @fragment
// fn frag_main(@location(0) a: bool) {}
- auto* p = Param(Source{{12, 34}}, "a", ty.bool_(), {Location(Source{{34, 56}}, 0)});
- Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ auto* p = Param(Source{{12, 34}}, "a", ty.bool_(),
+ utils::Vector{
+ Location(Source{{34, 56}}, 0),
+ });
+ Func("frag_main",
+ utils::Vector{
+ p,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -444,9 +795,16 @@ TEST_F(LocationAttributeTests, BadType_Output_Array) {
// @fragment
// fn frag_main()->@location(0) array<f32, 2> { return array<f32, 2>(); }
- Func(Source{{12, 34}}, "frag_main", {}, ty.array<f32, 2>(),
- {Return(Construct(ty.array<f32, 2>()))}, {Stage(ast::PipelineStage::kFragment)},
- {Location(Source{{34, 56}}, 0)});
+ Func(Source{{12, 34}}, "frag_main", utils::Empty, ty.array<f32, 2>(),
+ utils::Vector{
+ Return(Construct(ty.array<f32, 2>())),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(Source{{34, 56}}, 0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -462,9 +820,21 @@ TEST_F(LocationAttributeTests, BadType_Input_Struct) {
// };
// @fragment
// fn main(@location(0) param : Input) {}
- auto* input = Structure("Input", {Member("a", ty.f32())});
- auto* param = Param(Source{{12, 34}}, "param", ty.Of(input), {Location(Source{{13, 43}}, 0)});
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ auto* input = Structure("Input", utils::Vector{
+ Member("a", ty.f32()),
+ });
+ auto* param = Param(Source{{12, 34}}, "param", ty.Of(input),
+ utils::Vector{
+ Location(Source{{13, 43}}, 0),
+ });
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -483,10 +853,22 @@ TEST_F(LocationAttributeTests, BadType_Input_Struct_NestedStruct) {
// };
// @fragment
// fn main(param : Input) {}
- auto* inner = Structure("Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
- auto* input = Structure("Input", {Member(Source{{14, 52}}, "a", ty.Of(inner))});
+ auto* inner =
+ Structure("Inner", utils::Vector{
+ Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0)}),
+ });
+ auto* input = Structure("Input", utils::Vector{
+ Member(Source{{14, 52}}, "a", ty.Of(inner)),
+ });
auto* param = Param("param", ty.Of(input));
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -500,10 +882,19 @@ TEST_F(LocationAttributeTests, BadType_Input_Struct_RuntimeArray) {
// };
// @fragment
// fn main(param : Input) {}
- auto* input =
- Structure("Input", {Member(Source{{13, 43}}, "a", ty.array<f32>(), {Location(0)})});
+ auto* input = Structure(
+ "Input", utils::Vector{
+ Member(Source{{13, 43}}, "a", ty.array<f32>(), utils::Vector{Location(0)}),
+ });
auto* param = Param("param", ty.Of(input));
- Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -519,11 +910,20 @@ TEST_F(LocationAttributeTests, BadMemberType_Input) {
// fn frag_main( a: S) {}
auto* m = Member(Source{{34, 56}}, "m", ty.array<i32>(),
- ast::AttributeList{Location(Source{{12, 34}}, 0u)});
- auto* s = Structure("S", {m});
+ utils::Vector{
+ Location(Source{{12, 34}}, 0u),
+ });
+ auto* s = Structure("S", utils::Vector{m});
auto* p = Param("a", ty.Of(s));
- Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func("frag_main",
+ utils::Vector{
+ p,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -538,11 +938,19 @@ TEST_F(LocationAttributeTests, BadMemberType_Output) {
// @fragment
// fn frag_main() -> S {}
auto* m = Member(Source{{34, 56}}, "m", ty.atomic<i32>(),
- ast::AttributeList{Location(Source{{12, 34}}, 0u)});
- auto* s = Structure("S", {m});
-
- Func("frag_main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
- {Stage(ast::PipelineStage::kFragment)}, {});
+ utils::Vector{
+ Location(Source{{12, 34}}, 0u),
+ });
+ auto* s = Structure("S", utils::Vector{m});
+
+ Func("frag_main", utils::Empty, ty.Of(s),
+ utils::Vector{
+ Return(Construct(ty.Of(s))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ {});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -556,8 +964,10 @@ TEST_F(LocationAttributeTests, BadMemberType_Unused) {
// struct S { @location(0) m: mat3x2<f32>; };
auto* m = Member(Source{{34, 56}}, "m", ty.mat3x2<f32>(),
- ast::AttributeList{Location(Source{{12, 34}}, 0u)});
- Structure("S", {m});
+ utils::Vector{
+ Location(Source{{12, 34}}, 0u),
+ });
+ Structure("S", utils::Vector{m});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -576,11 +986,18 @@ TEST_F(LocationAttributeTests, ReturnType_Struct_Valid) {
// fn main() -> Output {
// return Output();
// }
- auto* output =
- Structure("Output", {Member("a", ty.f32(), {Location(0)}),
- Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* output = Structure(
+ "Output", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{Location(0)}),
+ Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -593,9 +1010,19 @@ TEST_F(LocationAttributeTests, ReturnType_Struct) {
// fn main() -> @location(0) Output {
// return Output();
// }
- auto* output = Structure("Output", {Member("a", ty.f32())});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kVertex)}, {Location(Source{{13, 43}}, 0)});
+ auto* output = Structure("Output", utils::Vector{
+ Member("a", ty.f32()),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Location(Source{{13, 43}}, 0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -614,10 +1041,20 @@ TEST_F(LocationAttributeTests, ReturnType_Struct_NestedStruct) {
// };
// @fragment
// fn main() -> Output { return Output(); }
- auto* inner = Structure("Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
- auto* output = Structure("Output", {Member(Source{{14, 52}}, "a", ty.Of(inner))});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* inner =
+ Structure("Inner", utils::Vector{
+ Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0)}),
+ });
+ auto* output = Structure("Output", utils::Vector{
+ Member(Source{{14, 52}}, "a", ty.Of(inner)),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -633,10 +1070,17 @@ TEST_F(LocationAttributeTests, ReturnType_Struct_RuntimeArray) {
// fn main() -> Output {
// return Output();
// }
- auto* output = Structure("Output", {Member(Source{{13, 43}}, "a", ty.array<f32>(),
- {Location(Source{{12, 34}}, 0)})});
- Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* output = Structure("Output", utils::Vector{
+ Member(Source{{13, 43}}, "a", ty.array<f32>(),
+ utils::Vector{Location(Source{{12, 34}}, 0)}),
+ });
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
+ utils::Vector{
+ Return(Construct(ty.Of(output))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -647,32 +1091,51 @@ TEST_F(LocationAttributeTests, ReturnType_Struct_RuntimeArray) {
}
TEST_F(LocationAttributeTests, ComputeShaderLocation_Input) {
- Func("main", {}, ty.i32(), {Return(Expr(1_i))},
- {Stage(ast::PipelineStage::kCompute),
- create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))},
- ast::AttributeList{Location(Source{{12, 34}}, 1)});
+ Func("main", utils::Empty, ty.i32(),
+ utils::Vector{
+ Return(Expr(1_i)),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
+ },
+ utils::Vector{
+ Location(Source{{12, 34}}, 1),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader output");
}
TEST_F(LocationAttributeTests, ComputeShaderLocation_Output) {
- auto* input = Param("input", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
- Func("main", {input}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute),
- create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
+ auto* input = Param("input", ty.i32(),
+ utils::Vector{
+ Location(Source{{12, 34}}, 0u),
+ });
+ Func("main", utils::Vector{input}, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader inputs");
}
TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
- auto* m = Member("m", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
- auto* s = Structure("S", {m});
- Func(Source{{56, 78}}, "main", {}, ty.Of(s),
- ast::StatementList{Return(Expr(Construct(ty.Of(s))))},
- {Stage(ast::PipelineStage::kCompute),
- create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
+ auto* m = Member("m", ty.i32(),
+ utils::Vector{
+ Location(Source{{12, 34}}, 0u),
+ });
+ auto* s = Structure("S", utils::Vector{m});
+ Func(Source{{56, 78}}, "main", utils::Empty, ty.Of(s),
+ utils::Vector{
+ Return(Expr(Construct(ty.Of(s)))),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -681,12 +1144,17 @@ TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
}
TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Input) {
- auto* m = Member("m", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
- auto* s = Structure("S", {m});
+ auto* m = Member("m", ty.i32(),
+ utils::Vector{
+ Location(Source{{12, 34}}, 0u),
+ });
+ auto* s = Structure("S", utils::Vector{m});
auto* input = Param("input", ty.Of(s));
- Func(Source{{56, 78}}, "main", {input}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute),
- create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
+ Func(Source{{56, 78}}, "main", utils::Vector{input}, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -698,10 +1166,23 @@ TEST_F(LocationAttributeTests, Duplicate_input) {
// @fragment
// fn main(@location(1) param_a : f32,
// @location(1) param_b : f32) {}
- auto* param_a = Param("param_a", ty.f32(), {Location(1)});
- auto* param_b = Param("param_b", ty.f32(), {Location(Source{{12, 34}}, 1)});
- Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ auto* param_a = Param("param_a", ty.f32(),
+ utils::Vector{
+ Location(1),
+ });
+ auto* param_b = Param("param_b", ty.f32(),
+ utils::Vector{
+ Location(Source{{12, 34}}, 1),
+ });
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param_a,
+ param_b,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: location(1) attribute appears multiple times");
@@ -716,12 +1197,24 @@ TEST_F(LocationAttributeTests, Duplicate_struct) {
// };
// @fragment
// fn main(param_a : InputA, param_b : InputB) {}
- auto* input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
- auto* input_b = Structure("InputB", {Member("a", ty.f32(), {Location(Source{{34, 56}}, 1)})});
+ auto* input_a = Structure("InputA", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{Location(1)}),
+ });
+ auto* input_b =
+ Structure("InputB", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{Location(Source{{34, 56}}, 1)}),
+ });
auto* param_a = Param("param_a", ty.Of(input_a));
auto* param_b = Param("param_b", ty.Of(input_b));
- Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{12, 34}}, "main",
+ utils::Vector{
+ param_a,
+ param_b,
+ },
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
diff --git a/chromium/third_party/dawn/src/tint/resolver/evaluation_stage_test.cc b/chromium/third_party/dawn/src/tint/resolver/evaluation_stage_test.cc
new file mode 100644
index 00000000000..4b603bb243c
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/resolver/evaluation_stage_test.cc
@@ -0,0 +1,297 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/resolver/resolver.h"
+
+#include "gmock/gmock.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+using ResolverEvaluationStageTest = ResolverTest;
+
+TEST_F(ResolverEvaluationStageTest, Literal_i32) {
+ auto* expr = Expr(123_i);
+ WrapInFunction(expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Literal_f32) {
+ auto* expr = Expr(123_f);
+ WrapInFunction(expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Vector_Ctor) {
+ auto* expr = vec3<f32>();
+ WrapInFunction(expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Vector_Ctor_Const_Const) {
+ // const f = 1.f;
+ // vec2<f32>(f, f);
+ auto* f = Const("f", nullptr, Expr(1_f));
+ auto* expr = vec2<f32>(f, f);
+ WrapInFunction(f, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Vector_Ctor_Runtime_Runtime) {
+ // var f = 1.f;
+ // vec2<f32>(f, f);
+ auto* f = Var("f", nullptr, Expr(1_f));
+ auto* expr = vec2<f32>(f, f);
+ WrapInFunction(f, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, Vector_Conv_Const) {
+ // const f = 1.f;
+ // vec2<u32>(vec2<f32>(f));
+ auto* f = Const("f", nullptr, Expr(1_f));
+ auto* expr = vec2<u32>(vec2<f32>(f));
+ WrapInFunction(f, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Vector_Conv_Runtime) {
+ // var f = 1.f;
+ // vec2<u32>(vec2<f32>(f));
+ auto* f = Var("f", nullptr, Expr(1_f));
+ auto* expr = vec2<u32>(vec2<f32>(f));
+ WrapInFunction(f, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, Matrix_Ctor) {
+ auto* expr = mat2x2<f32>();
+ WrapInFunction(expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Array_Ctor) {
+ auto* expr = array<f32, 3>();
+ WrapInFunction(expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Array_Ctor_Const_Const) {
+ // const f = 1.f;
+ // array<f32, 2>(f, f);
+ auto* f = Const("f", nullptr, Expr(1_f));
+ auto* expr = Construct(ty.array<f32, 2>(), f, f);
+ WrapInFunction(f, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Array_Ctor_Const_Override) {
+ // const f1 = 1.f;
+ // override f2 = 2.f;
+ // array<f32, 2>(f1, f2);
+ auto* f1 = Const("f1", nullptr, Expr(1_f));
+ auto* f2 = Override("f2", nullptr, Expr(2_f));
+ auto* expr = Construct(ty.array<f32, 2>(), f1, f2);
+ WrapInFunction(f1, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f1)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(f2)->Stage(), sem::EvaluationStage::kOverride);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kOverride);
+}
+
+TEST_F(ResolverEvaluationStageTest, Array_Ctor_Override_Runtime) {
+ // override f1 = 1.f;
+ // var f2 = 2.f;
+ // array<f32, 2>(f1, f2);
+ auto* f1 = Override("f1", nullptr, Expr(1_f));
+ auto* f2 = Var("f2", nullptr, Expr(2_f));
+ auto* expr = Construct(ty.array<f32, 2>(), f1, f2);
+ WrapInFunction(f2, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f1)->Stage(), sem::EvaluationStage::kOverride);
+ EXPECT_EQ(Sem().Get(f2)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, Array_Ctor_Const_Runtime) {
+ // const f1 = 1.f;
+ // var f2 = 2.f;
+ // array<f32, 2>(f1, f2);
+ auto* f1 = Const("f1", nullptr, Expr(1_f));
+ auto* f2 = Var("f2", nullptr, Expr(2_f));
+ auto* expr = Construct(ty.array<f32, 2>(), f1, f2);
+ WrapInFunction(f1, f2, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f1)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(f2)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, Array_Ctor_Runtime_Runtime) {
+ // var f = 1.f;
+ // array<f32, 2>(f, f);
+ auto* f = Var("f", nullptr, Expr(1_f));
+ auto* expr = Construct(ty.array<f32, 2>(), f, f);
+ WrapInFunction(f, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(f)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, IndexAccessor_Const_Const) {
+ // const vec = vec4<f32>();
+ // const idx = 1_i;
+ // vec[idx]
+ auto* vec = Const("vec", nullptr, vec4<f32>());
+ auto* idx = Const("idx", nullptr, Expr(1_i));
+ auto* expr = IndexAccessor(vec, idx);
+ WrapInFunction(vec, idx, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(vec)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(idx)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, IndexAccessor_Runtime_Const) {
+ // var vec = vec4<f32>();
+ // const idx = 1_i;
+ // vec[idx]
+ auto* vec = Var("vec", nullptr, vec4<f32>());
+ auto* idx = Const("idx", nullptr, Expr(1_i));
+ auto* expr = IndexAccessor(vec, idx);
+ WrapInFunction(vec, idx, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(vec)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(idx)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, IndexAccessor_Const_Override) {
+ // const vec = vec4<f32>();
+ // override idx = 1_i;
+ // vec[idx]
+ auto* vec = Const("vec", nullptr, vec4<f32>());
+ auto* idx = Override("idx", nullptr, Expr(1_i));
+ auto* expr = IndexAccessor(vec, idx);
+ WrapInFunction(vec, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(vec)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(idx)->Stage(), sem::EvaluationStage::kOverride);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kOverride);
+}
+
+TEST_F(ResolverEvaluationStageTest, IndexAccessor_Const_Runtime) {
+ // const vec = vec4<f32>();
+ // let idx = 1_i;
+ // vec[idx]
+ auto* vec = Const("vec", nullptr, vec4<f32>());
+ auto* idx = Let("idx", nullptr, Expr(1_i));
+ auto* expr = IndexAccessor(vec, idx);
+ WrapInFunction(vec, idx, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(vec)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(idx)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, Swizzle_Const) {
+ // const vec = S();
+ // vec.m
+ auto* vec = Const("vec", nullptr, vec4<f32>());
+ auto* expr = MemberAccessor(vec, "xz");
+ WrapInFunction(vec, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(vec)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, Swizzle_Runtime) {
+ // var vec = S();
+ // vec.m
+ auto* vec = Var("vec", nullptr, vec4<f32>());
+ auto* expr = MemberAccessor(vec, "rg");
+ WrapInFunction(vec, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(vec)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+TEST_F(ResolverEvaluationStageTest, MemberAccessor_Const) {
+ // struct S { m : i32 };
+ // const str = S();
+ // str.m
+ Structure("S", utils::Vector{Member("m", ty.i32())});
+ auto* str = Const("str", nullptr, Construct(ty.type_name("S")));
+ auto* expr = MemberAccessor(str, "m");
+ WrapInFunction(str, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(str)->Stage(), sem::EvaluationStage::kConstant);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kConstant);
+}
+
+TEST_F(ResolverEvaluationStageTest, MemberAccessor_Runtime) {
+ // struct S { m : i32 };
+ // var str = S();
+ // str.m
+ Structure("S", utils::Vector{Member("m", ty.i32())});
+ auto* str = Var("str", nullptr, Construct(ty.type_name("S")));
+ auto* expr = MemberAccessor(str, "m");
+ WrapInFunction(str, expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(Sem().Get(str)->Stage(), sem::EvaluationStage::kRuntime);
+ EXPECT_EQ(Sem().Get(expr)->Stage(), sem::EvaluationStage::kRuntime);
+}
+
+} // namespace
+} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/function_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/function_validation_test.cc
index cf8ddabb273..3c4a6ac496f 100644
--- a/chromium/third_party/dawn/src/tint/resolver/function_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/function_validation_test.cc
@@ -30,8 +30,8 @@ class ResolverFunctionValidationTest : public TestHelper, public testing::Test {
TEST_F(ResolverFunctionValidationTest, DuplicateParameterName) {
// fn func_a(common_name : f32) { }
// fn func_b(common_name : f32) { }
- Func("func_a", {Param("common_name", ty.f32())}, ty.void_(), {});
- Func("func_b", {Param("common_name", ty.f32())}, ty.void_(), {});
+ Func("func_a", utils::Vector{Param("common_name", ty.f32())}, ty.void_(), utils::Empty);
+ Func("func_b", utils::Vector{Param("common_name", ty.f32())}, ty.void_(), utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -39,8 +39,8 @@ TEST_F(ResolverFunctionValidationTest, DuplicateParameterName) {
TEST_F(ResolverFunctionValidationTest, ParameterMayShadowGlobal) {
// var<private> common_name : f32;
// fn func(common_name : f32) { }
- Global("common_name", ty.f32(), ast::StorageClass::kPrivate);
- Func("func", {Param("common_name", ty.f32())}, ty.void_(), {});
+ GlobalVar("common_name", ty.f32(), ast::StorageClass::kPrivate);
+ Func("func", utils::Vector{Param("common_name", ty.f32())}, ty.void_(), utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -49,8 +49,10 @@ TEST_F(ResolverFunctionValidationTest, LocalConflictsWithParameter) {
// fn func(common_name : f32) {
// let common_name = 1i;
// }
- Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
- {Decl(Let(Source{{56, 78}}, "common_name", nullptr, Expr(1_i)))});
+ Func("func", utils::Vector{Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
+ utils::Vector{
+ Decl(Let(Source{{56, 78}}, "common_name", nullptr, Expr(1_i))),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(56:78 error: redeclaration of 'common_name'
@@ -59,12 +61,14 @@ TEST_F(ResolverFunctionValidationTest, LocalConflictsWithParameter) {
TEST_F(ResolverFunctionValidationTest, NestedLocalMayShadowParameter) {
// fn func(common_name : f32) {
- // {
+ // utils::Vector {
// let common_name = 1i;
// }
// }
- Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
- {Block(Decl(Let(Source{{56, 78}}, "common_name", nullptr, Expr(1_i))))});
+ Func("func", utils::Vector{Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
+ utils::Vector{
+ Block(Decl(Let(Source{{56, 78}}, "common_name", nullptr, Expr(1_i)))),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -73,8 +77,8 @@ TEST_F(ResolverFunctionValidationTest, VoidFunctionEndWithoutReturnStatement_Pas
// fn func { var a:i32 = 2i; }
auto* var = Var("a", ty.i32(), Expr(2_i));
- Func(Source{{12, 34}}, "func", {}, ty.void_(),
- {
+ Func(Source{{12, 34}}, "func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
});
@@ -88,8 +92,8 @@ TEST_F(ResolverFunctionValidationTest, FunctionUsingSameVariableName_Pass) {
// }
auto* var = Var("func", ty.i32(), Expr(0_i));
- Func("func", {}, ty.i32(),
- {
+ Func("func", utils::Empty, ty.i32(),
+ utils::Vector{
Decl(var),
Return(Source{{12, 34}}, Expr("func")),
});
@@ -102,13 +106,13 @@ TEST_F(ResolverFunctionValidationTest, FunctionNameSameAsFunctionScopeVariableNa
// fn b() -> i32 { return 2; }
auto* var = Var("b", ty.i32(), Expr(0_i));
- Func("a", {}, ty.void_(),
- {
+ Func("a", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
});
- Func(Source{{12, 34}}, "b", {}, ty.i32(),
- {
+ Func(Source{{12, 34}}, "b", utils::Empty, ty.i32(),
+ utils::Vector{
Return(2_i),
});
@@ -126,7 +130,7 @@ TEST_F(ResolverFunctionValidationTest, UnreachableCode_return) {
auto* ret = Return();
auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
- Func("func", {}, ty.void_(), {decl_a, ret, assign_a});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{decl_a, ret, assign_a});
ASSERT_TRUE(r()->Resolve());
@@ -139,7 +143,7 @@ TEST_F(ResolverFunctionValidationTest, UnreachableCode_return) {
TEST_F(ResolverFunctionValidationTest, UnreachableCode_return_InBlocks) {
// fn func() -> {
// var a : i32;
- // {{{return;}}}
+ // utils::Vector {{{return;}}}
// a = 2i;
//}
@@ -147,7 +151,8 @@ TEST_F(ResolverFunctionValidationTest, UnreachableCode_return_InBlocks) {
auto* ret = Return();
auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
- Func("func", {}, ty.void_(), {decl_a, Block(Block(Block(ret))), assign_a});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{decl_a, Block(Block(Block(ret))), assign_a});
ASSERT_TRUE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
@@ -167,7 +172,7 @@ TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard) {
auto* discard = Discard();
auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
- Func("func", {}, ty.void_(), {decl_a, discard, assign_a});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{decl_a, discard, assign_a});
ASSERT_TRUE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
@@ -179,7 +184,7 @@ TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard) {
TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard_InBlocks) {
// fn func() -> {
// var a : i32;
- // {{{discard;}}}
+ // utils::Vector {{{discard;}}}
// a = 2i;
//}
@@ -187,7 +192,8 @@ TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard_InBlocks) {
auto* discard = Discard();
auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
- Func("func", {}, ty.void_(), {decl_a, Block(Block(Block(discard))), assign_a});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{decl_a, Block(Block(Block(discard))), assign_a});
ASSERT_TRUE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
@@ -201,8 +207,8 @@ TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatement_Fail) {
auto* var = Var("a", ty.i32(), Expr(2_i));
- Func(Source{{12, 34}}, "func", {}, ty.i32(),
- {
+ Func(Source{{12, 34}}, "func", utils::Empty, ty.i32(),
+ utils::Vector{
Decl(var),
});
@@ -213,7 +219,7 @@ TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatement_Fail) {
TEST_F(ResolverFunctionValidationTest, VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
// fn func {}
- Func(Source{{12, 34}}, "func", {}, ty.void_(), {});
+ Func(Source{{12, 34}}, "func", utils::Empty, ty.void_(), utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -221,7 +227,7 @@ TEST_F(ResolverFunctionValidationTest, VoidFunctionEndWithoutReturnStatementEmpt
TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
// fn func() -> int {}
- Func(Source{{12, 34}}, "func", {}, ty.i32(), {});
+ Func(Source{{12, 34}}, "func", utils::Empty, ty.i32(), utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
@@ -230,47 +236,62 @@ TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatementEmptyBod
TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_Pass) {
// fn func { return; }
- Func("func", {}, ty.void_(), {Return()});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverFunctionValidationTest, VoidFunctionReturnsAInt) {
// fn func { return 2; }
- Func("func", {}, ty.void_(), {Return(Source{{12, 34}}, Expr(2_a))});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(Source{{12, 34}}, Expr(2_a)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: return statement type must match its function return "
- "type, returned 'abstract-int', expected 'void'");
+ "12:34 error: return statement type must match its function return type, returned "
+ "'abstract-int', expected 'void'");
}
TEST_F(ResolverFunctionValidationTest, VoidFunctionReturnsAFloat) {
// fn func { return 2.0; }
- Func("func", {}, ty.void_(), {Return(Source{{12, 34}}, Expr(2.0_a))});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(Source{{12, 34}}, Expr(2.0_a)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: return statement type must match its function return "
- "type, returned 'abstract-float', expected 'void'");
+ "12:34 error: return statement type must match its function return type, returned "
+ "'abstract-float', expected 'void'");
}
TEST_F(ResolverFunctionValidationTest, VoidFunctionReturnsI32) {
// fn func { return 2i; }
- Func("func", {}, ty.void_(), {Return(Source{{12, 34}}, Expr(2_i))});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(Source{{12, 34}}, Expr(2_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: return statement type must match its function return "
- "type, returned 'i32', expected 'void'");
+ "12:34 error: return statement type must match its function return type, returned "
+ "'i32', expected 'void'");
}
TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_void_fail) {
// fn v { return; }
// fn func { return v(); }
- Func("v", {}, ty.void_(), {Return()});
- Func("func", {}, ty.void_(),
- {
+ Func("v", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(),
+ });
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(Call(Source{{12, 34}}, "v")),
});
@@ -280,21 +301,21 @@ TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_
TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeMissing_fail) {
// fn func() -> f32 { return; }
- Func("func", {}, ty.f32(),
- {
+ Func("func", utils::Empty, ty.f32(),
+ utils::Vector{
Return(Source{{12, 34}}, nullptr),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: return statement type must match its function return "
- "type, returned 'void', expected 'f32'");
+ "12:34 error: return statement type must match its function return type, returned "
+ "'void', expected 'f32'");
}
TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32_pass) {
// fn func() -> f32 { return 2.0; }
- Func("func", {}, ty.f32(),
- {
+ Func("func", utils::Empty, ty.f32(),
+ utils::Vector{
Return(Source{{12, 34}}, Expr(2_f)),
});
@@ -303,23 +324,23 @@ TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF
TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) {
// fn func() -> f32 { return 2i; }
- Func("func", {}, ty.f32(),
- {
+ Func("func", utils::Empty, ty.f32(),
+ utils::Vector{
Return(Source{{12, 34}}, Expr(2_i)),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: return statement type must match its function return "
- "type, returned 'i32', expected 'f32'");
+ "12:34 error: return statement type must match its function return type, returned "
+ "'i32', expected 'f32'");
}
TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32Alias_pass) {
// type myf32 = f32;
// fn func() -> myf32 { return 2.0; }
auto* myf32 = Alias("myf32", ty.f32());
- Func("func", {}, ty.Of(myf32),
- {
+ Func("func", utils::Empty, ty.Of(myf32),
+ utils::Vector{
Return(Source{{12, 34}}, Expr(2_f)),
});
@@ -330,43 +351,58 @@ TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF
// type myf32 = f32;
// fn func() -> myf32 { return 2u; }
auto* myf32 = Alias("myf32", ty.f32());
- Func("func", {}, ty.Of(myf32),
- {
+ Func("func", utils::Empty, ty.Of(myf32),
+ utils::Vector{
Return(Source{{12, 34}}, Expr(2_u)),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: return statement type must match its function return "
- "type, returned 'u32', expected 'f32'");
+ "12:34 error: return statement type must match its function return type, returned "
+ "'u32', expected 'f32'");
}
TEST_F(ResolverFunctionValidationTest, CannotCallEntryPoint) {
// @compute @workgroup_size(1) fn entrypoint() {}
// fn func() { return entrypoint(); }
- Func("entrypoint", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ Func("entrypoint", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
- Func("func", {}, ty.void_(),
- {
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call(Source{{12, 34}}, "entrypoint")),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
-
R"(12:34 error: entry point functions cannot be the target of a function call)");
}
+TEST_F(ResolverFunctionValidationTest, CannotCallFunctionAtModuleScope) {
+ // fn F() -> i32 { return 1; }
+ // var x = F();
+ Func("F", utils::Empty, ty.i32(),
+ utils::Vector{
+ Return(1_i),
+ });
+ GlobalVar("x", nullptr, Call(Source{{12, 34}}, "F"), ast::StorageClass::kPrivate);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(12:34 error: functions cannot be called at module-scope)");
+}
+
TEST_F(ResolverFunctionValidationTest, PipelineStage_MustBeUnique_Fail) {
// @fragment
// @vertex
// fn main() { return; }
- Func(Source{{12, 34}}, "main", {}, ty.void_(),
- {
+ Func(Source{{12, 34}}, "main", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
},
- ast::AttributeList{
+ utils::Vector{
Stage(Source{{12, 34}}, ast::PipelineStage::kVertex),
Stage(Source{{56, 78}}, ast::PipelineStage::kFragment),
});
@@ -378,8 +414,8 @@ TEST_F(ResolverFunctionValidationTest, PipelineStage_MustBeUnique_Fail) {
}
TEST_F(ResolverFunctionValidationTest, NoPipelineEntryPoints) {
- Func("vtx_func", {}, ty.void_(),
- {
+ Func("vtx_func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
});
@@ -394,7 +430,10 @@ TEST_F(ResolverFunctionValidationTest, FunctionVarInitWithParam) {
auto* bar = Param("bar", ty.f32());
auto* baz = Var("baz", ty.f32(), Expr("bar"));
- Func("foo", ast::VariableList{bar}, ty.void_(), {Decl(baz)});
+ Func("foo", utils::Vector{bar}, ty.void_(),
+ utils::Vector{
+ Decl(baz),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -407,30 +446,38 @@ TEST_F(ResolverFunctionValidationTest, FunctionConstInitWithParam) {
auto* bar = Param("bar", ty.f32());
auto* baz = Let("baz", ty.f32(), Expr("bar"));
- Func("foo", ast::VariableList{bar}, ty.void_(), {Decl(baz)});
+ Func("foo", utils::Vector{bar}, ty.void_(),
+ utils::Vector{
+ Decl(baz),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverFunctionValidationTest, FunctionParamsConst) {
- Func("foo", {Param(Sym("arg"), ty.i32())}, ty.void_(),
- {Assign(Expr(Source{{12, 34}}, "arg"), Expr(1_i)), Return()});
+ Func("foo", utils::Vector{Param(Sym("arg"), ty.i32())}, ty.void_(),
+ utils::Vector{
+ Assign(Expr(Source{{12, 34}}, "arg"), Expr(1_i)),
+ Return(),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: cannot assign to function parameter\nnote: 'arg' is "
- "declared here:");
+ "12:34 error: cannot assign to function parameter\nnote: 'arg' is declared here:");
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_ConstU32) {
- // let x = 4u;
- // let x = 8u;
+ // const x = 4u;
+ // const x = 8u;
// @compute @workgroup_size(x, y, 16u)
// fn main() {}
auto* x = GlobalConst("x", ty.u32(), Expr(4_u));
auto* y = GlobalConst("y", ty.u32(), Expr(8_u));
- auto* func = Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize("x", "y", 16_u)});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize("x", "y", 16_u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -442,16 +489,19 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_ConstU32) {
ASSERT_NE(sem_x, nullptr);
ASSERT_NE(sem_y, nullptr);
- EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_x));
- EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_y));
+ EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().Contains(sem_x));
+ EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().Contains(sem_y));
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_I32) {
// @compute @workgroup_size(1i, 2i, 3i)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_i, 2_i, 3_i)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, 1_i, 2_i, 3_i),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -460,8 +510,11 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_U32) {
// @compute @workgroup_size(1u, 2u, 3u)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_u, 2_u, 3_u)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, 1_u, 2_u, 3_u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -470,8 +523,11 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_I32_AInt) {
// @compute @workgroup_size(1, 2i, 3)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_a, 2_i, 3_a)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, 1_a, 2_i, 3_a),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -480,8 +536,11 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_U32_AInt) {
// @compute @workgroup_size(1u, 2, 3u)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_u, 2_a, 3_u)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, 1_u, 2_a, 3_u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -490,8 +549,11 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchType_U32) {
// @compute @workgroup_size(1u, 2, 3_i)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_u, 2_a, 3_i)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, 1_u, 2_a, 3_i),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -502,8 +564,11 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchType_I32) {
// @compute @workgroup_size(1_i, 2u, 3)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_i, 2_u, 3_a)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, 1_i, 2_u, 3_a),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -511,12 +576,15 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchType_I32) {
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch) {
- // let x = 64u;
+ // const x = 64u;
// @compute @workgroup_size(1i, x)
// fn main() {}
GlobalConst("x", ty.u32(), Expr(64_u));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_i, "x")});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, 1_i, "x"),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -524,28 +592,35 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch) {
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch2) {
- // let x = 64u;
- // let y = 32i;
+ // const x = 64u;
+ // const y = 32i;
// @compute @workgroup_size(x, y)
// fn main() {}
GlobalConst("x", ty.u32(), Expr(64_u));
GlobalConst("y", ty.i32(), Expr(32_i));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, "x", "y")});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, "x", "y"),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
}
+
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Mismatch_ConstU32) {
- // let x = 4u;
- // let x = 8u;
+ // const x = 4u;
+ // const x = 8u;
// @compute @workgroup_size(x, y, 16i)
// fn main() {}
GlobalConst("x", ty.u32(), Expr(4_u));
GlobalConst("y", ty.u32(), Expr(8_u));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, "x", "y", 16_i)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Source{{12, 34}}, "x", "y", 16_i),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -556,21 +631,27 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_BadType) {
// @compute @workgroup_size(64.0)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, 64_f))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, 64_f)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: workgroup_size argument must be either literal or "
- "module-scope constant of type i32 or u32");
+ "12:34 error: workgroup_size argument must be either a literal, constant, or "
+ "overridable of type abstract-integer, i32 or u32");
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Negative) {
// @compute @workgroup_size(-2i)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, -2_i))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, -2_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
@@ -580,58 +661,73 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Zero) {
// @compute @workgroup_size(0i)
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, 0_i))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, 0_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_BadType) {
- // let x = 64.0;
+ // const x = 64.0;
// @compute @workgroup_size(x)
// fn main() {}
GlobalConst("x", ty.f32(), Expr(64_f));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, "x")),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: workgroup_size argument must be either literal or "
- "module-scope constant of type i32 or u32");
+ "12:34 error: workgroup_size argument must be either a literal, constant, or "
+ "overridable of type abstract-integer, i32 or u32");
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Negative) {
- // let x = -2i;
+ // const x = -2i;
// @compute @workgroup_size(x)
// fn main() {}
GlobalConst("x", ty.i32(), Expr(-2_i));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, "x")),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Zero) {
- // let x = 0i;
+ // const x = 0i;
// @compute @workgroup_size(x)
// fn main() {}
GlobalConst("x", ty.i32(), Expr(0_i));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, "x")),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_NestedZeroValueConstructor) {
- // let x = i32(i32(i32()));
+ // const x = i32(i32(i32()));
// @compute @workgroup_size(x)
// fn main() {}
GlobalConst("x", ty.i32(), Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32()))));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, "x")),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
@@ -641,32 +737,37 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
// var<private> x = 64i;
// @compute @workgroup_size(x)
// fn main() {}
- Global("x", ty.i32(), ast::StorageClass::kPrivate, Expr(64_i));
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+ GlobalVar("x", ty.i32(), ast::StorageClass::kPrivate, Expr(64_i));
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Expr(Source{{12, 34}}, "x")),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: workgroup_size argument must be either literal or "
- "module-scope constant of type i32 or u32");
+ "12:34 error: workgroup_size argument must be either a literal, constant, or "
+ "overridable of type abstract-integer, i32 or u32");
}
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr) {
// @compute @workgroup_size(i32(1))
// fn main() {}
- Func("main", {}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(Construct(Source{{12, 34}}, ty.i32(), 1_i))});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(Construct(Source{{12, 34}}, ty.i32(), 1_i)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: workgroup_size argument must be either a literal or "
- "a module-scope constant");
+ "12:34 error: workgroup_size argument must be either a literal, constant, or "
+ "overridable of type abstract-integer, i32 or u32");
}
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
auto* ret_type = ty.pointer(Source{{12, 34}}, ty.i32(), ast::StorageClass::kFunction);
- Func("f", {}, ret_type, {});
+ Func("f", utils::Empty, ret_type, utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
@@ -674,7 +775,7 @@ TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_AtomicInt) {
auto* ret_type = ty.atomic(Source{{12, 34}}, ty.i32());
- Func("f", {}, ret_type, {});
+ Func("f", utils::Empty, ret_type, utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
@@ -682,16 +783,18 @@ TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_AtomicInt) {
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_ArrayOfAtomic) {
auto* ret_type = ty.array(Source{{12, 34}}, ty.atomic(ty.i32()), 10_u);
- Func("f", {}, ret_type, {});
+ Func("f", utils::Empty, ret_type, utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
}
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_StructOfAtomic) {
- Structure("S", {Member("m", ty.atomic(ty.i32()))});
+ Structure("S", utils::Vector{
+ Member("m", ty.atomic(ty.i32())),
+ });
auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
- Func("f", {}, ret_type, {});
+ Func("f", utils::Empty, ret_type, utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
@@ -699,49 +802,51 @@ TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_StructOfAtomic) {
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_RuntimeArray) {
auto* ret_type = ty.array(Source{{12, 34}}, ty.i32());
- Func("f", {}, ret_type, {});
+ Func("f", utils::Empty, ret_type, utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
}
TEST_F(ResolverFunctionValidationTest, ParameterStoreType_NonAtomicFree) {
- Structure("S", {Member("m", ty.atomic(ty.i32()))});
+ Structure("S", utils::Vector{
+ Member("m", ty.atomic(ty.i32())),
+ });
auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
- Func("f", ast::VariableList{bar}, ty.void_(), {});
+ Func("f", utils::Vector{bar}, ty.void_(), utils::Empty);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: store type of function parameter must be a "
- "constructible type");
+ EXPECT_EQ(r()->error(), "12:34 error: type of function parameter must be constructible");
}
TEST_F(ResolverFunctionValidationTest, ParameterSotreType_AtomicFree) {
- Structure("S", {Member("m", ty.i32())});
+ Structure("S", utils::Vector{
+ Member("m", ty.i32()),
+ });
auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
- Func("f", ast::VariableList{bar}, ty.void_(), {});
+ Func("f", utils::Vector{bar}, ty.void_(), utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverFunctionValidationTest, ParametersAtLimit) {
- ast::VariableList params;
+ utils::Vector<const ast::Parameter*, 256> params;
for (int i = 0; i < 255; i++) {
- params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
+ params.Push(Param("param_" + std::to_string(i), ty.i32()));
}
- Func(Source{{12, 34}}, "f", params, ty.void_(), {});
+ Func(Source{{12, 34}}, "f", params, ty.void_(), utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverFunctionValidationTest, ParametersOverLimit) {
- ast::VariableList params;
+ utils::Vector<const ast::Parameter*, 256> params;
for (int i = 0; i < 256; i++) {
- params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
+ params.Push(Param("param_" + std::to_string(i), ty.i32()));
}
- Func(Source{{12, 34}}, "f", params, ty.void_(), {});
+ Func(Source{{12, 34}}, "f", params, ty.void_(), utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: functions may declare at most 255 parameters");
@@ -750,8 +855,9 @@ TEST_F(ResolverFunctionValidationTest, ParametersOverLimit) {
TEST_F(ResolverFunctionValidationTest, ParameterVectorNoType) {
// fn f(p : vec3) {}
- Func(Source{{12, 34}}, "f", {Param("p", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))},
- ty.void_(), {});
+ Func(Source{{12, 34}}, "f",
+ utils::Vector{Param("p", create<ast::Vector>(Source{{12, 34}}, nullptr, 3u))}, ty.void_(),
+ utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
@@ -760,8 +866,9 @@ TEST_F(ResolverFunctionValidationTest, ParameterVectorNoType) {
TEST_F(ResolverFunctionValidationTest, ParameterMatrixNoType) {
// fn f(p : vec3) {}
- Func(Source{{12, 34}}, "f", {Param("p", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))},
- ty.void_(), {});
+ Func(Source{{12, 34}}, "f",
+ utils::Vector{Param("p", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3u, 3u))},
+ ty.void_(), utils::Empty);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
@@ -779,7 +886,7 @@ TEST_P(ResolverFunctionParameterValidationTest, StorageClass) {
auto& param = GetParam();
auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.storage_class);
auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
- Func("f", ast::VariableList{arg}, ty.void_(), {});
+ Func("f", utils::Vector{arg}, ty.void_(), utils::Empty);
if (param.should_pass) {
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -794,8 +901,8 @@ TEST_P(ResolverFunctionParameterValidationTest, StorageClass) {
INSTANTIATE_TEST_SUITE_P(ResolverTest,
ResolverFunctionParameterValidationTest,
testing::Values(TestParams{ast::StorageClass::kNone, false},
- TestParams{ast::StorageClass::kInput, false},
- TestParams{ast::StorageClass::kOutput, false},
+ TestParams{ast::StorageClass::kIn, false},
+ TestParams{ast::StorageClass::kOut, false},
TestParams{ast::StorageClass::kUniform, false},
TestParams{ast::StorageClass::kWorkgroup, true},
TestParams{ast::StorageClass::kHandle, false},
diff --git a/chromium/third_party/dawn/src/tint/resolver/host_shareable_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/host_shareable_validation_test.cc
index 01fbfb0a58c..d67a108eb11 100644
--- a/chromium/third_party/dawn/src/tint/resolver/host_shareable_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/host_shareable_validation_test.cc
@@ -24,13 +24,13 @@ namespace {
using ResolverHostShareableValidationTest = ResolverTest;
TEST_F(ResolverHostShareableValidationTest, BoolMember) {
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())});
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.bool_())});
- Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
@@ -38,17 +38,17 @@ TEST_F(ResolverHostShareableValidationTest, BoolMember) {
r()->error(),
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
12:34 note: while analysing structure member S.x
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
}
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())});
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.vec3<bool>())});
- Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
@@ -56,18 +56,18 @@ TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
r()->error(),
R"(56:78 error: Type 'vec3<bool>' cannot be used in storage class 'storage' as it is non-host-shareable
12:34 note: while analysing structure member S.x
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
}
TEST_F(ResolverHostShareableValidationTest, Aliases) {
auto* a1 = Alias("a1", ty.bool_());
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.Of(a1))});
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.Of(a1))});
auto* a2 = Alias("a2", ty.Of(s));
- Global(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
@@ -75,21 +75,21 @@ TEST_F(ResolverHostShareableValidationTest, Aliases) {
r()->error(),
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
12:34 note: while analysing structure member S.x
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
}
TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
- auto* i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
- auto* i2 = Structure("I2", {Member(Source{{3, 4}}, "y", ty.Of(i1))});
- auto* i3 = Structure("I3", {Member(Source{{5, 6}}, "z", ty.Of(i2))});
+ auto* i1 = Structure("I1", utils::Vector{Member(Source{{1, 2}}, "x", ty.bool_())});
+ auto* i2 = Structure("I2", utils::Vector{Member(Source{{3, 4}}, "y", ty.Of(i1))});
+ auto* i3 = Structure("I3", utils::Vector{Member(Source{{5, 6}}, "z", ty.Of(i2))});
- auto* s = Structure("S", {Member(Source{{7, 8}}, "m", ty.Of(i3))});
+ auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
- Global(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
@@ -100,35 +100,38 @@ TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
3:4 note: while analysing structure member I2.y
5:6 note: while analysing structure member I3.z
7:8 note: while analysing structure member S.m
-9:10 note: while instantiating variable g)");
+9:10 note: while instantiating 'var' g)");
}
TEST_F(ResolverHostShareableValidationTest, NoError) {
- auto* i1 = Structure("I1", {
- Member(Source{{1, 1}}, "x1", ty.f32()),
- Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
- Member(Source{{3, 1}}, "z1", ty.array<i32, 4>()),
+ Enable(ast::Extension::kF16);
+
+ auto* i1 = Structure("I1", utils::Vector{
+ Member(Source{{1, 1}}, "w1", ty.f32()),
+ Member(Source{{2, 1}}, "x1", ty.f32()),
+ Member(Source{{3, 1}}, "y1", ty.vec3<f32>()),
+ Member(Source{{4, 1}}, "z1", ty.array<i32, 4>()),
});
auto* a1 = Alias("a1", ty.Of(i1));
- auto* i2 = Structure("I2", {
- Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
- Member(Source{{5, 1}}, "y2", ty.Of(i1)),
+ auto* i2 = Structure("I2", utils::Vector{
+ Member(Source{{5, 1}}, "x2", ty.mat2x2<f32>()),
+ Member(Source{{6, 1}}, "w2", ty.mat3x4<f32>()),
+ Member(Source{{7, 1}}, "z2", ty.Of(i1)),
});
auto* a2 = Alias("a2", ty.Of(i2));
- auto* i3 = Structure("I3", {
+ auto* i3 = Structure("I3", utils::Vector{
Member(Source{{4, 1}}, "x3", ty.Of(a1)),
Member(Source{{5, 1}}, "y3", ty.Of(i2)),
Member(Source{{6, 1}}, "z3", ty.Of(a2)),
});
- auto* s = Structure("S", {Member(Source{{7, 8}}, "m", ty.Of(i3))});
+ auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
- Global(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
- WrapInFunction();
+ GlobalVar(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
diff --git a/chromium/third_party/dawn/src/tint/resolver/increment_decrement_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/increment_decrement_validation_test.cc
index e03352e97b9..a7e636fd65f 100644
--- a/chromium/third_party/dawn/src/tint/resolver/increment_decrement_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/increment_decrement_validation_test.cc
@@ -127,7 +127,7 @@ TEST_F(ResolverIncrementDecrementValidationTest, Vector) {
TEST_F(ResolverIncrementDecrementValidationTest, Atomic) {
// var<workgroup> a : atomic<i32>;
// a++;
- Global(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
+ GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
WrapInFunction(Increment(Expr(Source{{56, 78}}, "a")));
EXPECT_FALSE(r()->Resolve());
@@ -151,7 +151,7 @@ TEST_F(ResolverIncrementDecrementValidationTest, Constant) {
WrapInFunction(a, Increment(Expr(Source{{56, 78}}, "a")));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify constant value
+ EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify 'let'
12:34 note: 'a' is declared here:)");
}
@@ -161,7 +161,10 @@ TEST_F(ResolverIncrementDecrementValidationTest, Parameter) {
// a++;
// }
auto* a = Param(Source{{12, 34}}, "a", ty.i32());
- Func("func", {a}, ty.void_(), {Increment(Expr(Source{{56, 78}}, "a"))});
+ Func("func", utils::Vector{a}, ty.void_(),
+ utils::Vector{
+ Increment(Expr(Source{{56, 78}}, "a")),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify function parameter
@@ -175,7 +178,10 @@ TEST_F(ResolverIncrementDecrementValidationTest, ReturnValue) {
// {
// a++;
// }
- Func("func", {}, ty.i32(), {Return(0_i)});
+ Func("func", utils::Empty, ty.i32(),
+ utils::Vector{
+ Return(0_i),
+ });
WrapInFunction(Increment(Call(Source{{56, 78}}, "func")));
EXPECT_FALSE(r()->Resolve());
@@ -187,8 +193,8 @@ TEST_F(ResolverIncrementDecrementValidationTest, ReadOnlyBuffer) {
// {
// a++;
// }
- Global(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
WrapInFunction(Increment(Source{{56, 78}}, "a"));
EXPECT_FALSE(r()->Resolve());
diff --git a/chromium/third_party/dawn/src/tint/resolver/inferred_type_test.cc b/chromium/third_party/dawn/src/tint/resolver/inferred_type_test.cc
index d8cc649ffa8..4051d82a0ec 100644
--- a/chromium/third_party/dawn/src/tint/resolver/inferred_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/inferred_type_test.cc
@@ -75,30 +75,30 @@ Params all_cases[] = {
using ResolverInferredTypeParamTest = ResolverTestWithParam<Params>;
-TEST_P(ResolverInferredTypeParamTest, GlobalLet_Pass) {
+TEST_P(ResolverInferredTypeParamTest, GlobalConst_Pass) {
auto& params = GetParam();
auto* expected_type = params.create_expected_type(*this);
- // let a = <type constructor>;
+ // const a = <type constructor>;
auto* ctor_expr = params.create_value(*this, 0);
- auto* var = GlobalConst("a", nullptr, ctor_expr);
- WrapInFunction();
+ auto* a = GlobalConst("a", nullptr, ctor_expr);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(TypeOf(var), expected_type);
+ EXPECT_EQ(TypeOf(a), expected_type);
}
-TEST_P(ResolverInferredTypeParamTest, GlobalVar_Fail) {
+TEST_P(ResolverInferredTypeParamTest, GlobalVar_Pass) {
auto& params = GetParam();
+ auto* expected_type = params.create_expected_type(*this);
+
// var a = <type constructor>;
auto* ctor_expr = params.create_value(*this, 0);
- Global(Source{{12, 34}}, "a", nullptr, ast::StorageClass::kPrivate, ctor_expr);
- WrapInFunction();
+ auto* var = GlobalVar("a", nullptr, ast::StorageClass::kPrivate, ctor_expr);
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: global var declaration must specify a type");
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
}
TEST_P(ResolverInferredTypeParamTest, LocalLet_Pass) {
@@ -145,7 +145,7 @@ TEST_F(ResolverInferredTypeTest, InferArray_Pass) {
TEST_F(ResolverInferredTypeTest, InferStruct_Pass) {
auto* member = Member("x", ty.i32());
- auto* str = Structure("S", {member});
+ auto* str = Structure("S", utils::Vector{member});
auto* expected_type =
create<sem::Struct>(str, str->name,
diff --git a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.cc b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.cc
index eb8f30e47a8..67a75c3a37a 100644
--- a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.cc
@@ -19,6 +19,7 @@
#include <unordered_map>
#include <utility>
+#include "src/tint/ast/binary_expression.h"
#include "src/tint/program_builder.h"
#include "src/tint/sem/abstract_float.h"
#include "src/tint/sem/abstract_int.h"
@@ -47,6 +48,12 @@ class Matchers;
class NumberMatcher;
class TypeMatcher;
+/// The utils::Vector `N` template argument value for arrays of parameters.
+constexpr static const size_t kNumFixedParams = 8;
+
+/// The utils::Vector `N` template argument value for arrays of overload candidates.
+constexpr static const size_t kNumFixedCandidates = 8;
+
/// A special type that matches all TypeMatchers
class Any final : public Castable<Any, sem::Type> {
public:
@@ -116,17 +123,17 @@ class TemplateState {
/// If none of the above applies, then `ty` is a type mismatch for the template type, and
/// nullptr is returned.
const sem::Type* Type(size_t idx, const sem::Type* ty) {
- auto res = types_.emplace(idx, ty);
- if (res.second) {
- return ty;
+ if (idx >= types_.Length()) {
+ types_.Resize(idx + 1);
}
- auto* existing = res.first->second;
- if (existing == ty) {
+ auto& t = types_[idx];
+ if (t == nullptr) {
+ t = ty;
return ty;
}
- ty = sem::Type::Common({existing, ty});
+ ty = sem::Type::Common(utils::Vector{t, ty});
if (ty) {
- res.first->second = ty;
+ t = ty;
}
return ty;
}
@@ -135,28 +142,44 @@ class TemplateState {
/// Num() returns true. If the number is defined, then `Num()` returns true iff it is equal to
/// `ty`.
bool Num(size_t idx, Number number) {
- auto res = numbers_.emplace(idx, number.Value());
- return res.second || res.first->second == number.Value();
+ if (idx >= numbers_.Length()) {
+ numbers_.Resize(idx + 1, Number::invalid);
+ }
+ auto& n = numbers_[idx];
+ if (!n.IsValid()) {
+ n = number.Value();
+ return true;
+ }
+ return n.Value() == number.Value();
}
/// Type returns the template type with index `idx`, or nullptr if the type was not defined.
const sem::Type* Type(size_t idx) const {
- auto it = types_.find(idx);
- return (it != types_.end()) ? it->second : nullptr;
+ if (idx >= types_.Length()) {
+ return nullptr;
+ }
+ return types_[idx];
}
/// SetType replaces the template type with index `idx` with type `ty`.
- void SetType(size_t idx, const sem::Type* ty) { types_[idx] = ty; }
+ void SetType(size_t idx, const sem::Type* ty) {
+ if (idx >= types_.Length()) {
+ types_.Resize(idx + 1);
+ }
+ types_[idx] = ty;
+ }
/// Type returns the number type with index `idx`.
Number Num(size_t idx) const {
- auto it = numbers_.find(idx);
- return (it != numbers_.end()) ? Number(it->second) : Number::invalid;
+ if (idx >= numbers_.Length()) {
+ return Number::invalid;
+ }
+ return numbers_[idx];
}
private:
- std::unordered_map<size_t, const sem::Type*> types_;
- std::unordered_map<size_t, uint32_t> numbers_;
+ utils::Vector<const sem::Type*, 4> types_;
+ utils::Vector<Number, 2> numbers_;
};
/// Index type used for matcher indices
@@ -321,19 +344,19 @@ bool match_bool(const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::Bool>();
}
-const sem::AbstractFloat* build_af(MatchState& state) {
+const sem::AbstractFloat* build_fa(MatchState& state) {
return state.builder.create<sem::AbstractFloat>();
}
-bool match_af(const sem::Type* ty) {
+bool match_fa(const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::AbstractFloat>();
}
-const sem::AbstractInt* build_ai(MatchState& state) {
+const sem::AbstractInt* build_ia(MatchState& state) {
return state.builder.create<sem::AbstractInt>();
}
-bool match_ai(const sem::Type* ty) {
+bool match_ia(const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::AbstractInt>();
}
@@ -341,6 +364,14 @@ const sem::Bool* build_bool(MatchState& state) {
return state.builder.create<sem::Bool>();
}
+const sem::F16* build_f16(MatchState& state) {
+ return state.builder.create<sem::F16>();
+}
+
+bool match_f16(const sem::Type* ty) {
+ return ty->IsAnyOf<Any, sem::F16, sem::AbstractNumeric>();
+}
+
const sem::F32* build_f32(MatchState& state) {
return state.builder.create<sem::F32>();
}
@@ -701,24 +732,34 @@ const sem::ExternalTexture* build_texture_external(MatchState& state) {
// Builtin types starting with a _ prefix cannot be declared in WGSL, so they
// can only be used as return types. Because of this, they must only match Any,
// which is used as the return type matcher.
-bool match_modf_result(const sem::Type* ty) {
- return ty->Is<Any>();
+bool match_modf_result(const sem::Type* ty, const sem::Type*& T) {
+ if (!ty->Is<Any>()) {
+ return false;
+ }
+ T = ty;
+ return true;
}
-bool match_modf_result_vec(const sem::Type* ty, Number& N) {
+bool match_modf_result_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
if (!ty->Is<Any>()) {
return false;
}
N = Number::any;
+ T = ty;
return true;
}
-bool match_frexp_result(const sem::Type* ty) {
- return ty->Is<Any>();
+bool match_frexp_result(const sem::Type* ty, const sem::Type*& T) {
+ if (!ty->Is<Any>()) {
+ return false;
+ }
+ T = ty;
+ return true;
}
-bool match_frexp_result_vec(const sem::Type* ty, Number& N) {
+bool match_frexp_result_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
if (!ty->Is<Any>()) {
return false;
}
N = Number::any;
+ T = ty;
return true;
}
@@ -732,7 +773,7 @@ bool match_atomic_compare_exchange_result(const sem::Type* ty, const sem::Type*&
struct NameAndType {
std::string name;
- sem::Type* type;
+ const sem::Type* type;
};
const sem::Struct* build_struct(MatchState& state,
std::string name,
@@ -766,27 +807,46 @@ const sem::Struct* build_struct(MatchState& state,
/* size_no_padding */ size_without_padding);
}
-const sem::Struct* build_modf_result(MatchState& state) {
- auto* f32 = state.builder.create<sem::F32>();
- return build_struct(state, "__modf_result", {{"fract", f32}, {"whole", f32}});
+const sem::Struct* build_modf_result(MatchState& state, const sem::Type* el) {
+ std::string display_name;
+ if (el->Is<sem::F16>()) {
+ display_name = "__modf_result_f16";
+ } else {
+ display_name = "__modf_result";
+ }
+ return build_struct(state, display_name, {{"fract", el}, {"whole", el}});
}
-const sem::Struct* build_modf_result_vec(MatchState& state, Number& n) {
- auto* vec_f32 = state.builder.create<sem::Vector>(state.builder.create<sem::F32>(), n.Value());
- return build_struct(state, "__modf_result_vec" + std::to_string(n.Value()),
- {{"fract", vec_f32}, {"whole", vec_f32}});
+const sem::Struct* build_modf_result_vec(MatchState& state, Number& n, const sem::Type* el) {
+ std::string display_name;
+ if (el->Is<sem::F16>()) {
+ display_name = "__modf_result_vec" + std::to_string(n.Value()) + "_f16";
+ } else {
+ display_name = "__modf_result_vec" + std::to_string(n.Value());
+ }
+ auto* vec = state.builder.create<sem::Vector>(el, n.Value());
+ return build_struct(state, display_name, {{"fract", vec}, {"whole", vec}});
}
-const sem::Struct* build_frexp_result(MatchState& state) {
- auto* f32 = state.builder.create<sem::F32>();
+const sem::Struct* build_frexp_result(MatchState& state, const sem::Type* el) {
+ std::string display_name;
+ if (el->Is<sem::F16>()) {
+ display_name = "__frexp_result_f16";
+ } else {
+ display_name = "__frexp_result";
+ }
auto* i32 = state.builder.create<sem::I32>();
- return build_struct(state, "__frexp_result", {{"sig", f32}, {"exp", i32}});
+ return build_struct(state, display_name, {{"sig", el}, {"exp", i32}});
}
-const sem::Struct* build_frexp_result_vec(MatchState& state, Number& n) {
- auto* vec_f32 = state.builder.create<sem::Vector>(state.builder.create<sem::F32>(), n.Value());
+const sem::Struct* build_frexp_result_vec(MatchState& state, Number& n, const sem::Type* el) {
+ std::string display_name;
+ if (el->Is<sem::F16>()) {
+ display_name = "__frexp_result_vec" + std::to_string(n.Value()) + "_f16";
+ } else {
+ display_name = "__frexp_result_vec" + std::to_string(n.Value());
+ }
+ auto* vec = state.builder.create<sem::Vector>(el, n.Value());
auto* vec_i32 = state.builder.create<sem::Vector>(state.builder.create<sem::I32>(), n.Value());
- return build_struct(state, "__frexp_result_vec" + std::to_string(n.Value()),
- {{"sig", vec_f32}, {"exp", vec_i32}});
+ return build_struct(state, display_name, {{"sig", vec}, {"exp", vec_i32}});
}
-
const sem::Struct* build_atomic_compare_exchange_result(MatchState& state, const sem::Type* ty) {
return build_struct(
state, "__atomic_compare_exchange_result" + ty->FriendlyName(state.builder.Symbols()),
@@ -845,7 +905,7 @@ struct OverloadInfo {
/// The flags for the overload
OverloadFlags flags;
/// The function used to evaluate the overload at shader-creation time.
- const_eval::Function* const const_eval_fn;
+ ConstEval::Function const const_eval_fn;
};
/// IntrinsicInfo describes a builtin function or operator overload
@@ -873,7 +933,7 @@ struct IntrinsicPrototype {
/// @param i the IntrinsicPrototype to create a hash for
/// @return the hash value
inline std::size_t operator()(const IntrinsicPrototype& i) const {
- size_t hash = utils::Hash(i.parameters.size());
+ size_t hash = utils::Hash(i.parameters.Length());
for (auto& p : i.parameters) {
utils::HashCombine(&hash, p.type, p.usage);
}
@@ -883,16 +943,16 @@ struct IntrinsicPrototype {
const OverloadInfo* overload = nullptr;
sem::Type const* return_type = nullptr;
- std::vector<Parameter> parameters;
+ utils::Vector<Parameter, kNumFixedParams> parameters;
};
/// Equality operator for IntrinsicPrototype
bool operator==(const IntrinsicPrototype& a, const IntrinsicPrototype& b) {
if (a.overload != b.overload || a.return_type != b.return_type ||
- a.parameters.size() != b.parameters.size()) {
+ a.parameters.Length() != b.parameters.Length()) {
return false;
}
- for (size_t i = 0; i < a.parameters.size(); i++) {
+ for (size_t i = 0; i < a.parameters.Length(); i++) {
auto& pa = a.parameters[i];
auto& pb = b.parameters[i];
if (pa.type != pb.type || pa.usage != pb.usage) {
@@ -908,7 +968,7 @@ class Impl : public IntrinsicTable {
explicit Impl(ProgramBuilder& builder);
Builtin Lookup(sem::BuiltinType builtin_type,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
const Source& source) override;
UnaryOperator Lookup(ast::UnaryOp op, const sem::Type* arg, const Source& source) override;
@@ -919,10 +979,10 @@ class Impl : public IntrinsicTable {
const Source& source,
bool is_compound) override;
- const sem::CallTarget* Lookup(CtorConvIntrinsic type,
- const sem::Type* template_arg,
- const std::vector<const sem::Type*>& args,
- const Source& source) override;
+ CtorOrConv Lookup(CtorConvIntrinsic type,
+ const sem::Type* template_arg,
+ utils::VectorRef<const sem::Type*> args,
+ const Source& source) override;
private:
/// Candidate holds information about an overload evaluated for resolution.
@@ -932,7 +992,7 @@ class Impl : public IntrinsicTable {
/// The template types and numbers
TemplateState templates;
/// The parameter types for the candidate overload
- std::vector<IntrinsicPrototype::Parameter> parameters;
+ utils::Vector<IntrinsicPrototype::Parameter, kNumFixedParams> parameters;
/// The match-score of the candidate overload.
/// A score of zero indicates an exact match.
/// Non-zero scores are used for diagnostics when no overload matches.
@@ -941,10 +1001,10 @@ class Impl : public IntrinsicTable {
};
/// A list of candidates
- using Candidates = std::vector<Candidate>;
+ using Candidates = utils::Vector<Candidate, kNumFixedCandidates>;
/// Callback function when no overloads match.
- using OnNoMatch = std::function<void(Candidates)>;
+ using OnNoMatch = std::function<void(utils::VectorRef<Candidate>)>;
/// Sorts the candidates based on their score, with the lowest (best-ranking) scores first.
static inline void SortCandidates(Candidates& candidates) {
@@ -966,7 +1026,7 @@ class Impl : public IntrinsicTable {
/// IntrinsicPrototype::return_type.
IntrinsicPrototype MatchIntrinsic(const IntrinsicInfo& intrinsic,
const char* intrinsic_name,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates,
OnNoMatch on_no_match) const;
@@ -978,7 +1038,7 @@ class Impl : public IntrinsicTable {
/// template as `f32`.
/// @returns the evaluated Candidate information.
Candidate ScoreOverload(const OverloadInfo* overload,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates) const;
/// Performs overload resolution given the list of candidates, by ranking the conversions of
@@ -993,7 +1053,7 @@ class Impl : public IntrinsicTable {
/// @returns the resolved Candidate.
Candidate ResolveCandidate(Candidates&& candidates,
const char* intrinsic_name,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates) const;
/// Match constructs a new MatchState
@@ -1011,14 +1071,14 @@ class Impl : public IntrinsicTable {
// Prints the list of candidates for emitting diagnostics
void PrintCandidates(std::ostream& ss,
- const Candidates& candidates,
+ utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const;
/// Raises an error when no overload is a clear winner of overload resolution
void ErrAmbiguousOverload(const char* intrinsic_name,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates,
- Candidates candidates) const;
+ utils::VectorRef<Candidate> candidates) const;
ProgramBuilder& builder;
Matchers matchers;
@@ -1033,7 +1093,7 @@ class Impl : public IntrinsicTable {
/// types.
std::string CallSignature(ProgramBuilder& builder,
const char* intrinsic_name,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
const sem::Type* template_arg = nullptr) {
std::stringstream ss;
ss << intrinsic_name;
@@ -1067,18 +1127,18 @@ std::string TemplateNumberMatcher::String(MatchState* state) const {
Impl::Impl(ProgramBuilder& b) : builder(b) {}
Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
const Source& source) {
const char* intrinsic_name = sem::str(builtin_type);
// Generates an error when no overloads match the provided arguments
- auto on_no_match = [&](Candidates candidates) {
+ auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
std::stringstream ss;
ss << "no matching call to " << CallSignature(builder, intrinsic_name, args) << std::endl;
- if (!candidates.empty()) {
+ if (!candidates.IsEmpty()) {
ss << std::endl
- << candidates.size() << " candidate function" << (candidates.size() > 1 ? "s:" : ":")
- << std::endl;
+ << candidates.Length() << " candidate function"
+ << (candidates.Length() > 1 ? "s:" : ":") << std::endl;
PrintCandidates(ss, candidates, intrinsic_name);
}
builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
@@ -1093,11 +1153,11 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
// De-duplicate builtins that are identical.
auto* sem = utils::GetOrCreate(builtins, match, [&] {
- std::vector<sem::Parameter*> params;
- params.reserve(match.parameters.size());
+ utils::Vector<sem::Parameter*, kNumFixedParams> params;
+ params.Reserve(match.parameters.Length());
for (auto& p : match.parameters) {
- params.emplace_back(builder.create<sem::Parameter>(
- nullptr, static_cast<uint32_t>(params.size()), p.type, ast::StorageClass::kNone,
+ params.Push(builder.create<sem::Parameter>(
+ nullptr, static_cast<uint32_t>(params.Length()), p.type, ast::StorageClass::kNone,
ast::Access::kUndefined, p.usage));
}
sem::PipelineStageSet supported_stages;
@@ -1110,8 +1170,10 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
if (match.overload->flags.Contains(OverloadFlag::kSupportsComputePipeline)) {
supported_stages.Add(ast::PipelineStage::kCompute);
}
+ auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
+ : sem::EvaluationStage::kRuntime;
return builder.create<sem::Builtin>(
- builtin_type, match.return_type, std::move(params), supported_stages,
+ builtin_type, match.return_type, std::move(params), eval_stage, supported_stages,
match.overload->flags.Contains(OverloadFlag::kIsDeprecated));
});
return Builtin{sem, match.overload->const_eval_fn};
@@ -1133,27 +1195,33 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
}
}();
+ utils::Vector args{arg};
+
// Generates an error when no overloads match the provided arguments
- auto on_no_match = [&, name = intrinsic_name](Candidates candidates) {
+ auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) {
std::stringstream ss;
- ss << "no matching overload for " << CallSignature(builder, name, {arg}) << std::endl;
- if (!candidates.empty()) {
+ ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl;
+ if (!candidates.IsEmpty()) {
ss << std::endl
- << candidates.size() << " candidate operator" << (candidates.size() > 1 ? "s:" : ":")
- << std::endl;
+ << candidates.Length() << " candidate operator"
+ << (candidates.Length() > 1 ? "s:" : ":") << std::endl;
PrintCandidates(ss, candidates, name);
}
builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
};
// Resolve the intrinsic overload
- auto match = MatchIntrinsic(kUnaryOperators[intrinsic_index], intrinsic_name, {arg},
+ auto match = MatchIntrinsic(kUnaryOperators[intrinsic_index], intrinsic_name, args,
TemplateState{}, on_no_match);
if (!match.overload) {
return {};
}
- return UnaryOperator{match.return_type, match.parameters[0].type};
+ return UnaryOperator{
+ match.return_type,
+ match.parameters[0].type,
+ match.overload->const_eval_fn,
+ };
}
IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
@@ -1204,57 +1272,64 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
}
}();
+ utils::Vector args{lhs, rhs};
+
// Generates an error when no overloads match the provided arguments
- auto on_no_match = [&, name = intrinsic_name](Candidates candidates) {
+ auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) {
std::stringstream ss;
- ss << "no matching overload for " << CallSignature(builder, name, {lhs, rhs}) << std::endl;
- if (!candidates.empty()) {
+ ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl;
+ if (!candidates.IsEmpty()) {
ss << std::endl
- << candidates.size() << " candidate operator" << (candidates.size() > 1 ? "s:" : ":")
- << std::endl;
+ << candidates.Length() << " candidate operator"
+ << (candidates.Length() > 1 ? "s:" : ":") << std::endl;
PrintCandidates(ss, candidates, name);
}
builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
};
// Resolve the intrinsic overload
- auto match = MatchIntrinsic(kBinaryOperators[intrinsic_index], intrinsic_name, {lhs, rhs},
+ auto match = MatchIntrinsic(kBinaryOperators[intrinsic_index], intrinsic_name, args,
TemplateState{}, on_no_match);
if (!match.overload) {
return {};
}
- return BinaryOperator{match.return_type, match.parameters[0].type, match.parameters[1].type};
+ return BinaryOperator{
+ match.return_type,
+ match.parameters[0].type,
+ match.parameters[1].type,
+ match.overload->const_eval_fn,
+ };
}
-const sem::CallTarget* Impl::Lookup(CtorConvIntrinsic type,
- const sem::Type* template_arg,
- const std::vector<const sem::Type*>& args,
- const Source& source) {
+IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
+ const sem::Type* template_arg,
+ utils::VectorRef<const sem::Type*> args,
+ const Source& source) {
auto name = str(type);
// Generates an error when no overloads match the provided arguments
- auto on_no_match = [&](Candidates candidates) {
+ auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
std::stringstream ss;
ss << "no matching constructor for " << CallSignature(builder, name, args, template_arg)
<< std::endl;
Candidates ctor, conv;
for (auto candidate : candidates) {
if (candidate.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
- ctor.emplace_back(candidate);
+ ctor.Push(candidate);
} else {
- conv.emplace_back(candidate);
+ conv.Push(candidate);
}
}
- if (!ctor.empty()) {
+ if (!ctor.IsEmpty()) {
ss << std::endl
- << ctor.size() << " candidate constructor" << (ctor.size() > 1 ? "s:" : ":")
+ << ctor.Length() << " candidate constructor" << (ctor.Length() > 1 ? "s:" : ":")
<< std::endl;
PrintCandidates(ss, ctor, name);
}
- if (!conv.empty()) {
+ if (!conv.IsEmpty()) {
ss << std::endl
- << conv.size() << " candidate conversion" << (conv.size() > 1 ? "s:" : ":")
+ << conv.Length() << " candidate conversion" << (conv.Length() > 1 ? "s:" : ":")
<< std::endl;
PrintCandidates(ss, conv, name);
}
@@ -1276,36 +1351,43 @@ const sem::CallTarget* Impl::Lookup(CtorConvIntrinsic type,
// Was this overload a constructor or conversion?
if (match.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
- sem::ParameterList params;
- params.reserve(match.parameters.size());
+ utils::Vector<const sem::Parameter*, 8> params;
+ params.Reserve(match.parameters.Length());
for (auto& p : match.parameters) {
- params.emplace_back(builder.create<sem::Parameter>(
- nullptr, static_cast<uint32_t>(params.size()), p.type, ast::StorageClass::kNone,
+ params.Push(builder.create<sem::Parameter>(
+ nullptr, static_cast<uint32_t>(params.Length()), p.type, ast::StorageClass::kNone,
ast::Access::kUndefined, p.usage));
}
- return utils::GetOrCreate(constructors, match, [&]() {
- return builder.create<sem::TypeConstructor>(match.return_type, std::move(params));
+ auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
+ : sem::EvaluationStage::kRuntime;
+ auto* target = utils::GetOrCreate(constructors, match, [&]() {
+ return builder.create<sem::TypeConstructor>(match.return_type, std::move(params),
+ eval_stage);
});
+ return CtorOrConv{target, match.overload->const_eval_fn};
}
// Conversion.
- return utils::GetOrCreate(converters, match, [&]() {
+ auto* target = utils::GetOrCreate(converters, match, [&]() {
auto param = builder.create<sem::Parameter>(
- nullptr, 0, match.parameters[0].type, ast::StorageClass::kNone, ast::Access::kUndefined,
- match.parameters[0].usage);
- return builder.create<sem::TypeConversion>(match.return_type, param);
+ nullptr, 0u, match.parameters[0].type, ast::StorageClass::kNone,
+ ast::Access::kUndefined, match.parameters[0].usage);
+ auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
+ : sem::EvaluationStage::kRuntime;
+ return builder.create<sem::TypeConversion>(match.return_type, param, eval_stage);
});
+ return CtorOrConv{target, match.overload->const_eval_fn};
}
IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
const char* intrinsic_name,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates,
OnNoMatch on_no_match) const {
size_t num_matched = 0;
size_t match_idx = 0;
- Candidates candidates;
- candidates.reserve(intrinsic.num_overloads);
+ utils::Vector<Candidate, kNumFixedCandidates> candidates;
+ candidates.Reserve(intrinsic.num_overloads);
for (size_t overload_idx = 0; overload_idx < static_cast<size_t>(intrinsic.num_overloads);
overload_idx++) {
auto candidate = ScoreOverload(&intrinsic.overloads[overload_idx], args, templates);
@@ -1313,7 +1395,7 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
match_idx = overload_idx;
num_matched++;
}
- candidates.emplace_back(std::move(candidate));
+ candidates.Push(std::move(candidate));
}
// How many candidates matched?
@@ -1353,7 +1435,7 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
}
Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates) const {
// Penalty weights for overload mismatching.
// This scoring is used to order the suggested overloads in diagnostic on overload mismatch, and
@@ -1365,7 +1447,7 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
constexpr int kMismatchedTemplateNumberPenalty = 1;
size_t num_parameters = static_cast<size_t>(overload->num_parameters);
- size_t num_arguments = static_cast<size_t>(args.size());
+ size_t num_arguments = static_cast<size_t>(args.Length());
size_t score = 0;
@@ -1432,14 +1514,14 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
}
// Now that all the template types have been finalized, we can construct the parameters.
- std::vector<IntrinsicPrototype::Parameter> parameters;
+ utils::Vector<IntrinsicPrototype::Parameter, kNumFixedParams> parameters;
if (score == 0) {
- parameters.reserve(num_params);
+ parameters.Reserve(num_params);
for (size_t p = 0; p < num_params; p++) {
auto& parameter = overload->parameters[p];
auto* indices = parameter.matcher_indices;
auto* ty = Match(templates, overload, indices).Type(args[p]->UnwrapRef());
- parameters.emplace_back(IntrinsicPrototype::Parameter{ty, parameter.usage});
+ parameters.Emplace(ty, parameter.usage);
}
}
@@ -1448,9 +1530,10 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
Impl::Candidate Impl::ResolveCandidate(Impl::Candidates&& candidates,
const char* intrinsic_name,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates) const {
- std::vector<uint32_t> best_ranks(args.size(), 0xffffffff);
+ utils::Vector<uint32_t, kNumFixedParams> best_ranks;
+ best_ranks.Resize(args.Length(), 0xffffffff);
size_t num_matched = 0;
Candidate* best = nullptr;
for (auto& candidate : candidates) {
@@ -1459,7 +1542,7 @@ Impl::Candidate Impl::ResolveCandidate(Impl::Candidates&& candidates,
}
bool some_won = false; // An argument ranked less than the 'best' overload's argument
bool some_lost = false; // An argument ranked more than the 'best' overload's argument
- for (size_t i = 0; i < args.size(); i++) {
+ for (size_t i = 0; i < args.Length(); i++) {
auto rank = sem::Type::ConversionRank(args[i], candidate.parameters[i].type);
if (best_ranks[i] > rank) {
best_ranks[i] = rank;
@@ -1566,7 +1649,7 @@ void Impl::PrintOverload(std::ostream& ss,
}
void Impl::PrintCandidates(std::ostream& ss,
- const Candidates& candidates,
+ utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const {
for (auto& candidate : candidates) {
ss << " ";
@@ -1600,9 +1683,9 @@ std::string MatchState::NumName() {
}
void Impl::ErrAmbiguousOverload(const char* intrinsic_name,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates,
- Candidates candidates) const {
+ utils::VectorRef<Candidate> candidates) const {
std::stringstream ss;
ss << "ambiguous overload while attempting to match " << intrinsic_name;
for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) {
diff --git a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.h b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.h
index 058b253f849..b36f8d8a603 100644
--- a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.h
+++ b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.h
@@ -17,11 +17,13 @@
#include <memory>
#include <string>
-#include <vector>
+#include "src/tint/ast/binary_expression.h"
+#include "src/tint/ast/unary_op.h"
#include "src/tint/resolver/const_eval.h"
#include "src/tint/resolver/ctor_conv_intrinsic.h"
#include "src/tint/sem/builtin.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint {
@@ -45,7 +47,7 @@ class IntrinsicTable {
/// The semantic info for the builtin
const sem::Builtin* sem = nullptr;
/// The constant evaluation function
- const_eval::Function* const_eval_fn = nullptr;
+ ConstEval::Function const_eval_fn = nullptr;
};
/// UnaryOperator describes a resolved unary operator
@@ -54,6 +56,8 @@ class IntrinsicTable {
const sem::Type* result = nullptr;
/// The type of the parameter of the unary operator
const sem::Type* parameter = nullptr;
+ /// The constant evaluation function
+ ConstEval::Function const_eval_fn = nullptr;
};
/// BinaryOperator describes a resolved binary operator
@@ -64,6 +68,16 @@ class IntrinsicTable {
const sem::Type* lhs = nullptr;
/// The type of RHS parameter of the binary operator
const sem::Type* rhs = nullptr;
+ /// The constant evaluation function
+ ConstEval::Function const_eval_fn = nullptr;
+ };
+
+ /// CtorOrConv describes a resolved type constructor or type conversion
+ struct CtorOrConv {
+ /// The result type of the type constructor or type conversion
+ const sem::CallTarget* target = nullptr;
+ /// The constant evaluation function
+ ConstEval::Function const_eval_fn = nullptr;
};
/// Lookup looks for the builtin overload with the given signature, raising an error diagnostic
@@ -73,7 +87,7 @@ class IntrinsicTable {
/// @param source the source of the builtin call
/// @return the semantic builtin if found, otherwise nullptr
virtual Builtin Lookup(sem::BuiltinType type,
- const std::vector<const sem::Type*>& args,
+ utils::VectorRef<const sem::Type*> args,
const Source& source) = 0;
/// Lookup looks for the unary op overload with the given signature, raising an error
@@ -107,10 +121,10 @@ class IntrinsicTable {
/// @param args the argument types passed to the constructor / conversion call
/// @param source the source of the call
/// @return a sem::TypeConstructor, sem::TypeConversion or nullptr if nothing matched
- virtual const sem::CallTarget* Lookup(CtorConvIntrinsic type,
- const sem::Type* template_arg,
- const std::vector<const sem::Type*>& args,
- const Source& source) = 0;
+ virtual CtorOrConv Lookup(CtorConvIntrinsic type,
+ const sem::Type* template_arg,
+ utils::VectorRef<const sem::Type*> args,
+ const Source& source) = 0;
};
} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl
index 521e5e14f7a..c589b2f66e6 100644
--- a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl
+++ b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl
@@ -13,11 +13,9 @@
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/intrinsic-gen
+// File generated by tools/src/cmd/gen
// using the template:
// src/tint/resolver/intrinsic_table.inl.tmpl
-// and the intrinsic defintion file:
-// src/tint/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
@@ -25,7 +23,6 @@
// clang-format off
/// TypeMatcher for 'type bool'
-/// @see src/tint/intrinsics.def:73:6
class Bool : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -51,9 +48,8 @@ std::string Bool::String(MatchState*) const {
return "bool";
}
-/// TypeMatcher for 'type af'
-/// @see src/tint/intrinsics.def:74:48
-class Af : public TypeMatcher {
+/// TypeMatcher for 'type fa'
+class Fa : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
/// Match may define and refine the template types and numbers in state.
@@ -67,22 +63,21 @@ class Af : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* Af::Match(MatchState& state, const sem::Type* ty) const {
- if (!match_af(ty)) {
+const sem::Type* Fa::Match(MatchState& state, const sem::Type* ty) const {
+ if (!match_fa(ty)) {
return nullptr;
}
- return build_af(state);
+ return build_fa(state);
}
-std::string Af::String(MatchState*) const {
+std::string Fa::String(MatchState*) const {
std::stringstream ss;
ss << "abstract-float";
return ss.str();
}
-/// TypeMatcher for 'type ai'
-/// @see src/tint/intrinsics.def:75:48
-class Ai : public TypeMatcher {
+/// TypeMatcher for 'type ia'
+class Ia : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
/// Match may define and refine the template types and numbers in state.
@@ -96,21 +91,20 @@ class Ai : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* Ai::Match(MatchState& state, const sem::Type* ty) const {
- if (!match_ai(ty)) {
+const sem::Type* Ia::Match(MatchState& state, const sem::Type* ty) const {
+ if (!match_ia(ty)) {
return nullptr;
}
- return build_ai(state);
+ return build_ia(state);
}
-std::string Ai::String(MatchState*) const {
+std::string Ia::String(MatchState*) const {
std::stringstream ss;
ss << "abstract-int";
return ss.str();
}
/// TypeMatcher for 'type i32'
-/// @see src/tint/intrinsics.def:76:21
class I32 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -137,7 +131,6 @@ std::string I32::String(MatchState*) const {
}
/// TypeMatcher for 'type u32'
-/// @see src/tint/intrinsics.def:77:21
class U32 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -164,7 +157,6 @@ std::string U32::String(MatchState*) const {
}
/// TypeMatcher for 'type f32'
-/// @see src/tint/intrinsics.def:78:21
class F32 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -190,8 +182,33 @@ std::string F32::String(MatchState*) const {
return "f32";
}
+/// TypeMatcher for 'type f16'
+class F16 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* F16::Match(MatchState& state, const sem::Type* ty) const {
+ if (!match_f16(ty)) {
+ return nullptr;
+ }
+ return build_f16(state);
+}
+
+std::string F16::String(MatchState*) const {
+ return "f16";
+}
+
/// TypeMatcher for 'type vec2'
-/// @see src/tint/intrinsics.def:79:6
class Vec2 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -224,7 +241,6 @@ std::string Vec2::String(MatchState* state) const {
}
/// TypeMatcher for 'type vec3'
-/// @see src/tint/intrinsics.def:80:6
class Vec3 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -257,7 +273,6 @@ std::string Vec3::String(MatchState* state) const {
}
/// TypeMatcher for 'type vec4'
-/// @see src/tint/intrinsics.def:81:6
class Vec4 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -290,7 +305,6 @@ std::string Vec4::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat2x2'
-/// @see src/tint/intrinsics.def:82:6
class Mat2X2 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -323,7 +337,6 @@ std::string Mat2X2::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat2x3'
-/// @see src/tint/intrinsics.def:83:6
class Mat2X3 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -356,7 +369,6 @@ std::string Mat2X3::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat2x4'
-/// @see src/tint/intrinsics.def:84:6
class Mat2X4 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -389,7 +401,6 @@ std::string Mat2X4::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat3x2'
-/// @see src/tint/intrinsics.def:85:6
class Mat3X2 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -422,7 +433,6 @@ std::string Mat3X2::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat3x3'
-/// @see src/tint/intrinsics.def:86:6
class Mat3X3 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -455,7 +465,6 @@ std::string Mat3X3::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat3x4'
-/// @see src/tint/intrinsics.def:87:6
class Mat3X4 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -488,7 +497,6 @@ std::string Mat3X4::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat4x2'
-/// @see src/tint/intrinsics.def:88:6
class Mat4X2 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -521,7 +529,6 @@ std::string Mat4X2::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat4x3'
-/// @see src/tint/intrinsics.def:89:6
class Mat4X3 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -554,7 +561,6 @@ std::string Mat4X3::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat4x4'
-/// @see src/tint/intrinsics.def:90:6
class Mat4X4 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -587,7 +593,6 @@ std::string Mat4X4::String(MatchState* state) const {
}
/// TypeMatcher for 'type vec'
-/// @see src/tint/intrinsics.def:91:34
class Vec : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -628,7 +633,6 @@ std::string Vec::String(MatchState* state) const {
}
/// TypeMatcher for 'type mat'
-/// @see src/tint/intrinsics.def:92:34
class Mat : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -675,7 +679,6 @@ std::string Mat::String(MatchState* state) const {
}
/// TypeMatcher for 'type ptr'
-/// @see src/tint/intrinsics.def:93:6
class Ptr : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -720,7 +723,6 @@ std::string Ptr::String(MatchState* state) const {
}
/// TypeMatcher for 'type atomic'
-/// @see src/tint/intrinsics.def:94:6
class Atomic : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -753,7 +755,6 @@ std::string Atomic::String(MatchState* state) const {
}
/// TypeMatcher for 'type array'
-/// @see src/tint/intrinsics.def:95:6
class Array : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -786,7 +787,6 @@ std::string Array::String(MatchState* state) const {
}
/// TypeMatcher for 'type sampler'
-/// @see src/tint/intrinsics.def:96:6
class Sampler : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -813,7 +813,6 @@ std::string Sampler::String(MatchState*) const {
}
/// TypeMatcher for 'type sampler_comparison'
-/// @see src/tint/intrinsics.def:97:6
class SamplerComparison : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -840,7 +839,6 @@ std::string SamplerComparison::String(MatchState*) const {
}
/// TypeMatcher for 'type texture_1d'
-/// @see src/tint/intrinsics.def:98:6
class Texture1D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -873,7 +871,6 @@ std::string Texture1D::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_2d'
-/// @see src/tint/intrinsics.def:99:6
class Texture2D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -906,7 +903,6 @@ std::string Texture2D::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_2d_array'
-/// @see src/tint/intrinsics.def:100:6
class Texture2DArray : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -939,7 +935,6 @@ std::string Texture2DArray::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_3d'
-/// @see src/tint/intrinsics.def:101:6
class Texture3D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -972,7 +967,6 @@ std::string Texture3D::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_cube'
-/// @see src/tint/intrinsics.def:102:6
class TextureCube : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1005,7 +999,6 @@ std::string TextureCube::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_cube_array'
-/// @see src/tint/intrinsics.def:103:6
class TextureCubeArray : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1038,7 +1031,6 @@ std::string TextureCubeArray::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_multisampled_2d'
-/// @see src/tint/intrinsics.def:104:6
class TextureMultisampled2D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1071,7 +1063,6 @@ std::string TextureMultisampled2D::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_depth_2d'
-/// @see src/tint/intrinsics.def:105:6
class TextureDepth2D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1098,7 +1089,6 @@ std::string TextureDepth2D::String(MatchState*) const {
}
/// TypeMatcher for 'type texture_depth_2d_array'
-/// @see src/tint/intrinsics.def:106:6
class TextureDepth2DArray : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1125,7 +1115,6 @@ std::string TextureDepth2DArray::String(MatchState*) const {
}
/// TypeMatcher for 'type texture_depth_cube'
-/// @see src/tint/intrinsics.def:107:6
class TextureDepthCube : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1152,7 +1141,6 @@ std::string TextureDepthCube::String(MatchState*) const {
}
/// TypeMatcher for 'type texture_depth_cube_array'
-/// @see src/tint/intrinsics.def:108:6
class TextureDepthCubeArray : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1179,7 +1167,6 @@ std::string TextureDepthCubeArray::String(MatchState*) const {
}
/// TypeMatcher for 'type texture_depth_multisampled_2d'
-/// @see src/tint/intrinsics.def:109:6
class TextureDepthMultisampled2D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1206,7 +1193,6 @@ std::string TextureDepthMultisampled2D::String(MatchState*) const {
}
/// TypeMatcher for 'type texture_storage_1d'
-/// @see src/tint/intrinsics.def:110:6
class TextureStorage1D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1245,7 +1231,6 @@ std::string TextureStorage1D::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_storage_2d'
-/// @see src/tint/intrinsics.def:111:6
class TextureStorage2D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1284,7 +1269,6 @@ std::string TextureStorage2D::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_storage_2d_array'
-/// @see src/tint/intrinsics.def:112:6
class TextureStorage2DArray : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1323,7 +1307,6 @@ std::string TextureStorage2DArray::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_storage_3d'
-/// @see src/tint/intrinsics.def:113:6
class TextureStorage3D : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1362,7 +1345,6 @@ std::string TextureStorage3D::String(MatchState* state) const {
}
/// TypeMatcher for 'type texture_external'
-/// @see src/tint/intrinsics.def:114:6
class TextureExternal : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1389,7 +1371,6 @@ std::string TextureExternal::String(MatchState*) const {
}
/// TypeMatcher for 'type __modf_result'
-/// @see src/tint/intrinsics.def:116:6
class ModfResult : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1405,18 +1386,25 @@ class ModfResult : public TypeMatcher {
};
const sem::Type* ModfResult::Match(MatchState& state, const sem::Type* ty) const {
- if (!match_modf_result(ty)) {
+ const sem::Type* T = nullptr;
+ if (!match_modf_result(ty, T)) {
+ return nullptr;
+ }
+ T = state.Type(T);
+ if (T == nullptr) {
return nullptr;
}
- return build_modf_result(state);
+ return build_modf_result(state, T);
}
-std::string ModfResult::String(MatchState*) const {
- return "__modf_result";
+std::string ModfResult::String(MatchState* state) const {
+ const std::string T = state->TypeName();
+ std::stringstream ss;
+ ss << "__modf_result_" << T;
+ return ss.str();
}
/// TypeMatcher for 'type __modf_result_vec'
-/// @see src/tint/intrinsics.def:117:39
class ModfResultVec : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1433,25 +1421,30 @@ class ModfResultVec : public TypeMatcher {
const sem::Type* ModfResultVec::Match(MatchState& state, const sem::Type* ty) const {
Number N = Number::invalid;
- if (!match_modf_result_vec(ty, N)) {
+ const sem::Type* T = nullptr;
+ if (!match_modf_result_vec(ty, N, T)) {
return nullptr;
}
N = state.Num(N);
if (!N.IsValid()) {
return nullptr;
}
- return build_modf_result_vec(state, N);
+ T = state.Type(T);
+ if (T == nullptr) {
+ return nullptr;
+ }
+ return build_modf_result_vec(state, N, T);
}
std::string ModfResultVec::String(MatchState* state) const {
const std::string N = state->NumName();
+ const std::string T = state->TypeName();
std::stringstream ss;
- ss << "__modf_result_vec" << N;
+ ss << "__modf_result_vec" << N << "_" << T;
return ss.str();
}
/// TypeMatcher for 'type __frexp_result'
-/// @see src/tint/intrinsics.def:118:6
class FrexpResult : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1467,18 +1460,25 @@ class FrexpResult : public TypeMatcher {
};
const sem::Type* FrexpResult::Match(MatchState& state, const sem::Type* ty) const {
- if (!match_frexp_result(ty)) {
+ const sem::Type* T = nullptr;
+ if (!match_frexp_result(ty, T)) {
+ return nullptr;
+ }
+ T = state.Type(T);
+ if (T == nullptr) {
return nullptr;
}
- return build_frexp_result(state);
+ return build_frexp_result(state, T);
}
-std::string FrexpResult::String(MatchState*) const {
- return "__frexp_result";
+std::string FrexpResult::String(MatchState* state) const {
+ const std::string T = state->TypeName();
+ std::stringstream ss;
+ ss << "__frexp_result_" << T;
+ return ss.str();
}
/// TypeMatcher for 'type __frexp_result_vec'
-/// @see src/tint/intrinsics.def:119:40
class FrexpResultVec : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1495,25 +1495,30 @@ class FrexpResultVec : public TypeMatcher {
const sem::Type* FrexpResultVec::Match(MatchState& state, const sem::Type* ty) const {
Number N = Number::invalid;
- if (!match_frexp_result_vec(ty, N)) {
+ const sem::Type* T = nullptr;
+ if (!match_frexp_result_vec(ty, N, T)) {
return nullptr;
}
N = state.Num(N);
if (!N.IsValid()) {
return nullptr;
}
- return build_frexp_result_vec(state, N);
+ T = state.Type(T);
+ if (T == nullptr) {
+ return nullptr;
+ }
+ return build_frexp_result_vec(state, N, T);
}
std::string FrexpResultVec::String(MatchState* state) const {
const std::string N = state->NumName();
+ const std::string T = state->TypeName();
std::stringstream ss;
- ss << "__frexp_result_vec" << N;
+ ss << "__frexp_result_vec" << N << "_" << T;
return ss.str();
}
/// TypeMatcher for 'type __atomic_compare_exchange_result'
-/// @see src/tint/intrinsics.def:121:6
class AtomicCompareExchangeResult : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules.
@@ -1545,9 +1550,8 @@ std::string AtomicCompareExchangeResult::String(MatchState* state) const {
return "__atomic_compare_exchange_result<" + T + ">";
}
-/// TypeMatcher for 'match fiu32'
-/// @see src/tint/intrinsics.def:129:7
-class Fiu32 : public TypeMatcher {
+/// TypeMatcher for 'match abstract_or_scalar'
+class AbstractOrScalar : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1562,7 +1566,13 @@ class Fiu32 : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* Fiu32::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* AbstractOrScalar::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_fa(ty)) {
+ return build_fa(state);
+ }
+ if (match_ia(ty)) {
+ return build_ia(state);
+ }
if (match_i32(ty)) {
return build_i32(state);
}
@@ -1572,20 +1582,25 @@ const sem::Type* Fiu32::Match(MatchState& state, const sem::Type* ty) const {
if (match_f32(ty)) {
return build_f32(state);
}
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
+ if (match_bool(ty)) {
+ return build_bool(state);
+ }
return nullptr;
}
-std::string Fiu32::String(MatchState*) const {
+std::string AbstractOrScalar::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
+ ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match fi32'
-/// @see src/tint/intrinsics.def:130:7
-class Fi32 : public TypeMatcher {
+/// TypeMatcher for 'match scalar'
+class Scalar : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1600,27 +1615,35 @@ class Fi32 : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* Fi32::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* Scalar::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
return build_i32(state);
}
+ if (match_u32(ty)) {
+ return build_u32(state);
+ }
if (match_f32(ty)) {
return build_f32(state);
}
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
+ if (match_bool(ty)) {
+ return build_bool(state);
+ }
return nullptr;
}
-std::string Fi32::String(MatchState*) const {
+std::string Scalar::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << F32().String(nullptr) << " or " << I32().String(nullptr);
+ ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match iu32'
-/// @see src/tint/intrinsics.def:131:7
-class Iu32 : public TypeMatcher {
+/// TypeMatcher for 'match scalar_no_f32'
+class ScalarNoF32 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1635,27 +1658,32 @@ class Iu32 : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* Iu32::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* ScalarNoF32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
return build_u32(state);
}
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
+ if (match_bool(ty)) {
+ return build_bool(state);
+ }
return nullptr;
}
-std::string Iu32::String(MatchState*) const {
+std::string ScalarNoF32::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << I32().String(nullptr) << " or " << U32().String(nullptr);
+ ss << I32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match scalar'
-/// @see src/tint/intrinsics.def:132:7
-class Scalar : public TypeMatcher {
+/// TypeMatcher for 'match scalar_no_f16'
+class ScalarNoF16 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1670,7 +1698,7 @@ class Scalar : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* Scalar::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* ScalarNoF16::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
return build_i32(state);
}
@@ -1686,7 +1714,7 @@ const sem::Type* Scalar::Match(MatchState& state, const sem::Type* ty) const {
return nullptr;
}
-std::string Scalar::String(MatchState*) const {
+std::string ScalarNoF16::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
@@ -1694,9 +1722,8 @@ std::string Scalar::String(MatchState*) const {
return ss.str();
}
-/// TypeMatcher for 'match abstract_or_scalar'
-/// @see src/tint/intrinsics.def:133:7
-class AbstractOrScalar : public TypeMatcher {
+/// TypeMatcher for 'match scalar_no_i32'
+class ScalarNoI32 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1711,39 +1738,72 @@ class AbstractOrScalar : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* AbstractOrScalar::Match(MatchState& state, const sem::Type* ty) const {
- if (match_af(ty)) {
- return build_af(state);
+const sem::Type* ScalarNoI32::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_u32(ty)) {
+ return build_u32(state);
+ }
+ if (match_f32(ty)) {
+ return build_f32(state);
+ }
+ if (match_f16(ty)) {
+ return build_f16(state);
}
- if (match_ai(ty)) {
- return build_ai(state);
+ if (match_bool(ty)) {
+ return build_bool(state);
}
+ return nullptr;
+}
+
+std::string ScalarNoI32::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match scalar_no_u32'
+class ScalarNoU32 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* ScalarNoU32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
return build_i32(state);
}
- if (match_u32(ty)) {
- return build_u32(state);
- }
if (match_f32(ty)) {
return build_f32(state);
}
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
if (match_bool(ty)) {
return build_bool(state);
}
return nullptr;
}
-std::string AbstractOrScalar::String(MatchState*) const {
+std::string ScalarNoU32::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << Ai().String(nullptr) << ", " << Af().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
+ ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << Bool().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match af_f32'
-/// @see src/tint/intrinsics.def:134:7
-class AfF32 : public TypeMatcher {
+/// TypeMatcher for 'match scalar_no_bool'
+class ScalarNoBool : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1758,27 +1818,32 @@ class AfF32 : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* AfF32::Match(MatchState& state, const sem::Type* ty) const {
- if (match_af(ty)) {
- return build_af(state);
+const sem::Type* ScalarNoBool::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_i32(ty)) {
+ return build_i32(state);
+ }
+ if (match_u32(ty)) {
+ return build_u32(state);
}
if (match_f32(ty)) {
return build_f32(state);
}
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
return nullptr;
}
-std::string AfF32::String(MatchState*) const {
+std::string ScalarNoBool::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << Af().String(nullptr) << " or " << F32().String(nullptr);
+ ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match scalar_no_f32'
-/// @see src/tint/intrinsics.def:135:7
-class ScalarNoF32 : public TypeMatcher {
+/// TypeMatcher for 'match fia_fiu32_f16'
+class FiaFiu32F16 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1793,30 +1858,38 @@ class ScalarNoF32 : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* ScalarNoF32::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* FiaFiu32F16::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_fa(ty)) {
+ return build_fa(state);
+ }
+ if (match_ia(ty)) {
+ return build_ia(state);
+ }
if (match_i32(ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
return build_u32(state);
}
- if (match_bool(ty)) {
- return build_bool(state);
+ if (match_f32(ty)) {
+ return build_f32(state);
+ }
+ if (match_f16(ty)) {
+ return build_f16(state);
}
return nullptr;
}
-std::string ScalarNoF32::String(MatchState*) const {
+std::string FiaFiu32F16::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
+ ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match scalar_no_i32'
-/// @see src/tint/intrinsics.def:136:7
-class ScalarNoI32 : public TypeMatcher {
+/// TypeMatcher for 'match fia_fi32_f16'
+class FiaFi32F16 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1831,30 +1904,112 @@ class ScalarNoI32 : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* ScalarNoI32::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* FiaFi32F16::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_fa(ty)) {
+ return build_fa(state);
+ }
+ if (match_ia(ty)) {
+ return build_ia(state);
+ }
+ if (match_i32(ty)) {
+ return build_i32(state);
+ }
+ if (match_f32(ty)) {
+ return build_f32(state);
+ }
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
+ return nullptr;
+}
+
+std::string FiaFi32F16::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match fia_fiu32'
+class FiaFiu32 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* FiaFiu32::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_fa(ty)) {
+ return build_fa(state);
+ }
+ if (match_ia(ty)) {
+ return build_ia(state);
+ }
+ if (match_i32(ty)) {
+ return build_i32(state);
+ }
if (match_u32(ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
return build_f32(state);
}
- if (match_bool(ty)) {
- return build_bool(state);
+ return nullptr;
+}
+
+std::string FiaFiu32::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match fa_f32'
+class FaF32 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* FaF32::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_fa(ty)) {
+ return build_fa(state);
+ }
+ if (match_f32(ty)) {
+ return build_f32(state);
}
return nullptr;
}
-std::string ScalarNoI32::String(MatchState*) const {
+std::string FaF32::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << F32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
+ ss << Fa().String(nullptr) << " or " << F32().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match scalar_no_u32'
-/// @see src/tint/intrinsics.def:137:7
-class ScalarNoU32 : public TypeMatcher {
+/// TypeMatcher for 'match fa_f32_f16'
+class FaF32F16 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1869,30 +2024,106 @@ class ScalarNoU32 : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* ScalarNoU32::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* FaF32F16::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_fa(ty)) {
+ return build_fa(state);
+ }
+ if (match_f32(ty)) {
+ return build_f32(state);
+ }
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
+ return nullptr;
+}
+
+std::string FaF32F16::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << Fa().String(nullptr) << ", " << F32().String(nullptr) << " or " << F16().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match ia_iu32'
+class IaIu32 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* IaIu32::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_ia(ty)) {
+ return build_ia(state);
+ }
if (match_i32(ty)) {
return build_i32(state);
}
+ if (match_u32(ty)) {
+ return build_u32(state);
+ }
+ return nullptr;
+}
+
+std::string IaIu32::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << Ia().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match fiu32_f16'
+class Fiu32F16 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* Fiu32F16::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_i32(ty)) {
+ return build_i32(state);
+ }
+ if (match_u32(ty)) {
+ return build_u32(state);
+ }
if (match_f32(ty)) {
return build_f32(state);
}
- if (match_bool(ty)) {
- return build_bool(state);
+ if (match_f16(ty)) {
+ return build_f16(state);
}
return nullptr;
}
-std::string ScalarNoU32::String(MatchState*) const {
+std::string Fiu32F16::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << Bool().String(nullptr);
+ ss << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr);
return ss.str();
}
-/// TypeMatcher for 'match scalar_no_bool'
-/// @see src/tint/intrinsics.def:138:7
-class ScalarNoBool : public TypeMatcher {
+/// TypeMatcher for 'match fiu32'
+class Fiu32 : public TypeMatcher {
public:
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
@@ -1907,7 +2138,7 @@ class ScalarNoBool : public TypeMatcher {
std::string String(MatchState* state) const override;
};
-const sem::Type* ScalarNoBool::Match(MatchState& state, const sem::Type* ty) const {
+const sem::Type* Fiu32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
return build_i32(state);
}
@@ -1920,7 +2151,7 @@ const sem::Type* ScalarNoBool::Match(MatchState& state, const sem::Type* ty) con
return nullptr;
}
-std::string ScalarNoBool::String(MatchState*) const {
+std::string Fiu32::String(MatchState*) const {
std::stringstream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
@@ -1928,8 +2159,146 @@ std::string ScalarNoBool::String(MatchState*) const {
return ss.str();
}
+/// TypeMatcher for 'match fi32_f16'
+class Fi32F16 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* Fi32F16::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_i32(ty)) {
+ return build_i32(state);
+ }
+ if (match_f32(ty)) {
+ return build_f32(state);
+ }
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
+ return nullptr;
+}
+
+std::string Fi32F16::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match fi32'
+class Fi32 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* Fi32::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_i32(ty)) {
+ return build_i32(state);
+ }
+ if (match_f32(ty)) {
+ return build_f32(state);
+ }
+ return nullptr;
+}
+
+std::string Fi32::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << F32().String(nullptr) << " or " << I32().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match f32_f16'
+class F32F16 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* F32F16::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_f32(ty)) {
+ return build_f32(state);
+ }
+ if (match_f16(ty)) {
+ return build_f16(state);
+ }
+ return nullptr;
+}
+
+std::string F32F16::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << F32().String(nullptr) << " or " << F16().String(nullptr);
+ return ss.str();
+}
+
+/// TypeMatcher for 'match iu32'
+class Iu32 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules, and returns the
+ /// expected, canonicalized type on success.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const sem::Type* Match(MatchState& state,
+ const sem::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const sem::Type* Iu32::Match(MatchState& state, const sem::Type* ty) const {
+ if (match_i32(ty)) {
+ return build_i32(state);
+ }
+ if (match_u32(ty)) {
+ return build_u32(state);
+ }
+ return nullptr;
+}
+
+std::string Iu32::String(MatchState*) const {
+ std::stringstream ss;
+ // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ ss << I32().String(nullptr) << " or " << U32().String(nullptr);
+ return ss.str();
+}
+
/// EnumMatcher for 'match f32_texel_format'
-/// @see src/tint/intrinsics.def:149:7
class F32TexelFormat : public NumberMatcher {
public:
/// Checks whether the given number matches the enum matcher rules.
@@ -1962,7 +2331,6 @@ std::string F32TexelFormat::String(MatchState*) const {
}
/// EnumMatcher for 'match i32_texel_format'
-/// @see src/tint/intrinsics.def:151:7
class I32TexelFormat : public NumberMatcher {
public:
/// Checks whether the given number matches the enum matcher rules.
@@ -1994,7 +2362,6 @@ std::string I32TexelFormat::String(MatchState*) const {
}
/// EnumMatcher for 'match u32_texel_format'
-/// @see src/tint/intrinsics.def:153:7
class U32TexelFormat : public NumberMatcher {
public:
/// Checks whether the given number matches the enum matcher rules.
@@ -2025,9 +2392,8 @@ std::string U32TexelFormat::String(MatchState*) const {
return "rgba8uint, rgba16uint, r32uint, rg32uint or rgba32uint";
}
-/// EnumMatcher for 'match write_only'
-/// @see src/tint/intrinsics.def:156:7
-class WriteOnly : public NumberMatcher {
+/// EnumMatcher for 'match write'
+class Write : public NumberMatcher {
public:
/// Checks whether the given number matches the enum matcher rules.
/// Match may define template numbers in state.
@@ -2040,19 +2406,43 @@ class WriteOnly : public NumberMatcher {
std::string String(MatchState* state) const override;
};
-Number WriteOnly::Match(MatchState&, Number number) const {
+Number Write::Match(MatchState&, Number number) const {
if (number.IsAny() || number.Value() == static_cast<uint32_t>(Access::kWrite)) {
return Number(static_cast<uint32_t>(Access::kWrite));
}
return Number::invalid;
}
-std::string WriteOnly::String(MatchState*) const {
+std::string Write::String(MatchState*) const {
return "write";
}
+/// EnumMatcher for 'match read_write'
+class ReadWrite : public NumberMatcher {
+ public:
+ /// Checks whether the given number matches the enum matcher rules.
+ /// Match may define template numbers in state.
+ /// @param state the MatchState
+ /// @param number the enum value as a Number
+ /// @return true if the enum value matches the set
+ Number Match(MatchState& state, Number number) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+Number ReadWrite::Match(MatchState&, Number number) const {
+ if (number.IsAny() || number.Value() == static_cast<uint32_t>(Access::kReadWrite)) {
+ return Number(static_cast<uint32_t>(Access::kReadWrite));
+ }
+ return Number::invalid;
+}
+
+std::string ReadWrite::String(MatchState*) const {
+ return "read_write";
+}
+
/// EnumMatcher for 'match function_private_workgroup'
-/// @see src/tint/intrinsics.def:158:7
class FunctionPrivateWorkgroup : public NumberMatcher {
public:
/// Checks whether the given number matches the enum matcher rules.
@@ -2082,7 +2472,6 @@ std::string FunctionPrivateWorkgroup::String(MatchState*) const {
}
/// EnumMatcher for 'match workgroup_or_storage'
-/// @see src/tint/intrinsics.def:159:7
class WorkgroupOrStorage : public NumberMatcher {
public:
/// Checks whether the given number matches the enum matcher rules.
@@ -2135,56 +2524,6 @@ std::string Storage::String(MatchState*) const {
return "storage";
}
-/// EnumMatcher for 'match write'
-class Write : public NumberMatcher {
- public:
- /// Checks whether the given number matches the enum matcher rules.
- /// Match may define template numbers in state.
- /// @param state the MatchState
- /// @param number the enum value as a Number
- /// @return true if the enum value matches the set
- Number Match(MatchState& state, Number number) const override;
- /// @param state the MatchState
- /// @return a string representation of the matcher.
- std::string String(MatchState* state) const override;
-};
-
-Number Write::Match(MatchState&, Number number) const {
- if (number.IsAny() || number.Value() == static_cast<uint32_t>(Access::kWrite)) {
- return Number(static_cast<uint32_t>(Access::kWrite));
- }
- return Number::invalid;
-}
-
-std::string Write::String(MatchState*) const {
- return "write";
-}
-
-/// EnumMatcher for 'match read_write'
-class ReadWrite : public NumberMatcher {
- public:
- /// Checks whether the given number matches the enum matcher rules.
- /// Match may define template numbers in state.
- /// @param state the MatchState
- /// @param number the enum value as a Number
- /// @return true if the enum value matches the set
- Number Match(MatchState& state, Number number) const override;
- /// @param state the MatchState
- /// @return a string representation of the matcher.
- std::string String(MatchState* state) const override;
-};
-
-Number ReadWrite::Match(MatchState&, Number number) const {
- if (number.IsAny() || number.Value() == static_cast<uint32_t>(Access::kReadWrite)) {
- return Number(static_cast<uint32_t>(Access::kReadWrite));
- }
- return Number::invalid;
-}
-
-std::string ReadWrite::String(MatchState*) const {
- return "read_write";
-}
-
/// Matchers holds type and number matchers
class Matchers {
private:
@@ -2194,11 +2533,12 @@ class Matchers {
TemplateNumberMatcher template_number_1_{1};
TemplateNumberMatcher template_number_2_{2};
Bool Bool_;
- Af Af_;
- Ai Ai_;
+ Fa Fa_;
+ Ia Ia_;
I32 I32_;
U32 U32_;
F32 F32_;
+ F16 F16_;
Vec2 Vec2_;
Vec3 Vec3_;
Vec4 Vec4_;
@@ -2240,25 +2580,33 @@ class Matchers {
FrexpResult FrexpResult_;
FrexpResultVec FrexpResultVec_;
AtomicCompareExchangeResult AtomicCompareExchangeResult_;
- Fiu32 Fiu32_;
- Fi32 Fi32_;
- Iu32 Iu32_;
- Scalar Scalar_;
AbstractOrScalar AbstractOrScalar_;
- AfF32 AfF32_;
+ Scalar Scalar_;
ScalarNoF32 ScalarNoF32_;
+ ScalarNoF16 ScalarNoF16_;
ScalarNoI32 ScalarNoI32_;
ScalarNoU32 ScalarNoU32_;
ScalarNoBool ScalarNoBool_;
+ FiaFiu32F16 FiaFiu32F16_;
+ FiaFi32F16 FiaFi32F16_;
+ FiaFiu32 FiaFiu32_;
+ FaF32 FaF32_;
+ FaF32F16 FaF32F16_;
+ IaIu32 IaIu32_;
+ Fiu32F16 Fiu32F16_;
+ Fiu32 Fiu32_;
+ Fi32F16 Fi32F16_;
+ Fi32 Fi32_;
+ F32F16 F32F16_;
+ Iu32 Iu32_;
F32TexelFormat F32TexelFormat_;
I32TexelFormat I32TexelFormat_;
U32TexelFormat U32TexelFormat_;
- WriteOnly WriteOnly_;
+ Write Write_;
+ ReadWrite ReadWrite_;
FunctionPrivateWorkgroup FunctionPrivateWorkgroup_;
WorkgroupOrStorage WorkgroupOrStorage_;
Storage Storage_;
- Write Write_;
- ReadWrite ReadWrite_;
public:
/// Constructor
@@ -2267,82 +2615,91 @@ class Matchers {
~Matchers();
/// The template types, types, and type matchers
- TypeMatcher const* const type[59] = {
+ TypeMatcher const* const type[69] = {
/* [0] */ &template_type_0_,
/* [1] */ &template_type_1_,
/* [2] */ &Bool_,
- /* [3] */ &Af_,
- /* [4] */ &Ai_,
+ /* [3] */ &Fa_,
+ /* [4] */ &Ia_,
/* [5] */ &I32_,
/* [6] */ &U32_,
/* [7] */ &F32_,
- /* [8] */ &Vec2_,
- /* [9] */ &Vec3_,
- /* [10] */ &Vec4_,
- /* [11] */ &Mat2X2_,
- /* [12] */ &Mat2X3_,
- /* [13] */ &Mat2X4_,
- /* [14] */ &Mat3X2_,
- /* [15] */ &Mat3X3_,
- /* [16] */ &Mat3X4_,
- /* [17] */ &Mat4X2_,
- /* [18] */ &Mat4X3_,
- /* [19] */ &Mat4X4_,
- /* [20] */ &Vec_,
- /* [21] */ &Mat_,
- /* [22] */ &Ptr_,
- /* [23] */ &Atomic_,
- /* [24] */ &Array_,
- /* [25] */ &Sampler_,
- /* [26] */ &SamplerComparison_,
- /* [27] */ &Texture1D_,
- /* [28] */ &Texture2D_,
- /* [29] */ &Texture2DArray_,
- /* [30] */ &Texture3D_,
- /* [31] */ &TextureCube_,
- /* [32] */ &TextureCubeArray_,
- /* [33] */ &TextureMultisampled2D_,
- /* [34] */ &TextureDepth2D_,
- /* [35] */ &TextureDepth2DArray_,
- /* [36] */ &TextureDepthCube_,
- /* [37] */ &TextureDepthCubeArray_,
- /* [38] */ &TextureDepthMultisampled2D_,
- /* [39] */ &TextureStorage1D_,
- /* [40] */ &TextureStorage2D_,
- /* [41] */ &TextureStorage2DArray_,
- /* [42] */ &TextureStorage3D_,
- /* [43] */ &TextureExternal_,
- /* [44] */ &ModfResult_,
- /* [45] */ &ModfResultVec_,
- /* [46] */ &FrexpResult_,
- /* [47] */ &FrexpResultVec_,
- /* [48] */ &AtomicCompareExchangeResult_,
- /* [49] */ &Fiu32_,
- /* [50] */ &Fi32_,
- /* [51] */ &Iu32_,
- /* [52] */ &Scalar_,
- /* [53] */ &AbstractOrScalar_,
- /* [54] */ &AfF32_,
- /* [55] */ &ScalarNoF32_,
- /* [56] */ &ScalarNoI32_,
- /* [57] */ &ScalarNoU32_,
- /* [58] */ &ScalarNoBool_,
+ /* [8] */ &F16_,
+ /* [9] */ &Vec2_,
+ /* [10] */ &Vec3_,
+ /* [11] */ &Vec4_,
+ /* [12] */ &Mat2X2_,
+ /* [13] */ &Mat2X3_,
+ /* [14] */ &Mat2X4_,
+ /* [15] */ &Mat3X2_,
+ /* [16] */ &Mat3X3_,
+ /* [17] */ &Mat3X4_,
+ /* [18] */ &Mat4X2_,
+ /* [19] */ &Mat4X3_,
+ /* [20] */ &Mat4X4_,
+ /* [21] */ &Vec_,
+ /* [22] */ &Mat_,
+ /* [23] */ &Ptr_,
+ /* [24] */ &Atomic_,
+ /* [25] */ &Array_,
+ /* [26] */ &Sampler_,
+ /* [27] */ &SamplerComparison_,
+ /* [28] */ &Texture1D_,
+ /* [29] */ &Texture2D_,
+ /* [30] */ &Texture2DArray_,
+ /* [31] */ &Texture3D_,
+ /* [32] */ &TextureCube_,
+ /* [33] */ &TextureCubeArray_,
+ /* [34] */ &TextureMultisampled2D_,
+ /* [35] */ &TextureDepth2D_,
+ /* [36] */ &TextureDepth2DArray_,
+ /* [37] */ &TextureDepthCube_,
+ /* [38] */ &TextureDepthCubeArray_,
+ /* [39] */ &TextureDepthMultisampled2D_,
+ /* [40] */ &TextureStorage1D_,
+ /* [41] */ &TextureStorage2D_,
+ /* [42] */ &TextureStorage2DArray_,
+ /* [43] */ &TextureStorage3D_,
+ /* [44] */ &TextureExternal_,
+ /* [45] */ &ModfResult_,
+ /* [46] */ &ModfResultVec_,
+ /* [47] */ &FrexpResult_,
+ /* [48] */ &FrexpResultVec_,
+ /* [49] */ &AtomicCompareExchangeResult_,
+ /* [50] */ &AbstractOrScalar_,
+ /* [51] */ &Scalar_,
+ /* [52] */ &ScalarNoF32_,
+ /* [53] */ &ScalarNoF16_,
+ /* [54] */ &ScalarNoI32_,
+ /* [55] */ &ScalarNoU32_,
+ /* [56] */ &ScalarNoBool_,
+ /* [57] */ &FiaFiu32F16_,
+ /* [58] */ &FiaFi32F16_,
+ /* [59] */ &FiaFiu32_,
+ /* [60] */ &FaF32_,
+ /* [61] */ &FaF32F16_,
+ /* [62] */ &IaIu32_,
+ /* [63] */ &Fiu32F16_,
+ /* [64] */ &Fiu32_,
+ /* [65] */ &Fi32F16_,
+ /* [66] */ &Fi32_,
+ /* [67] */ &F32F16_,
+ /* [68] */ &Iu32_,
};
/// The template numbers, and number matchers
- NumberMatcher const* const number[12] = {
+ NumberMatcher const* const number[11] = {
/* [0] */ &template_number_0_,
/* [1] */ &template_number_1_,
/* [2] */ &template_number_2_,
/* [3] */ &F32TexelFormat_,
/* [4] */ &I32TexelFormat_,
/* [5] */ &U32TexelFormat_,
- /* [6] */ &WriteOnly_,
- /* [7] */ &FunctionPrivateWorkgroup_,
- /* [8] */ &WorkgroupOrStorage_,
- /* [9] */ &Storage_,
- /* [10] */ &Write_,
- /* [11] */ &ReadWrite_,
+ /* [6] */ &Write_,
+ /* [7] */ &ReadWrite_,
+ /* [8] */ &FunctionPrivateWorkgroup_,
+ /* [9] */ &WorkgroupOrStorage_,
+ /* [10] */ &Storage_,
};
};
@@ -2350,209 +2707,244 @@ Matchers::Matchers() = default;
Matchers::~Matchers() = default;
constexpr MatcherIndex kMatcherIndices[] = {
- /* [0] */ 22,
+ /* [0] */ 23,
/* [1] */ 0,
- /* [2] */ 23,
+ /* [2] */ 24,
/* [3] */ 0,
- /* [4] */ 11,
- /* [5] */ 7,
- /* [6] */ 22,
- /* [7] */ 9,
- /* [8] */ 24,
+ /* [4] */ 7,
+ /* [5] */ 23,
+ /* [6] */ 10,
+ /* [7] */ 25,
+ /* [8] */ 0,
/* [9] */ 0,
- /* [10] */ 0,
- /* [11] */ 21,
- /* [12] */ 0,
- /* [13] */ 1,
- /* [14] */ 7,
- /* [15] */ 21,
- /* [16] */ 0,
+ /* [10] */ 22,
+ /* [11] */ 0,
+ /* [12] */ 1,
+ /* [13] */ 0,
+ /* [14] */ 22,
+ /* [15] */ 0,
+ /* [16] */ 2,
/* [17] */ 0,
- /* [18] */ 7,
- /* [19] */ 21,
+ /* [18] */ 22,
+ /* [19] */ 1,
/* [20] */ 0,
- /* [21] */ 2,
- /* [22] */ 7,
- /* [23] */ 21,
- /* [24] */ 1,
+ /* [21] */ 0,
+ /* [22] */ 22,
+ /* [23] */ 1,
+ /* [24] */ 2,
/* [25] */ 0,
- /* [26] */ 7,
- /* [27] */ 21,
- /* [28] */ 1,
- /* [29] */ 2,
- /* [30] */ 7,
- /* [31] */ 20,
+ /* [26] */ 22,
+ /* [27] */ 0,
+ /* [28] */ 0,
+ /* [29] */ 0,
+ /* [30] */ 21,
+ /* [31] */ 0,
/* [32] */ 0,
- /* [33] */ 7,
- /* [34] */ 41,
- /* [35] */ 0,
- /* [36] */ 1,
- /* [37] */ 20,
- /* [38] */ 0,
- /* [39] */ 0,
- /* [40] */ 20,
- /* [41] */ 0,
- /* [42] */ 2,
- /* [43] */ 42,
- /* [44] */ 5,
- /* [45] */ 10,
- /* [46] */ 7,
- /* [47] */ 41,
- /* [48] */ 5,
- /* [49] */ 10,
- /* [50] */ 0,
- /* [51] */ 40,
- /* [52] */ 5,
- /* [53] */ 10,
- /* [54] */ 1,
- /* [55] */ 39,
- /* [56] */ 5,
- /* [57] */ 10,
- /* [58] */ 5,
- /* [59] */ 42,
- /* [60] */ 4,
- /* [61] */ 10,
- /* [62] */ 6,
- /* [63] */ 41,
+ /* [33] */ 43,
+ /* [34] */ 5,
+ /* [35] */ 6,
+ /* [36] */ 42,
+ /* [37] */ 5,
+ /* [38] */ 6,
+ /* [39] */ 21,
+ /* [40] */ 0,
+ /* [41] */ 2,
+ /* [42] */ 41,
+ /* [43] */ 5,
+ /* [44] */ 6,
+ /* [45] */ 40,
+ /* [46] */ 5,
+ /* [47] */ 6,
+ /* [48] */ 42,
+ /* [49] */ 0,
+ /* [50] */ 1,
+ /* [51] */ 43,
+ /* [52] */ 4,
+ /* [53] */ 6,
+ /* [54] */ 42,
+ /* [55] */ 4,
+ /* [56] */ 6,
+ /* [57] */ 41,
+ /* [58] */ 4,
+ /* [59] */ 6,
+ /* [60] */ 21,
+ /* [61] */ 0,
+ /* [62] */ 7,
+ /* [63] */ 40,
/* [64] */ 4,
- /* [65] */ 10,
- /* [66] */ 2,
- /* [67] */ 40,
- /* [68] */ 4,
- /* [69] */ 10,
- /* [70] */ 39,
- /* [71] */ 4,
- /* [72] */ 10,
- /* [73] */ 42,
- /* [74] */ 3,
- /* [75] */ 10,
- /* [76] */ 20,
- /* [77] */ 1,
- /* [78] */ 7,
- /* [79] */ 42,
+ /* [65] */ 6,
+ /* [66] */ 43,
+ /* [67] */ 3,
+ /* [68] */ 6,
+ /* [69] */ 21,
+ /* [70] */ 1,
+ /* [71] */ 0,
+ /* [72] */ 42,
+ /* [73] */ 3,
+ /* [74] */ 6,
+ /* [75] */ 41,
+ /* [76] */ 3,
+ /* [77] */ 6,
+ /* [78] */ 48,
+ /* [79] */ 0,
/* [80] */ 0,
- /* [81] */ 1,
- /* [82] */ 40,
- /* [83] */ 0,
- /* [84] */ 1,
- /* [85] */ 39,
- /* [86] */ 0,
- /* [87] */ 1,
- /* [88] */ 41,
- /* [89] */ 3,
- /* [90] */ 10,
- /* [91] */ 40,
- /* [92] */ 3,
- /* [93] */ 10,
- /* [94] */ 39,
- /* [95] */ 3,
- /* [96] */ 10,
- /* [97] */ 20,
+ /* [81] */ 43,
+ /* [82] */ 0,
+ /* [83] */ 1,
+ /* [84] */ 41,
+ /* [85] */ 0,
+ /* [86] */ 1,
+ /* [87] */ 40,
+ /* [88] */ 0,
+ /* [89] */ 1,
+ /* [90] */ 21,
+ /* [91] */ 0,
+ /* [92] */ 5,
+ /* [93] */ 21,
+ /* [94] */ 0,
+ /* [95] */ 6,
+ /* [96] */ 46,
+ /* [97] */ 0,
/* [98] */ 0,
- /* [99] */ 5,
- /* [100] */ 20,
- /* [101] */ 0,
- /* [102] */ 6,
- /* [103] */ 8,
- /* [104] */ 7,
- /* [105] */ 8,
- /* [106] */ 0,
- /* [107] */ 8,
- /* [108] */ 1,
+ /* [99] */ 40,
+ /* [100] */ 3,
+ /* [101] */ 6,
+ /* [102] */ 17,
+ /* [103] */ 0,
+ /* [104] */ 10,
+ /* [105] */ 7,
+ /* [106] */ 10,
+ /* [107] */ 1,
+ /* [108] */ 10,
/* [109] */ 8,
- /* [110] */ 5,
- /* [111] */ 8,
- /* [112] */ 6,
- /* [113] */ 8,
- /* [114] */ 2,
- /* [115] */ 9,
- /* [116] */ 0,
- /* [117] */ 45,
- /* [118] */ 0,
- /* [119] */ 9,
- /* [120] */ 1,
- /* [121] */ 9,
- /* [122] */ 7,
- /* [123] */ 9,
- /* [124] */ 5,
- /* [125] */ 9,
- /* [126] */ 6,
- /* [127] */ 9,
- /* [128] */ 2,
- /* [129] */ 27,
- /* [130] */ 0,
- /* [131] */ 28,
- /* [132] */ 0,
- /* [133] */ 29,
- /* [134] */ 0,
- /* [135] */ 47,
- /* [136] */ 0,
- /* [137] */ 19,
- /* [138] */ 0,
- /* [139] */ 30,
- /* [140] */ 0,
- /* [141] */ 31,
- /* [142] */ 0,
- /* [143] */ 32,
- /* [144] */ 0,
- /* [145] */ 33,
- /* [146] */ 0,
- /* [147] */ 11,
- /* [148] */ 0,
- /* [149] */ 12,
- /* [150] */ 7,
- /* [151] */ 12,
- /* [152] */ 0,
- /* [153] */ 13,
- /* [154] */ 7,
- /* [155] */ 13,
- /* [156] */ 0,
- /* [157] */ 14,
- /* [158] */ 7,
- /* [159] */ 14,
- /* [160] */ 0,
- /* [161] */ 15,
- /* [162] */ 7,
- /* [163] */ 15,
- /* [164] */ 0,
- /* [165] */ 16,
- /* [166] */ 7,
- /* [167] */ 16,
- /* [168] */ 0,
- /* [169] */ 17,
- /* [170] */ 7,
- /* [171] */ 17,
- /* [172] */ 0,
- /* [173] */ 48,
- /* [174] */ 0,
- /* [175] */ 18,
- /* [176] */ 7,
- /* [177] */ 18,
- /* [178] */ 0,
- /* [179] */ 27,
- /* [180] */ 7,
- /* [181] */ 28,
- /* [182] */ 7,
- /* [183] */ 29,
- /* [184] */ 7,
- /* [185] */ 19,
- /* [186] */ 7,
- /* [187] */ 30,
- /* [188] */ 7,
- /* [189] */ 31,
- /* [190] */ 7,
- /* [191] */ 32,
- /* [192] */ 7,
- /* [193] */ 25,
- /* [194] */ 26,
- /* [195] */ 37,
- /* [196] */ 36,
- /* [197] */ 35,
- /* [198] */ 34,
- /* [199] */ 43,
- /* [200] */ 38,
- /* [201] */ 44,
- /* [202] */ 46,
+ /* [110] */ 10,
+ /* [111] */ 5,
+ /* [112] */ 10,
+ /* [113] */ 0,
+ /* [114] */ 10,
+ /* [115] */ 6,
+ /* [116] */ 9,
+ /* [117] */ 0,
+ /* [118] */ 10,
+ /* [119] */ 2,
+ /* [120] */ 11,
+ /* [121] */ 0,
+ /* [122] */ 9,
+ /* [123] */ 2,
+ /* [124] */ 9,
+ /* [125] */ 1,
+ /* [126] */ 11,
+ /* [127] */ 7,
+ /* [128] */ 9,
+ /* [129] */ 6,
+ /* [130] */ 9,
+ /* [131] */ 5,
+ /* [132] */ 9,
+ /* [133] */ 8,
+ /* [134] */ 9,
+ /* [135] */ 7,
+ /* [136] */ 45,
+ /* [137] */ 0,
+ /* [138] */ 28,
+ /* [139] */ 0,
+ /* [140] */ 29,
+ /* [141] */ 0,
+ /* [142] */ 30,
+ /* [143] */ 0,
+ /* [144] */ 11,
+ /* [145] */ 1,
+ /* [146] */ 31,
+ /* [147] */ 0,
+ /* [148] */ 32,
+ /* [149] */ 0,
+ /* [150] */ 11,
+ /* [151] */ 8,
+ /* [152] */ 33,
+ /* [153] */ 0,
+ /* [154] */ 34,
+ /* [155] */ 0,
+ /* [156] */ 11,
+ /* [157] */ 5,
+ /* [158] */ 11,
+ /* [159] */ 6,
+ /* [160] */ 11,
+ /* [161] */ 2,
+ /* [162] */ 12,
+ /* [163] */ 0,
+ /* [164] */ 12,
+ /* [165] */ 7,
+ /* [166] */ 12,
+ /* [167] */ 8,
+ /* [168] */ 13,
+ /* [169] */ 0,
+ /* [170] */ 13,
+ /* [171] */ 7,
+ /* [172] */ 47,
+ /* [173] */ 0,
+ /* [174] */ 13,
+ /* [175] */ 8,
+ /* [176] */ 14,
+ /* [177] */ 0,
+ /* [178] */ 14,
+ /* [179] */ 7,
+ /* [180] */ 14,
+ /* [181] */ 8,
+ /* [182] */ 15,
+ /* [183] */ 0,
+ /* [184] */ 15,
+ /* [185] */ 7,
+ /* [186] */ 15,
+ /* [187] */ 8,
+ /* [188] */ 16,
+ /* [189] */ 0,
+ /* [190] */ 16,
+ /* [191] */ 7,
+ /* [192] */ 16,
+ /* [193] */ 8,
+ /* [194] */ 17,
+ /* [195] */ 7,
+ /* [196] */ 17,
+ /* [197] */ 8,
+ /* [198] */ 18,
+ /* [199] */ 0,
+ /* [200] */ 18,
+ /* [201] */ 7,
+ /* [202] */ 18,
+ /* [203] */ 8,
+ /* [204] */ 19,
+ /* [205] */ 0,
+ /* [206] */ 49,
+ /* [207] */ 0,
+ /* [208] */ 28,
+ /* [209] */ 7,
+ /* [210] */ 29,
+ /* [211] */ 7,
+ /* [212] */ 30,
+ /* [213] */ 7,
+ /* [214] */ 31,
+ /* [215] */ 7,
+ /* [216] */ 19,
+ /* [217] */ 7,
+ /* [218] */ 19,
+ /* [219] */ 8,
+ /* [220] */ 32,
+ /* [221] */ 7,
+ /* [222] */ 33,
+ /* [223] */ 7,
+ /* [224] */ 20,
+ /* [225] */ 0,
+ /* [226] */ 20,
+ /* [227] */ 7,
+ /* [228] */ 20,
+ /* [229] */ 8,
+ /* [230] */ 26,
+ /* [231] */ 38,
+ /* [232] */ 27,
+ /* [233] */ 37,
+ /* [234] */ 36,
+ /* [235] */ 35,
+ /* [236] */ 44,
+ /* [237] */ 39,
};
// Assert that the MatcherIndex is big enough to index all the matchers, plus
@@ -2890,2632 +3282,2632 @@ constexpr ParameterInfo kParameters[] = {
{
/* [65] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [66] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [67] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [68] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [69] */
/* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [70] */
/* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [71] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [72] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [73] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [74] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [75] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [76] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [77] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [78] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [79] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [80] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [81] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kDdx,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [82] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kDdy,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [83] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [84] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [85] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [86] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [87] */
- /* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [88] */
- /* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [89] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [90] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [91] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [92] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [93] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [94] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [95] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [96] */
/* usage */ ParameterUsage::kComponent,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [97] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[133],
+ /* matcher indices */ &kMatcherIndices[142],
},
{
/* [98] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [99] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [100] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [101] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [102] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [103] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [104] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [105] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [106] */
/* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [107] */
/* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [108] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [109] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [110] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [111] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kDdx,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [112] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kDdy,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [113] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [114] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [115] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [116] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [117] */
- /* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [118] */
- /* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [119] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[123],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [120] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[191],
+ /* matcher indices */ &kMatcherIndices[222],
},
{
/* [121] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [122] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [123] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [124] */
/* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [125] */
/* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [126] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [127] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [128] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [129] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [130] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [131] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [132] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [133] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [134] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [135] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [136] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [137] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [138] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [139] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [140] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [141] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [142] */
/* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [143] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [144] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [145] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [146] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [147] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [148] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [149] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [150] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [151] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [152] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [153] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [154] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [155] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [156] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [157] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [158] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [159] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [160] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [161] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [162] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [163] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [164] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [165] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[191],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [166] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [167] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [168] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [169] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [170] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* usage */ ParameterUsage::kComponent,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [171] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[152],
},
{
/* [172] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [173] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [174] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [175] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [176] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [177] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [178] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [179] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[123],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [180] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [181] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [182] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [183] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kDdx,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [184] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kDdy,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [185] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [186] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [187] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [188] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [189] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [190] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [191] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [192] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [193] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [194] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [195] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [196] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [197] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [198] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [199] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [200] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [201] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [202] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [203] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [204] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [205] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [206] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [207] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [208] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [209] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [210] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[189],
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [211] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [212] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [213] */
- /* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [214] */
- /* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [215] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* usage */ ParameterUsage::kComponent,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [216] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[142],
},
{
/* [217] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [218] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [219] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [220] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [221] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [222] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [223] */
- /* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [224] */
- /* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [225] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [226] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [227] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [228] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [229] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [230] */
- /* usage */ ParameterUsage::kComponent,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [231] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[143],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [232] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [233] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [234] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [235] */
- /* usage */ ParameterUsage::kComponent,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [236] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[133],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [237] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [238] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kDdx,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [239] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kDdy,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [240] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [241] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [242] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [243] */
- /* usage */ ParameterUsage::kDdx,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [244] */
- /* usage */ ParameterUsage::kDdy,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [245] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* matcher indices */ &kMatcherIndices[220],
},
{
/* [246] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [247] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [248] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kDdx,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [249] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kDdy,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [250] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* usage */ ParameterUsage::kComponent,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [251] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[140],
},
{
/* [252] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [253] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [254] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[123],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [255] */
- /* usage */ ParameterUsage::kComponent,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [256] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[131],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [257] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [258] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [259] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [260] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [261] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [262] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [263] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [264] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [265] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [266] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [267] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [268] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [269] */
/* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [270] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[191],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [271] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [272] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [273] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [274] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [275] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [276] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [277] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [278] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [279] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [280] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[222],
},
{
/* [281] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [282] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [283] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [284] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [285] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[222],
},
{
/* [286] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [287] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [288] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [289] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [290] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [291] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [292] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [293] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [294] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [295] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* matcher indices */ &kMatcherIndices[220],
},
{
/* [296] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [297] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [298] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [299] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [300] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [301] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [302] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [303] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [304] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [305] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [306] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [307] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[189],
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [308] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [309] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [310] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [311] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* matcher indices */ &kMatcherIndices[54],
},
{
/* [312] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [313] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [314] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[156],
},
{
/* [315] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [316] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [317] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [318] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [319] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [320] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [321] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [322] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [323] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[133],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [324] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [325] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [326] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [327] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* matcher indices */ &kMatcherIndices[222],
},
{
/* [328] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [329] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [330] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [331] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [332] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [333] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [334] */
- /* usage */ ParameterUsage::kBias,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [335] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* matcher indices */ &kMatcherIndices[72],
},
{
/* [336] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [337] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [338] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[126],
},
{
/* [339] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[189],
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [340] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [341] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [342] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [343] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [344] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [345] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [346] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [347] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[212],
},
{
/* [348] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [349] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [350] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [351] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[191],
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [352] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [353] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [354] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [355] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [356] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [357] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [358] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[123],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [359] */
- /* usage */ ParameterUsage::kComponent,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[36],
},
{
/* [360] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[131],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [361] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [362] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[158],
},
{
/* [363] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[183],
+ /* matcher indices */ &kMatcherIndices[142],
},
{
/* [364] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [365] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [366] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [367] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [368] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [369] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [370] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [371] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [372] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [373] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [374] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [375] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [376] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [377] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [378] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [379] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [380] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [381] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [382] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kArrayIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [383] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[88],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [384] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [385] */
/* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [386] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[45],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [387] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[63],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [388] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [389] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [390] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[57],
+ /* usage */ ParameterUsage::kOffset,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [391] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [392] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[194],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [393] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [394] */
- /* usage */ ParameterUsage::kDepthRef,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [395] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [396] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [397] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [398] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [399] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[47],
+ /* usage */ ParameterUsage::kX,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [400] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kY,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [401] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kZ,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [402] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[61],
+ /* usage */ ParameterUsage::kW,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [403] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [404] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [405] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [406] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [407] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* usage */ ParameterUsage::kComponent,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [408] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[148],
},
{
/* [409] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [410] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [411] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [412] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [413] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [414] */
- /* usage */ ParameterUsage::kArrayIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [415] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [416] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [417] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [418] */
- /* usage */ ParameterUsage::kOffset,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [419] */
- /* usage */ ParameterUsage::kX,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [420] */
- /* usage */ ParameterUsage::kY,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[232],
},
{
/* [421] */
- /* usage */ ParameterUsage::kZ,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [422] */
- /* usage */ ParameterUsage::kW,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kDepthRef,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [423] */
- /* usage */ ParameterUsage::kComponent,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [424] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[141],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [425] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [426] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [427] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [428] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [429] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [430] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [431] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kComponent,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [432] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[140],
},
{
/* [433] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [434] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [435] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[220],
},
{
/* [436] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [437] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [438] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [439] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [440] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [441] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [442] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kBias,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [443] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [444] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [445] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [446] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [447] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [448] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [449] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [450] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [451] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [452] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [453] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [454] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [455] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [456] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[199],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [457] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [458] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [459] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [460] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [461] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [462] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [463] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [464] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [465] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[42],
},
{
/* [466] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [467] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[158],
},
{
/* [468] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [469] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [470] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [471] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [472] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [473] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [474] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [475] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [476] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [477] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[94],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [478] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [479] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[45],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [480] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[91],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [481] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [482] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[45],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [483] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[73],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [484] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[123],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [485] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[45],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [486] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[70],
+ /* matcher indices */ &kMatcherIndices[99],
},
{
/* [487] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [488] */
/* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[57],
+ /* matcher indices */ &kMatcherIndices[126],
},
{
/* [489] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[67],
+ /* matcher indices */ &kMatcherIndices[220],
},
{
/* [490] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [491] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[57],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [492] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[59],
+ /* matcher indices */ &kMatcherIndices[75],
},
{
/* [493] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[123],
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [494] */
/* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[57],
+ /* matcher indices */ &kMatcherIndices[126],
},
{
/* [495] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[214],
},
{
/* [496] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [497] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [498] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[66],
},
{
/* [499] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [500] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[126],
},
{
/* [501] */
- /* usage */ ParameterUsage::kX,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[63],
},
{
/* [502] */
- /* usage */ ParameterUsage::kY,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [503] */
- /* usage */ ParameterUsage::kZw,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[156],
},
{
/* [504] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[57],
},
{
/* [505] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [506] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[156],
},
{
/* [507] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[210],
},
{
/* [508] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [509] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [510] */
- /* usage */ ParameterUsage::kX,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[208],
},
{
/* [511] */
- /* usage */ ParameterUsage::kYz,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [512] */
- /* usage */ ParameterUsage::kW,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [513] */
- /* usage */ ParameterUsage::kXy,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[51],
},
{
/* [514] */
- /* usage */ ParameterUsage::kZ,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [515] */
- /* usage */ ParameterUsage::kW,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kValue,
+ /* matcher indices */ &kMatcherIndices[156],
},
{
/* [516] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[55],
+ /* matcher indices */ &kMatcherIndices[45],
},
{
/* [517] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [518] */
/* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[61],
+ /* matcher indices */ &kMatcherIndices[158],
},
{
/* [519] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[51],
+ /* matcher indices */ &kMatcherIndices[33],
},
{
/* [520] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [521] */
/* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[61],
+ /* matcher indices */ &kMatcherIndices[158],
},
{
/* [522] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[138],
},
{
/* [523] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [524] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [525] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [526] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [527] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [528] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[140],
},
{
/* [529] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [530] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [531] */
- /* usage */ ParameterUsage::kX,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[146],
},
{
/* [532] */
- /* usage */ ParameterUsage::kY,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[110],
},
{
/* [533] */
- /* usage */ ParameterUsage::kZ,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [534] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [535] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [536] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [537] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[43],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [538] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[123],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [539] */
- /* usage */ ParameterUsage::kValue,
- /* matcher indices */ &kMatcherIndices[61],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [540] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[129],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [541] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [542] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [543] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[131],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [544] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [545] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [546] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [547] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [548] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [549] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[154],
},
{
/* [550] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [551] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kSampleIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [552] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [553] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [554] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [555] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [556] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [557] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kSampleIndex,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [558] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [559] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kSampler,
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [560] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [561] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [562] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [563] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [564] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[189],
+ /* usage */ ParameterUsage::kXy,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [565] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kZ,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [566] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kW,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [567] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [568] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [569] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [570] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[187],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [571] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [572] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [573] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[139],
+ /* usage */ ParameterUsage::kX,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [574] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[123],
+ /* usage */ ParameterUsage::kYz,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [575] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kW,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [576] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[145],
+ /* usage */ ParameterUsage::kX,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [577] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kY,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [578] */
- /* usage */ ParameterUsage::kSampleIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kZw,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [579] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [580] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [581] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [582] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[181],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [583] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [584] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[103],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [585] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[179],
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [586] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* matcher indices */ &kMatcherIndices[230],
},
{
/* [587] */
/* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[104],
},
{
/* [588] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[200],
+ /* usage */ ParameterUsage::kX,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [589] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kY,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [590] */
- /* usage */ ParameterUsage::kSampleIndex,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kZ,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [591] */
@@ -5530,327 +5922,327 @@ constexpr ParameterInfo kParameters[] = {
{
/* [593] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [594] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [595] */
- /* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[193],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [596] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[121],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [597] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [598] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [599] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [600] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [601] */
- /* usage */ ParameterUsage::kNone,
+ /* usage */ ParameterUsage::kX,
/* matcher indices */ &kMatcherIndices[1],
},
{
/* [602] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kZyw,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [603] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kXyz,
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [604] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kW,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [605] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kXy,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [606] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kZw,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [607] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kX,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [608] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kYz,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [609] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kXy,
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [610] */
- /* usage */ ParameterUsage::kNone,
+ /* usage */ ParameterUsage::kZ,
/* matcher indices */ &kMatcherIndices[1],
},
{
/* [611] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[129],
+ /* usage */ ParameterUsage::kX,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [612] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kY,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [613] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [614] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [615] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[131],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [616] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[93],
},
{
/* [617] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[138],
},
{
/* [618] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [619] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[133],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [620] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [621] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[140],
},
{
/* [622] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [623] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[139],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [624] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[93],
},
{
/* [625] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[142],
},
{
/* [626] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [627] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[141],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [628] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [629] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[146],
},
{
/* [630] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [631] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[143],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [632] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [633] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[148],
},
{
/* [634] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [635] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [636] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [637] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* matcher indices */ &kMatcherIndices[152],
},
{
/* [638] */
/* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [639] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [640] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [641] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [642] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [643] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [644] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [645] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [646] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [647] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [648] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [649] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [650] */
- /* usage */ ParameterUsage::kLevel,
- /* matcher indices */ &kMatcherIndices[44],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [651] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [652] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [653] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [654] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [655] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [656] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kLevel,
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [657] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [658] */
@@ -5860,82 +6252,82 @@ constexpr ParameterInfo kParameters[] = {
{
/* [659] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [660] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [661] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [662] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [663] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[19],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [664] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[23],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [665] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[76],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [666] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [667] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [668] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [669] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [670] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [671] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [672] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [673] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [674] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [675] */
@@ -5950,77 +6342,77 @@ constexpr ParameterInfo kParameters[] = {
{
/* [677] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [678] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [679] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [680] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [681] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [682] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [683] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [684] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [685] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [686] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [687] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [688] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [689] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [690] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [691] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [692] */
@@ -6030,17 +6422,17 @@ constexpr ParameterInfo kParameters[] = {
{
/* [693] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [694] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [695] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [696] */
@@ -6050,27 +6442,27 @@ constexpr ParameterInfo kParameters[] = {
{
/* [697] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [698] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [699] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [700] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [701] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [702] */
@@ -6080,17 +6472,17 @@ constexpr ParameterInfo kParameters[] = {
{
/* [703] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [704] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [705] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [706] */
@@ -6100,17 +6492,17 @@ constexpr ParameterInfo kParameters[] = {
{
/* [707] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [708] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [709] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [710] */
@@ -6120,37 +6512,37 @@ constexpr ParameterInfo kParameters[] = {
{
/* [711] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[14],
},
{
/* [712] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[18],
},
{
/* [713] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[69],
},
{
/* [714] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [715] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [716] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [717] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [718] */
@@ -6160,27 +6552,27 @@ constexpr ParameterInfo kParameters[] = {
{
/* [719] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [720] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [721] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [722] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [723] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [724] */
@@ -6190,47 +6582,47 @@ constexpr ParameterInfo kParameters[] = {
{
/* [725] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[0],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [726] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [727] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[199],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [728] */
- /* usage */ ParameterUsage::kCoords,
- /* matcher indices */ &kMatcherIndices[109],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [729] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [730] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [731] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [732] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [733] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [734] */
@@ -6240,12 +6632,12 @@ constexpr ParameterInfo kParameters[] = {
{
/* [735] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [736] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [737] */
@@ -6270,232 +6662,232 @@ constexpr ParameterInfo kParameters[] = {
{
/* [741] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [742] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [743] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [744] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [745] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [746] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [747] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [748] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [749] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [750] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [751] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [752] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [753] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [754] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[100],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [755] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [756] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [757] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [758] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[100],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [759] */
- /* usage */ ParameterUsage::kX,
+ /* usage */ ParameterUsage::kNone,
/* matcher indices */ &kMatcherIndices[1],
},
{
/* [760] */
- /* usage */ ParameterUsage::kY,
+ /* usage */ ParameterUsage::kNone,
/* matcher indices */ &kMatcherIndices[1],
},
{
/* [761] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [762] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [763] */
- /* usage */ ParameterUsage::kXy,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [764] */
- /* usage */ ParameterUsage::kZ,
+ /* usage */ ParameterUsage::kNone,
/* matcher indices */ &kMatcherIndices[1],
},
{
/* [765] */
- /* usage */ ParameterUsage::kX,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [766] */
- /* usage */ ParameterUsage::kYz,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [767] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [768] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [769] */
- /* usage */ ParameterUsage::kXy,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [770] */
- /* usage */ ParameterUsage::kZw,
- /* matcher indices */ &kMatcherIndices[105],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [771] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [772] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [773] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [774] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [775] */
- /* usage */ ParameterUsage::kXyz,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[0],
},
{
/* [776] */
- /* usage */ ParameterUsage::kW,
+ /* usage */ ParameterUsage::kNone,
/* matcher indices */ &kMatcherIndices[1],
},
{
/* [777] */
- /* usage */ ParameterUsage::kX,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [778] */
- /* usage */ ParameterUsage::kZyw,
- /* matcher indices */ &kMatcherIndices[115],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[90],
},
{
/* [779] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [780] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [781] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [782] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [783] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [784] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* usage */ ParameterUsage::kCoords,
+ /* matcher indices */ &kMatcherIndices[130],
},
{
/* [785] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [786] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [787] */
@@ -6510,227 +6902,227 @@ constexpr ParameterInfo kParameters[] = {
{
/* [789] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [790] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [791] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [792] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[121],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [793] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [794] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [795] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [796] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [797] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [798] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [799] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [800] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [801] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [802] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[97],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [803] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [804] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [805] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [806] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [807] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [808] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [809] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[15],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [810] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [811] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [812] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [813] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [814] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [815] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [816] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [817] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [818] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [819] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [820] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [821] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [822] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [823] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [824] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [825] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [826] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [827] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[26],
},
{
/* [828] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [829] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [830] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[60],
},
{
/* [831] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [832] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [833] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [834] */
@@ -6739,63 +7131,63 @@ constexpr ParameterInfo kParameters[] = {
},
{
/* [835] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [836] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [837] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [838] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [839] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [840] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[34],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [841] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [842] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [843] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [844] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[200],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [845] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[145],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [846] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [847] */
@@ -6804,63 +7196,63 @@ constexpr ParameterInfo kParameters[] = {
},
{
/* [848] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [849] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [850] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [851] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[143],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [852] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[141],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [853] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[139],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [854] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[133],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [855] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[131],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [856] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[129],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [857] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[34],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [858] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [859] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [860] */
@@ -6870,7 +7262,7 @@ constexpr ParameterInfo kParameters[] = {
{
/* [861] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [862] */
@@ -6880,292 +7272,292 @@ constexpr ParameterInfo kParameters[] = {
{
/* [863] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [864] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [865] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [866] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[143],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[134],
},
{
/* [867] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[133],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[126],
},
{
/* [868] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[126],
},
{
/* [869] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [870] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[154],
},
{
/* [871] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [872] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [873] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [874] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [875] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[152],
},
{
/* [876] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[148],
},
{
/* [877] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[146],
},
{
/* [878] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[142],
},
{
/* [879] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[140],
},
{
/* [880] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[138],
},
{
/* [881] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[48],
},
{
/* [882] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[231],
},
{
/* [883] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[199],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [884] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[79],
+ /* matcher indices */ &kMatcherIndices[152],
},
{
/* [885] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[142],
},
{
/* [886] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[82],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [887] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[85],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [888] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[200],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [889] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[195],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [890] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[196],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [891] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[197],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [892] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[198],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [893] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[145],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [894] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[143],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [895] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[141],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [896] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[139],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [897] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[133],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [898] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[131],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [899] */
- /* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[129],
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [900] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [901] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [902] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[81],
},
{
/* [903] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[48],
},
{
/* [904] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[84],
},
{
/* [905] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[87],
},
{
/* [906] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[228],
},
{
/* [907] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [908] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[11],
+ /* matcher indices */ &kMatcherIndices[226],
},
{
/* [909] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[233],
},
{
/* [910] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [911] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [912] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[154],
},
{
/* [913] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[152],
},
{
/* [914] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[148],
},
{
/* [915] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[146],
},
{
/* [916] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[142],
},
{
/* [917] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[140],
},
{
/* [918] */
- /* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* usage */ ParameterUsage::kTexture,
+ /* matcher indices */ &kMatcherIndices[138],
},
{
/* [919] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[185],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [920] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[44],
+ /* matcher indices */ &kMatcherIndices[34],
},
{
/* [921] */
@@ -7175,12 +7567,12 @@ constexpr ParameterInfo kParameters[] = {
{
/* [922] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[224],
},
{
/* [923] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [924] */
@@ -7190,12 +7582,12 @@ constexpr ParameterInfo kParameters[] = {
{
/* [925] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[218],
},
{
/* [926] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[4],
},
{
/* [927] */
@@ -7205,12 +7597,12 @@ constexpr ParameterInfo kParameters[] = {
{
/* [928] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[216],
},
{
/* [929] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* matcher indices */ &kMatcherIndices[109],
},
{
/* [930] */
@@ -7220,12 +7612,12 @@ constexpr ParameterInfo kParameters[] = {
{
/* [931] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[175],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [932] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[105],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [933] */
@@ -7235,117 +7627,117 @@ constexpr ParameterInfo kParameters[] = {
{
/* [934] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [935] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[107],
+ /* matcher indices */ &kMatcherIndices[116],
},
{
/* [936] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[107],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [937] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[107],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [938] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[107],
+ /* matcher indices */ &kMatcherIndices[124],
},
{
/* [939] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* matcher indices */ &kMatcherIndices[124],
},
{
/* [940] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[115],
+ /* matcher indices */ &kMatcherIndices[124],
},
{
/* [941] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[124],
},
{
/* [942] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[124],
},
{
/* [943] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[204],
},
{
/* [944] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[112],
},
{
/* [945] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[119],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [946] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[119],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [947] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[119],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [948] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[119],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [949] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* matcher indices */ &kMatcherIndices[106],
},
{
/* [950] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[49],
+ /* matcher indices */ &kMatcherIndices[106],
},
{
/* [951] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[106],
},
{
/* [952] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[106],
},
{
/* [953] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[37],
+ /* matcher indices */ &kMatcherIndices[106],
},
{
/* [954] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[202],
},
{
/* [955] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[120],
},
{
/* [956] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [957] */
@@ -7355,162 +7747,232 @@ constexpr ParameterInfo kParameters[] = {
{
/* [958] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[45],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [959] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[53],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [960] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[53],
+ /* matcher indices */ &kMatcherIndices[5],
},
{
/* [961] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[53],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [962] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[53],
+ /* matcher indices */ &kMatcherIndices[35],
},
{
/* [963] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [964] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[4],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [965] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[144],
},
{
/* [966] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[144],
},
{
/* [967] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[144],
},
{
/* [968] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[169],
+ /* matcher indices */ &kMatcherIndices[144],
},
{
/* [969] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[149],
+ /* matcher indices */ &kMatcherIndices[200],
},
{
/* [970] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[162],
},
{
/* [971] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [972] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[10],
},
{
/* [973] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[164],
},
{
/* [974] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[153],
+ /* matcher indices */ &kMatcherIndices[166],
},
{
/* [975] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [976] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[5],
+ /* matcher indices */ &kMatcherIndices[168],
},
{
/* [977] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[103],
+ /* matcher indices */ &kMatcherIndices[39],
},
{
/* [978] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[21],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [979] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[157],
+ /* matcher indices */ &kMatcherIndices[170],
},
{
/* [980] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[174],
},
{
/* [981] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[6],
+ /* matcher indices */ &kMatcherIndices[16],
},
{
/* [982] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[31],
+ /* matcher indices */ &kMatcherIndices[176],
},
{
/* [983] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[30],
},
{
/* [984] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[161],
+ /* matcher indices */ &kMatcherIndices[1],
},
{
/* [985] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[1],
+ /* matcher indices */ &kMatcherIndices[178],
},
{
/* [986] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[40],
+ /* matcher indices */ &kMatcherIndices[180],
},
{
/* [987] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[62],
+ /* matcher indices */ &kMatcherIndices[198],
},
{
/* [988] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[165],
+ /* matcher indices */ &kMatcherIndices[182],
},
{
/* [989] */
/* usage */ ParameterUsage::kNone,
- /* matcher indices */ &kMatcherIndices[45],
+ /* matcher indices */ &kMatcherIndices[1],
+ },
+ {
+ /* [990] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
+ },
+ {
+ /* [991] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[184],
+ },
+ {
+ /* [992] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[186],
+ },
+ {
+ /* [993] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[196],
+ },
+ {
+ /* [994] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[188],
+ },
+ {
+ /* [995] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
+ },
+ {
+ /* [996] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[30],
+ },
+ {
+ /* [997] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[190],
+ },
+ {
+ /* [998] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[192],
+ },
+ {
+ /* [999] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[194],
+ },
+ {
+ /* [1000] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[102],
+ },
+ {
+ /* [1001] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[60],
+ },
+ {
+ /* [1002] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[1],
+ },
+ {
+ /* [1003] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[144],
},
};
@@ -7518,22 +7980,22 @@ constexpr TemplateTypeInfo kTemplateTypes[] = {
{
/* [0] */
/* name */ "T",
- /* matcher index */ 2,
+ /* matcher index */ 7,
},
{
/* [1] */
/* name */ "U",
- /* matcher index */ 58,
+ /* matcher index */ 52,
},
{
/* [2] */
/* name */ "T",
- /* matcher index */ 7,
+ /* matcher index */ 8,
},
{
/* [3] */
/* name */ "U",
- /* matcher index */ 55,
+ /* matcher index */ 53,
},
{
/* [4] */
@@ -7543,7 +8005,7 @@ constexpr TemplateTypeInfo kTemplateTypes[] = {
{
/* [5] */
/* name */ "U",
- /* matcher index */ 56,
+ /* matcher index */ 54,
},
{
/* [6] */
@@ -7553,67 +8015,97 @@ constexpr TemplateTypeInfo kTemplateTypes[] = {
{
/* [7] */
/* name */ "U",
- /* matcher index */ 57,
+ /* matcher index */ 55,
},
{
/* [8] */
/* name */ "T",
- /* matcher index */ 49,
+ /* matcher index */ 2,
},
{
/* [9] */
- /* name */ "f32",
- /* matcher index */ kNoMatcher,
+ /* name */ "U",
+ /* matcher index */ 56,
},
{
/* [10] */
/* name */ "T",
- /* matcher index */ 54,
+ /* matcher index */ 62,
},
{
/* [11] */
/* name */ "T",
- /* matcher index */ 51,
+ /* matcher index */ 67,
},
{
/* [12] */
/* name */ "T",
- /* matcher index */ 53,
+ /* matcher index */ 61,
},
{
/* [13] */
/* name */ "T",
- /* matcher index */ 52,
+ /* matcher index */ 57,
},
{
/* [14] */
/* name */ "T",
- /* matcher index */ kNoMatcher,
+ /* matcher index */ 68,
},
{
/* [15] */
/* name */ "T",
- /* matcher index */ 58,
+ /* matcher index */ 63,
},
{
/* [16] */
/* name */ "T",
- /* matcher index */ 55,
+ /* matcher index */ 51,
},
{
/* [17] */
/* name */ "T",
- /* matcher index */ 57,
+ /* matcher index */ 64,
},
{
/* [18] */
/* name */ "T",
- /* matcher index */ 56,
+ /* matcher index */ 50,
},
{
/* [19] */
/* name */ "T",
- /* matcher index */ 50,
+ /* matcher index */ kNoMatcher,
+ },
+ {
+ /* [20] */
+ /* name */ "T",
+ /* matcher index */ 56,
+ },
+ {
+ /* [21] */
+ /* name */ "T",
+ /* matcher index */ 53,
+ },
+ {
+ /* [22] */
+ /* name */ "T",
+ /* matcher index */ 52,
+ },
+ {
+ /* [23] */
+ /* name */ "T",
+ /* matcher index */ 55,
+ },
+ {
+ /* [24] */
+ /* name */ "T",
+ /* matcher index */ 54,
+ },
+ {
+ /* [25] */
+ /* name */ "T",
+ /* matcher index */ 58,
},
};
@@ -7666,7 +8158,7 @@ constexpr TemplateNumberInfo kTemplateNumbers[] = {
{
/* [9] */
/* name */ "S",
- /* matcher index */ 8,
+ /* matcher index */ 9,
},
};
@@ -7676,10 +8168,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[899],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[918],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7688,10 +8180,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[611],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[617],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7700,10 +8192,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[898],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[917],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7712,10 +8204,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[615],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[621],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7724,10 +8216,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[897],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[916],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7736,10 +8228,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[619],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[625],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7748,10 +8240,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[896],
- /* return matcher indices */ &kMatcherIndices[123],
+ /* parameters */ &kParameters[915],
+ /* return matcher indices */ &kMatcherIndices[110],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7760,10 +8252,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[623],
- /* return matcher indices */ &kMatcherIndices[123],
+ /* parameters */ &kParameters[629],
+ /* return matcher indices */ &kMatcherIndices[110],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7772,10 +8264,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[895],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[914],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7784,10 +8276,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[627],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[633],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7796,10 +8288,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[894],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[913],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7808,10 +8300,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[631],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[637],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7820,10 +8312,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[893],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[912],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7832,10 +8324,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[892],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[911],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7844,10 +8336,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[637],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[643],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7856,10 +8348,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[891],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[910],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7868,10 +8360,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[641],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[647],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7880,10 +8372,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[890],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[909],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7892,10 +8384,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[645],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[651],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7904,10 +8396,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[889],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[835],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7916,10 +8408,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[649],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[655],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7928,10 +8420,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[888],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[907],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7940,10 +8432,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[3],
- /* parameters */ &kParameters[887],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[905],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7952,10 +8444,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[3],
- /* parameters */ &kParameters[886],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[904],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7964,10 +8456,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[3],
- /* parameters */ &kParameters[840],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[903],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7976,10 +8468,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[3],
- /* parameters */ &kParameters[884],
- /* return matcher indices */ &kMatcherIndices[123],
+ /* parameters */ &kParameters[902],
+ /* return matcher indices */ &kMatcherIndices[110],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -7988,263 +8480,263 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[883],
- /* return matcher indices */ &kMatcherIndices[109],
+ /* parameters */ &kParameters[901],
+ /* return matcher indices */ &kMatcherIndices[130],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [27] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* num parameters */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[585],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
},
{
/* [28] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[582],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[955],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
},
{
/* [29] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[367],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[956],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecSplat,
},
{
/* [30] */
/* num parameters */ 4,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[363],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[399],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorS,
},
{
/* [31] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 3,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[215],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[564],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [32] */
/* num parameters */ 3,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[570],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[573],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [33] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 3,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[355],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[576],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [34] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[564],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[605],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [35] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[351],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[603],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [36] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[546],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[601],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [37] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[347],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1003],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [38] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[343],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[965],
+ /* return matcher indices */ &kMatcherIndices[150],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [39] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[4],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[200],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[966],
+ /* return matcher indices */ &kMatcherIndices[156],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [40] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[6],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[534],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[967],
+ /* return matcher indices */ &kMatcherIndices[158],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [41] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[8],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[335],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[968],
+ /* return matcher indices */ &kMatcherIndices[160],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [42] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[319],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[510],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [43] */
- /* num parameters */ 5,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[195],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[507],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [44] */
- /* num parameters */ 5,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[190],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[351],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [45] */
- /* num parameters */ 6,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[126],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[347],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [46] */
- /* num parameters */ 4,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[327],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[230],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [47] */
- /* num parameters */ 5,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[175],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[495],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
@@ -8252,23 +8744,23 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[339],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[331],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [49] */
- /* num parameters */ 5,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[165],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[489],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
@@ -8276,274 +8768,274 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[371],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[327],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [51] */
- /* num parameters */ 5,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[155],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[474],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [52] */
- /* num parameters */ 5,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[150],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[323],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [53] */
- /* num parameters */ 6,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[72],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[319],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [54] */
- /* num parameters */ 4,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[379],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[165],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [55] */
- /* num parameters */ 5,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[170],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[462],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [56] */
- /* num parameters */ 3,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[456],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[339],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [57] */
- /* num parameters */ 0,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[315],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [58] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[950],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[265],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [59] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[951],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[260],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [60] */
- /* num parameters */ 4,
- /* num template types */ 1,
+ /* num parameters */ 6,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[419],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[132],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [61] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[513],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[299],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [62] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[510],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[205],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [63] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[501],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[295],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [64] */
- /* num parameters */ 2,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[769],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[285],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [65] */
- /* num parameters */ 2,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[775],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[303],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [66] */
- /* num parameters */ 2,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[777],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[275],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [67] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[2],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[959],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[270],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [68] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 6,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[4],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[960],
- /* return matcher indices */ &kMatcherIndices[57],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[90],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [69] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[6],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[961],
- /* return matcher indices */ &kMatcherIndices[61],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[307],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [70] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[0],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[962],
- /* return matcher indices */ &kMatcherIndices[65],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[255],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [71] */
- /* num parameters */ 4,
- /* num template types */ 1,
+ /* num parameters */ 3,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[359],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[471],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [72] */
- /* num parameters */ 5,
+ /* num parameters */ 4,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[255],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[431],
+ /* return matcher indices */ &kMatcherIndices[120],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -8552,70 +9044,70 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 5,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[235],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[250],
+ /* return matcher indices */ &kMatcherIndices[120],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [74] */
- /* num parameters */ 6,
+ /* num parameters */ 5,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[96],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[215],
+ /* return matcher indices */ &kMatcherIndices[120],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [75] */
- /* num parameters */ 4,
+ /* num parameters */ 6,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[423],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[96],
+ /* return matcher indices */ &kMatcherIndices[120],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [76] */
- /* num parameters */ 5,
+ /* num parameters */ 4,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[230],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[407],
+ /* return matcher indices */ &kMatcherIndices[120],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [77] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* num parameters */ 5,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[447],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[170],
+ /* return matcher indices */ &kMatcherIndices[120],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [78] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[415],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[558],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -8624,58 +9116,58 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[411],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[387],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [80] */
- /* num parameters */ 5,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[225],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[379],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [81] */
- /* num parameters */ 3,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[594],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[160],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [82] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[395],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[585],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [83] */
- /* num parameters */ 3,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[477],
- /* return matcher indices */ nullptr,
+ /* parameters */ &kParameters[375],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -8684,33 +9176,33 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[480],
+ /* parameters */ &kParameters[486],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [85] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[383],
+ /* parameters */ &kParameters[492],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [86] */
- /* num parameters */ 3,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[483],
+ /* parameters */ &kParameters[335],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
@@ -8720,9 +9212,9 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[486],
+ /* parameters */ &kParameters[498],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
@@ -8732,33 +9224,33 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[489],
+ /* parameters */ &kParameters[501],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [89] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[387],
+ /* parameters */ &kParameters[504],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [90] */
- /* num parameters */ 3,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[492],
+ /* parameters */ &kParameters[311],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
@@ -8768,9 +9260,9 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[516],
+ /* parameters */ &kParameters[513],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
@@ -8780,190 +9272,190 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[519],
+ /* parameters */ &kParameters[516],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [93] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[399],
+ /* parameters */ &kParameters[465],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [94] */
- /* num parameters */ 3,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[537],
+ /* parameters */ &kParameters[359],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [95] */
- /* num parameters */ 0,
- /* num template types */ 1,
+ /* num parameters */ 3,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[115],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[519],
+ /* return matcher indices */ nullptr,
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [96] */
- /* num parameters */ 1,
+ /* num parameters */ 0,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[940],
- /* return matcher indices */ &kMatcherIndices[115],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[112],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
/* [97] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[941],
- /* return matcher indices */ &kMatcherIndices[115],
+ /* parameters */ &kParameters[944],
+ /* return matcher indices */ &kMatcherIndices[112],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
/* [98] */
- /* num parameters */ 3,
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[531],
- /* return matcher indices */ &kMatcherIndices[115],
+ /* parameters */ &kParameters[945],
+ /* return matcher indices */ &kMatcherIndices[112],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::VecSplat,
},
{
/* [99] */
- /* num parameters */ 2,
+ /* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[763],
- /* return matcher indices */ &kMatcherIndices[115],
+ /* parameters */ &kParameters[588],
+ /* return matcher indices */ &kMatcherIndices[112],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::VecCtorS,
},
{
/* [100] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[765],
- /* return matcher indices */ &kMatcherIndices[115],
+ /* parameters */ &kParameters[609],
+ /* return matcher indices */ &kMatcherIndices[112],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [101] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[2],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[945],
- /* return matcher indices */ &kMatcherIndices[121],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[607],
+ /* return matcher indices */ &kMatcherIndices[112],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorM,
},
{
/* [102] */
/* num parameters */ 1,
/* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[4],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[946],
- /* return matcher indices */ &kMatcherIndices[123],
+ /* parameters */ &kParameters[949],
+ /* return matcher indices */ &kMatcherIndices[104],
/* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Conv,
},
{
/* [103] */
/* num parameters */ 1,
/* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[6],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[947],
- /* return matcher indices */ &kMatcherIndices[125],
+ /* parameters */ &kParameters[950],
+ /* return matcher indices */ &kMatcherIndices[108],
/* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Conv,
},
{
/* [104] */
/* num parameters */ 1,
/* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[0],
+ /* template types */ &kTemplateTypes[4],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[948],
- /* return matcher indices */ &kMatcherIndices[127],
+ /* parameters */ &kParameters[951],
+ /* return matcher indices */ &kMatcherIndices[110],
/* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Conv,
},
{
/* [105] */
/* num parameters */ 1,
- /* num template types */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[6],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[856],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[952],
+ /* return matcher indices */ &kMatcherIndices[114],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [106] */
/* num parameters */ 1,
- /* num template types */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[8],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[855],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[953],
+ /* return matcher indices */ &kMatcherIndices[118],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [107] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[854],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[880],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -8972,10 +9464,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[853],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[879],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -8984,10 +9476,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[852],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[878],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -8996,34 +9488,34 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[851],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[877],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [111] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[850],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[876],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [112] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[849],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[875],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -9032,10 +9524,10 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[848],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[874],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -9044,130 +9536,130 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[846],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[873],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [115] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* num parameters */ 1,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[540],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[872],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [116] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* num parameters */ 1,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[543],
- /* return matcher indices */ &kMatcherIndices[49],
+ /* parameters */ &kParameters[871],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [117] */
- /* num parameters */ 4,
+ /* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[323],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[727],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [118] */
- /* num parameters */ 3,
+ /* num parameters */ 2,
/* num template types */ 1,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[573],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[725],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [119] */
- /* num parameters */ 3,
+ /* num parameters */ 2,
/* num template types */ 1,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[576],
- /* return matcher indices */ &kMatcherIndices[49],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[723],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [120] */
- /* num parameters */ 3,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[579],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[721],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [121] */
- /* num parameters */ 4,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[407],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 2,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[719],
+ /* return matcher indices */ &kMatcherIndices[10],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [122] */
- /* num parameters */ 3,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[588],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 2,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[717],
+ /* return matcher indices */ &kMatcherIndices[10],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [123] */
/* num parameters */ 2,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[727],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template types */ 1,
+ /* num template numbers */ 2,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[1],
+ /* parameters */ &kParameters[715],
+ /* return matcher indices */ &kMatcherIndices[69],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [124] */
/* num parameters */ 2,
/* num template types */ 1,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[685],
- /* return matcher indices */ &kMatcherIndices[1],
+ /* num template numbers */ 2,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[1],
+ /* parameters */ &kParameters[713],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -9175,251 +9667,251 @@ constexpr OverloadInfo kOverloads[] = {
/* [125] */
/* num parameters */ 2,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[681],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* num template numbers */ 3,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[0],
+ /* parameters */ &kParameters[711],
+ /* return matcher indices */ &kMatcherIndices[22],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [126] */
- /* num parameters */ 2,
+ /* num parameters */ 3,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[679],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[17],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[522],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [127] */
- /* num parameters */ 2,
+ /* num parameters */ 3,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[673],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[17],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[528],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [128] */
- /* num parameters */ 2,
- /* num template types */ 0,
- /* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[671],
- /* return matcher indices */ &kMatcherIndices[11],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num parameters */ 4,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[17],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[363],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [129] */
- /* num parameters */ 2,
- /* num template types */ 0,
- /* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[669],
- /* return matcher indices */ &kMatcherIndices[11],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num parameters */ 3,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[17],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[531],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [130] */
- /* num parameters */ 2,
- /* num template types */ 0,
- /* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[1],
- /* parameters */ &kParameters[667],
- /* return matcher indices */ &kMatcherIndices[76],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num parameters */ 3,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[17],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[549],
+ /* return matcher indices */ &kMatcherIndices[120],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [131] */
- /* num parameters */ 2,
+ /* num parameters */ 3,
/* num template types */ 0,
- /* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[1],
- /* parameters */ &kParameters[665],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[552],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [132] */
- /* num parameters */ 2,
+ /* num parameters */ 4,
/* num template types */ 0,
- /* num template numbers */ 3,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[0],
- /* parameters */ &kParameters[663],
- /* return matcher indices */ &kMatcherIndices[27],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[383],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [133] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[331],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[555],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [134] */
- /* num parameters */ 5,
+ /* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[180],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[783],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [135] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[290],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[116],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
},
{
/* [136] */
- /* num parameters */ 6,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[132],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[935],
+ /* return matcher indices */ &kMatcherIndices[116],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
},
{
/* [137] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[315],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[936],
+ /* return matcher indices */ &kMatcherIndices[116],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecSplat,
},
{
/* [138] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[18],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[250],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[611],
+ /* return matcher indices */ &kMatcherIndices[116],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::VecCtorS,
},
{
/* [139] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[307],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[938],
+ /* return matcher indices */ &kMatcherIndices[134],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [140] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[270],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[939],
+ /* return matcher indices */ &kMatcherIndices[132],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [141] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[4],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[240],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[940],
+ /* return matcher indices */ &kMatcherIndices[130],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [142] */
- /* num parameters */ 6,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[6],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[84],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[941],
+ /* return matcher indices */ &kMatcherIndices[128],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [143] */
- /* num parameters */ 6,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 2,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[8],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[102],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[942],
+ /* return matcher indices */ &kMatcherIndices[122],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [144] */
- /* num parameters */ 7,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[65],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[180],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [145] */
- /* num parameters */ 5,
+ /* num parameters */ 6,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[220],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[108],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
@@ -9428,155 +9920,155 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 6,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[114],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[102],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [147] */
- /* num parameters */ 5,
+ /* num parameters */ 7,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[210],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[65],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [148] */
- /* num parameters */ 6,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[120],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[235],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [149] */
- /* num parameters */ 0,
- /* num template types */ 1,
+ /* num parameters */ 6,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[105],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[78],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [150] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[932],
- /* return matcher indices */ &kMatcherIndices[105],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[245],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [151] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 6,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[933],
- /* return matcher indices */ &kMatcherIndices[105],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[120],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [152] */
- /* num parameters */ 2,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[12],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[759],
- /* return matcher indices */ &kMatcherIndices[105],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[343],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [153] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[2],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[935],
- /* return matcher indices */ &kMatcherIndices[103],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[225],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [154] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[4],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[936],
- /* return matcher indices */ &kMatcherIndices[109],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[150],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [155] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 6,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[6],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[937],
- /* return matcher indices */ &kMatcherIndices[111],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[144],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [156] */
- /* num parameters */ 1,
- /* num template types */ 2,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[0],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[938],
- /* return matcher indices */ &kMatcherIndices[113],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[439],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [157] */
- /* num parameters */ 4,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[391],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[200],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [158] */
- /* num parameters */ 5,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[205],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[435],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
@@ -9584,107 +10076,107 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[185],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[280],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [160] */
- /* num parameters */ 6,
- /* num template types */ 0,
+ /* num parameters */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[138],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[224],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
},
{
/* [161] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[375],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[922],
+ /* return matcher indices */ &kMatcherIndices[224],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
},
{
/* [162] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 16,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[160],
- /* return matcher indices */ &kMatcherIndices[45],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[0],
+ /* return matcher indices */ &kMatcherIndices[224],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [163] */
/* num parameters */ 4,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[303],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[443],
+ /* return matcher indices */ &kMatcherIndices[224],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [164] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[265],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[908],
+ /* return matcher indices */ &kMatcherIndices[228],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [165] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[260],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[906],
+ /* return matcher indices */ &kMatcherIndices[226],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [166] */
- /* num parameters */ 6,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[144],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[419],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [167] */
- /* num parameters */ 4,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[311],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[240],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
@@ -9692,34 +10184,34 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[245],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[220],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [169] */
- /* num parameters */ 4,
+ /* num parameters */ 6,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[299],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[138],
+ /* return matcher indices */ &kMatcherIndices[4],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [170] */
- /* num parameters */ 5,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[280],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[403],
+ /* return matcher indices */ &kMatcherIndices[4],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
@@ -9728,3287 +10220,3515 @@ constexpr OverloadInfo kOverloads[] = {
/* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[285],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[290],
+ /* return matcher indices */ &kMatcherIndices[4],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
/* [172] */
- /* num parameters */ 6,
- /* num template types */ 0,
+ /* num parameters */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[108],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[176],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
},
{
/* [173] */
- /* num parameters */ 4,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[295],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[982],
+ /* return matcher indices */ &kMatcherIndices[176],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
},
{
/* [174] */
- /* num parameters */ 5,
- /* num template types */ 0,
+ /* num parameters */ 8,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[275],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[57],
+ /* return matcher indices */ &kMatcherIndices[176],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [175] */
- /* num parameters */ 0,
- /* num template types */ 0,
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[149],
+ /* parameters */ &kParameters[593],
+ /* return matcher indices */ &kMatcherIndices[176],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [176] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[969],
- /* return matcher indices */ &kMatcherIndices[149],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[985],
+ /* return matcher indices */ &kMatcherIndices[180],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [177] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[970],
- /* return matcher indices */ &kMatcherIndices[151],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[986],
+ /* return matcher indices */ &kMatcherIndices[178],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [178] */
- /* num parameters */ 6,
+ /* num parameters */ 0,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[90],
- /* return matcher indices */ &kMatcherIndices[151],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[162],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
/* [179] */
- /* num parameters */ 2,
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[781],
- /* return matcher indices */ &kMatcherIndices[151],
+ /* parameters */ &kParameters[970],
+ /* return matcher indices */ &kMatcherIndices[162],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
/* [180] */
- /* num parameters */ 0,
- /* num template types */ 0,
+ /* num parameters */ 4,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[165],
+ /* parameters */ &kParameters[411],
+ /* return matcher indices */ &kMatcherIndices[162],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [181] */
- /* num parameters */ 1,
+ /* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[988],
- /* return matcher indices */ &kMatcherIndices[165],
+ /* parameters */ &kParameters[597],
+ /* return matcher indices */ &kMatcherIndices[162],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [182] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[983],
- /* return matcher indices */ &kMatcherIndices[167],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[973],
+ /* return matcher indices */ &kMatcherIndices[166],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [183] */
- /* num parameters */ 12,
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[16],
- /* return matcher indices */ &kMatcherIndices[167],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[974],
+ /* return matcher indices */ &kMatcherIndices[164],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [184] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[468],
- /* return matcher indices */ &kMatcherIndices[167],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[395],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [185] */
- /* num parameters */ 0,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[169],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[195],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [186] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[968],
- /* return matcher indices */ &kMatcherIndices[169],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[155],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [187] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 6,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[957],
- /* return matcher indices */ &kMatcherIndices[171],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[72],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [188] */
- /* num parameters */ 8,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[57],
- /* return matcher indices */ &kMatcherIndices[171],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[371],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [189] */
- /* num parameters */ 4,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[431],
- /* return matcher indices */ &kMatcherIndices[171],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[175],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [190] */
- /* num parameters */ 0,
+ /* num parameters */ 4,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[4],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[367],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [191] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[964],
- /* return matcher indices */ &kMatcherIndices[4],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[185],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [192] */
- /* num parameters */ 1,
- /* num template types */ 1,
+ /* num parameters */ 5,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[965],
- /* return matcher indices */ &kMatcherIndices[147],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[190],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [193] */
- /* num parameters */ 4,
- /* num template types */ 1,
+ /* num parameters */ 6,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[427],
- /* return matcher indices */ &kMatcherIndices[147],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[126],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [194] */
- /* num parameters */ 2,
- /* num template types */ 1,
+ /* num parameters */ 4,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[779],
- /* return matcher indices */ &kMatcherIndices[147],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[355],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [195] */
- /* num parameters */ 0,
+ /* num parameters */ 5,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[157],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[210],
+ /* return matcher indices */ &kMatcherIndices[126],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
/* [196] */
- /* num parameters */ 1,
+ /* num parameters */ 0,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[979],
- /* return matcher indices */ &kMatcherIndices[157],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[168],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
/* [197] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[980],
- /* return matcher indices */ &kMatcherIndices[159],
+ /* parameters */ &kParameters[976],
+ /* return matcher indices */ &kMatcherIndices[168],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
/* [198] */
/* num parameters */ 6,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[78],
- /* return matcher indices */ &kMatcherIndices[159],
+ /* parameters */ &kParameters[84],
+ /* return matcher indices */ &kMatcherIndices[168],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [199] */
- /* num parameters */ 3,
+ /* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[474],
- /* return matcher indices */ &kMatcherIndices[159],
+ /* parameters */ &kParameters[595],
+ /* return matcher indices */ &kMatcherIndices[168],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [200] */
- /* num parameters */ 0,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[153],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[979],
+ /* return matcher indices */ &kMatcherIndices[174],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [201] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[974],
- /* return matcher indices */ &kMatcherIndices[153],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[980],
+ /* return matcher indices */ &kMatcherIndices[170],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [202] */
- /* num parameters */ 1,
+ /* num parameters */ 0,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[975],
- /* return matcher indices */ &kMatcherIndices[155],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[198],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
/* [203] */
- /* num parameters */ 8,
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[49],
- /* return matcher indices */ &kMatcherIndices[155],
+ /* parameters */ &kParameters[987],
+ /* return matcher indices */ &kMatcherIndices[198],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
/* [204] */
- /* num parameters */ 2,
+ /* num parameters */ 8,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[783],
- /* return matcher indices */ &kMatcherIndices[155],
+ /* parameters */ &kParameters[49],
+ /* return matcher indices */ &kMatcherIndices[198],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [205] */
- /* num parameters */ 1,
+ /* num parameters */ 4,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[867],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[415],
+ /* return matcher indices */ &kMatcherIndices[198],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [206] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[866],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[969],
+ /* return matcher indices */ &kMatcherIndices[202],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [207] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[865],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[954],
+ /* return matcher indices */ &kMatcherIndices[200],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [208] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* num parameters */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[864],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[204],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
},
{
/* [209] */
/* num parameters */ 1,
- /* num template types */ 0,
- /* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[3],
- /* parameters */ &kParameters[857],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[943],
+ /* return matcher indices */ &kMatcherIndices[204],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
},
{
/* [210] */
- /* num parameters */ 0,
- /* num template types */ 0,
+ /* num parameters */ 12,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[175],
+ /* parameters */ &kParameters[16],
+ /* return matcher indices */ &kMatcherIndices[204],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [211] */
- /* num parameters */ 1,
+ /* num parameters */ 4,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[931],
- /* return matcher indices */ &kMatcherIndices[175],
+ /* parameters */ &kParameters[391],
+ /* return matcher indices */ &kMatcherIndices[204],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [212] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[928],
- /* return matcher indices */ &kMatcherIndices[177],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* return matcher indices */ &kMatcherIndices[218],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [213] */
- /* num parameters */ 12,
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[28],
- /* return matcher indices */ &kMatcherIndices[177],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[925],
+ /* return matcher indices */ &kMatcherIndices[216],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [214] */
- /* num parameters */ 4,
+ /* num parameters */ 0,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[435],
- /* return matcher indices */ &kMatcherIndices[177],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[102],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
/* [215] */
- /* num parameters */ 2,
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[695],
- /* return matcher indices */ &kMatcherIndices[1],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1000],
+ /* return matcher indices */ &kMatcherIndices[102],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
},
{
/* [216] */
- /* num parameters */ 2,
+ /* num parameters */ 12,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[693],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[12],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[28],
+ /* return matcher indices */ &kMatcherIndices[102],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [217] */
- /* num parameters */ 2,
+ /* num parameters */ 3,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[691],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[12],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[468],
+ /* return matcher indices */ &kMatcherIndices[102],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [218] */
- /* num parameters */ 2,
+ /* num parameters */ 1,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[689],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[2],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[999],
+ /* return matcher indices */ &kMatcherIndices[196],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [219] */
- /* num parameters */ 2,
- /* num template types */ 0,
- /* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[687],
- /* return matcher indices */ &kMatcherIndices[11],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num parameters */ 1,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[0],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[993],
+ /* return matcher indices */ &kMatcherIndices[194],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [220] */
- /* num parameters */ 2,
+ /* num parameters */ 0,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[705],
- /* return matcher indices */ &kMatcherIndices[1],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[188],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
},
{
/* [221] */
- /* num parameters */ 2,
+ /* num parameters */ 1,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[703],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[994],
+ /* return matcher indices */ &kMatcherIndices[188],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
},
{
/* [222] */
- /* num parameters */ 2,
+ /* num parameters */ 9,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[701],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[12],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[40],
+ /* return matcher indices */ &kMatcherIndices[188],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [223] */
- /* num parameters */ 2,
+ /* num parameters */ 3,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[699],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[12],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[582],
+ /* return matcher indices */ &kMatcherIndices[188],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [224] */
- /* num parameters */ 2,
- /* num template types */ 0,
- /* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[697],
- /* return matcher indices */ &kMatcherIndices[11],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* num parameters */ 1,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[2],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[997],
+ /* return matcher indices */ &kMatcherIndices[192],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [225] */
- /* num parameters */ 0,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[185],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[998],
+ /* return matcher indices */ &kMatcherIndices[190],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [226] */
- /* num parameters */ 1,
+ /* num parameters */ 0,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[919],
- /* return matcher indices */ &kMatcherIndices[185],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[182],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
/* [227] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[912],
- /* return matcher indices */ &kMatcherIndices[137],
+ /* parameters */ &kParameters[988],
+ /* return matcher indices */ &kMatcherIndices[182],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
/* [228] */
- /* num parameters */ 16,
+ /* num parameters */ 6,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[0],
- /* return matcher indices */ &kMatcherIndices[137],
+ /* parameters */ &kParameters[114],
+ /* return matcher indices */ &kMatcherIndices[182],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorS,
},
{
/* [229] */
- /* num parameters */ 4,
+ /* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[443],
- /* return matcher indices */ &kMatcherIndices[137],
+ /* parameters */ &kParameters[579],
+ /* return matcher indices */ &kMatcherIndices[182],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::MatCtorV,
},
{
/* [230] */
- /* num parameters */ 0,
- /* num template types */ 0,
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[2],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[161],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[991],
+ /* return matcher indices */ &kMatcherIndices[186],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [231] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[9],
+ /* template types */ &kTemplateTypes[0],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[984],
- /* return matcher indices */ &kMatcherIndices[161],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[992],
+ /* return matcher indices */ &kMatcherIndices[184],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
},
{
/* [232] */
- /* num parameters */ 1,
+ /* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[13],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[985],
- /* return matcher indices */ &kMatcherIndices[163],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[737],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpMinus,
},
{
/* [233] */
- /* num parameters */ 9,
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[13],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[735],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpMinus,
+ },
+ {
+ /* [234] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[13],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[733],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpMinus,
+ },
+ {
+ /* [235] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[13],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[731],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpMinus,
+ },
+ {
+ /* [236] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 2,
+ /* template types */ &kTemplateTypes[12],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[729],
+ /* return matcher indices */ &kMatcherIndices[10],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpMinus,
+ },
+ {
+ /* [237] */
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[40],
- /* return matcher indices */ &kMatcherIndices[163],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[885],
+ /* return matcher indices */ &kMatcherIndices[34],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [234] */
- /* num parameters */ 3,
+ /* [238] */
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[10],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[471],
- /* return matcher indices */ &kMatcherIndices[163],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[884],
+ /* return matcher indices */ &kMatcherIndices[34],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [235] */
- /* num parameters */ 2,
+ /* [239] */
+ /* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[633],
- /* return matcher indices */ &kMatcherIndices[21],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[883],
+ /* return matcher indices */ &kMatcherIndices[34],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [236] */
- /* num parameters */ 2,
+ /* [240] */
+ /* num parameters */ 1,
/* num template types */ 0,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[629],
- /* return matcher indices */ &kMatcherIndices[40],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[882],
+ /* return matcher indices */ &kMatcherIndices[34],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [237] */
+ /* [241] */
+ /* num parameters */ 1,
+ /* num template types */ 0,
+ /* num template numbers */ 2,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[3],
+ /* parameters */ &kParameters[881],
+ /* return matcher indices */ &kMatcherIndices[34],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [242] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[13],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[625],
+ /* parameters */ &kParameters[749],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::OpPlus,
},
{
- /* [238] */
+ /* [243] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[13],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[621],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[747],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::OpPlus,
},
{
- /* [239] */
+ /* [244] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[13],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[745],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpPlus,
+ },
+ {
+ /* [245] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[13],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[743],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpPlus,
+ },
+ {
+ /* [246] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 2,
+ /* template types */ &kTemplateTypes[12],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[741],
+ /* return matcher indices */ &kMatcherIndices[10],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpPlus,
+ },
+ {
+ /* [247] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[653],
+ /* parameters */ &kParameters[701],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [240] */
+ /* [248] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[651],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[699],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [241] */
+ /* [249] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[647],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[695],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [242] */
+ /* [250] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[643],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[693],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [243] */
+ /* [251] */
/* num parameters */ 2,
- /* num template types */ 1,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[661],
- /* return matcher indices */ &kMatcherIndices[1],
+ /* parameters */ &kParameters[687],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [244] */
+ /* [252] */
/* num parameters */ 2,
- /* num template types */ 1,
+ /* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[659],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[685],
+ /* return matcher indices */ &kMatcherIndices[39],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [245] */
+ /* [253] */
/* num parameters */ 2,
/* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[657],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[14],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[683],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [246] */
+ /* [254] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[655],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[681],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [247] */
+ /* [255] */
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[617],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[679],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [248] */
+ /* [256] */
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[613],
- /* return matcher indices */ &kMatcherIndices[40],
+ /* parameters */ &kParameters[677],
+ /* return matcher indices */ &kMatcherIndices[39],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [249] */
+ /* [257] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[609],
+ /* parameters */ &kParameters[675],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [250] */
+ /* [258] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[607],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[673],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [251] */
+ /* [259] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[709],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [260] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[707],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [261] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[705],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [262] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[781],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [263] */
/* num parameters */ 0,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
- /* [252] */
+ /* [264] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[920],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
- /* [253] */
+ /* [265] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[18],
+ /* template types */ &kTemplateTypes[24],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[921],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Conv,
},
{
- /* [254] */
+ /* [266] */
/* num parameters */ 0,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
- /* [255] */
+ /* [267] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[932],
+ /* return matcher indices */ &kMatcherIndices[16],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
+ },
+ {
+ /* [268] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
/* template types */ &kTemplateTypes[20],
/* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[933],
+ /* return matcher indices */ &kMatcherIndices[16],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
+ },
+ {
+ /* [269] */
+ /* num parameters */ 0,
+ /* num template types */ 0,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[109],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
+ },
+ {
+ /* [270] */
+ /* num parameters */ 1,
+ /* num template types */ 0,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[929],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* return matcher indices */ &kMatcherIndices[109],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
- /* [256] */
+ /* [271] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[15],
+ /* template types */ &kTemplateTypes[21],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[930],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* return matcher indices */ &kMatcherIndices[109],
/* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Conv,
},
{
- /* [257] */
+ /* [272] */
+ /* num parameters */ 0,
+ /* num template types */ 0,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Zero,
+ },
+ {
+ /* [273] */
+ /* num parameters */ 1,
+ /* num template types */ 0,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[926],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Identity,
+ },
+ {
+ /* [274] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[22],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[927],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::Conv,
+ },
+ {
+ /* [275] */
/* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[522],
+ /* parameters */ &kParameters[540],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [258] */
+ /* [276] */
/* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[525],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[543],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [259] */
+ /* [277] */
/* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[528],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[546],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [260] */
+ /* [278] */
/* num parameters */ 0,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Zero,
},
{
- /* [261] */
+ /* [279] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[923],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Identity,
},
{
- /* [262] */
+ /* [280] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[17],
+ /* template types */ &kTemplateTypes[23],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[924],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::Conv,
},
{
- /* [263] */
- /* num parameters */ 0,
- /* num template types */ 0,
+ /* [281] */
+ /* num parameters */ 3,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[477],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [264] */
- /* num parameters */ 1,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[926],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* [282] */
+ /* num parameters */ 3,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[480],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [265] */
- /* num parameters */ 1,
+ /* [283] */
+ /* num parameters */ 3,
/* num template types */ 1,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[16],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[927],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[483],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [266] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* [284] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[10],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[459],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[860],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpComplement,
},
{
- /* [267] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* [285] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[10],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[462],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[861],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::OpComplement,
+ },
+ {
+ /* [286] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[798],
+ /* return matcher indices */ &kMatcherIndices[172],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [268] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* [287] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[465],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[810],
+ /* return matcher indices */ &kMatcherIndices[78],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [269] */
+ /* [288] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[858],
- /* return matcher indices */ &kMatcherIndices[21],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[822],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [270] */
+ /* [289] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[859],
- /* return matcher indices */ &kMatcherIndices[40],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[823],
+ /* return matcher indices */ &kMatcherIndices[60],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [271] */
+ /* [290] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[871],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[800],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [272] */
+ /* [291] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[872],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[799],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [273] */
+ /* [292] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[869],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[826],
+ /* return matcher indices */ &kMatcherIndices[4],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [274] */
+ /* [293] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[870],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[830],
+ /* return matcher indices */ &kMatcherIndices[60],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [275] */
+ /* [294] */
/* num parameters */ 4,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[439],
+ /* parameters */ &kParameters[423],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [276] */
+ /* [295] */
/* num parameters */ 4,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[403],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[427],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [277] */
+ /* [296] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[875],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[846],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [278] */
+ /* [297] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[876],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[848],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [279] */
+ /* [298] */
/* num parameters */ 2,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[677],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[779],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [280] */
+ /* [299] */
/* num parameters */ 2,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[801],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[777],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [281] */
+ /* [300] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[878],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[849],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [282] */
+ /* [301] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[879],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[850],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [283] */
+ /* [302] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[880],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[851],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [284] */
+ /* [303] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[881],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[852],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [285] */
+ /* [304] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[882],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[853],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [286] */
+ /* [305] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[885],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[854],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [287] */
+ /* [306] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[737],
+ /* parameters */ &kParameters[763],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [288] */
+ /* [307] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[789],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[761],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [289] */
+ /* [308] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[787],
+ /* parameters */ &kParameters[759],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [290] */
+ /* [309] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[785],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[757],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [291] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [310] */
+ /* num parameters */ 3,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[843],
- /* return matcher indices */ &kMatcherIndices[202],
+ /* parameters */ &kParameters[450],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [292] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [311] */
+ /* num parameters */ 3,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[868],
- /* return matcher indices */ &kMatcherIndices[135],
+ /* parameters */ &kParameters[447],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [293] */
+ /* [312] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[973],
- /* return matcher indices */ &kMatcherIndices[201],
+ /* parameters */ &kParameters[855],
+ /* return matcher indices */ &kMatcherIndices[136],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [294] */
+ /* [313] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[905],
- /* return matcher indices */ &kMatcherIndices[117],
+ /* parameters */ &kParameters[856],
+ /* return matcher indices */ &kMatcherIndices[96],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [295] */
+ /* [314] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[841],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[802],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [296] */
+ /* [315] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[842],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[801],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [297] */
- /* num parameters */ 3,
+ /* [316] */
+ /* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[561],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[824],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [298] */
- /* num parameters */ 3,
+ /* [317] */
+ /* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[567],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[825],
+ /* return matcher indices */ &kMatcherIndices[60],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [299] */
+ /* [318] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[873],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[806],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [300] */
+ /* [319] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[874],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[805],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [301] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [320] */
+ /* num parameters */ 3,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[838],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[459],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [302] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [321] */
+ /* num parameters */ 3,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[839],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[456],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [303] */
+ /* [322] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[836],
+ /* parameters */ &kParameters[808],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [304] */
+ /* [323] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[837],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[807],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [305] */
+ /* [324] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[834],
+ /* parameters */ &kParameters[886],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [306] */
+ /* [325] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[835],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[809],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [307] */
+ /* [326] */
/* num parameters */ 2,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[773],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[739],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [308] */
+ /* [327] */
/* num parameters */ 2,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[771],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[703],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [309] */
+ /* [328] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[956],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[887],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [310] */
+ /* [329] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[955],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[888],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [311] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* [330] */
+ /* num parameters */ 1,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[495],
- /* return matcher indices */ &kMatcherIndices[1],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[811],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [312] */
- /* num parameters */ 3,
- /* num template types */ 1,
+ /* [331] */
+ /* num parameters */ 1,
+ /* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[498],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[1001],
+ /* return matcher indices */ &kMatcherIndices[60],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [313] */
+ /* [332] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[831],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[813],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [314] */
+ /* [333] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[833],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[812],
+ /* return matcher indices */ &kMatcherIndices[60],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [315] */
+ /* [334] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[954],
+ /* parameters */ &kParameters[889],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [316] */
+ /* [335] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[953],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[890],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [317] */
+ /* [336] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[944],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[891],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [318] */
+ /* [337] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[943],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[892],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [319] */
+ /* [338] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[829],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[815],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [320] */
+ /* [339] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[830],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[814],
+ /* return matcher indices */ &kMatcherIndices[60],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [321] */
+ /* [340] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[942],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[893],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [322] */
+ /* [341] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[934],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[894],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [323] */
+ /* [342] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[918],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[895],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [324] */
+ /* [343] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[917],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[896],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [325] */
+ /* [344] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[916],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[897],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [326] */
+ /* [345] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[915],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[898],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [327] */
+ /* [346] */
/* num parameters */ 3,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[549],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[567],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [328] */
+ /* [347] */
/* num parameters */ 3,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[552],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[570],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [329] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* [348] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[555],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kIsDeprecated),
+ /* parameters */ &kParameters[899],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [330] */
- /* num parameters */ 3,
- /* num template types */ 0,
+ /* [349] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[558],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kIsDeprecated),
+ /* parameters */ &kParameters[900],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [331] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [350] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[914],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[671],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [332] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [351] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[913],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[669],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [333] */
- /* num parameters */ 2,
- /* num template types */ 0,
+ /* [352] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[745],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[804],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [334] */
- /* num parameters */ 2,
- /* num template types */ 0,
+ /* [353] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[743],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[803],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [335] */
+ /* [354] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[826],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[919],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [336] */
+ /* [355] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[827],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[797],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [337] */
+ /* [356] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[911],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[984],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [338] */
+ /* [357] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[877],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[978],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [339] */
+ /* [358] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[910],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[817],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [340] */
+ /* [359] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[909],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[816],
+ /* return matcher indices */ &kMatcherIndices[60],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [341] */
- /* num parameters */ 2,
+ /* [360] */
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[755],
+ /* parameters */ &kParameters[964],
/* return matcher indices */ &kMatcherIndices[1],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [342] */
- /* num parameters */ 2,
+ /* [361] */
+ /* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[757],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[963],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [343] */
+ /* [362] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[907],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[819],
+ /* return matcher indices */ &kMatcherIndices[4],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [344] */
+ /* [363] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[906],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[818],
+ /* return matcher indices */ &kMatcherIndices[60],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [345] */
+ /* [364] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[751],
+ /* parameters */ &kParameters[619],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [346] */
+ /* [365] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[753],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[615],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [347] */
+ /* [366] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[824],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[821],
+ /* return matcher indices */ &kMatcherIndices[4],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [348] */
+ /* [367] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[825],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[820],
+ /* return matcher indices */ &kMatcherIndices[60],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
/* const eval */ nullptr,
},
{
- /* [349] */
+ /* [368] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[739],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[635],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [350] */
+ /* [369] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[741],
- /* return matcher indices */ &kMatcherIndices[40],
+ /* parameters */ &kParameters[631],
+ /* return matcher indices */ &kMatcherIndices[39],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [351] */
+ /* [370] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[733],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[641],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [352] */
+ /* [371] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[735],
- /* return matcher indices */ &kMatcherIndices[40],
+ /* parameters */ &kParameters[639],
+ /* return matcher indices */ &kMatcherIndices[39],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [353] */
+ /* [372] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[707],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[649],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [354] */
+ /* [373] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[729],
- /* return matcher indices */ &kMatcherIndices[40],
+ /* parameters */ &kParameters[645],
+ /* return matcher indices */ &kMatcherIndices[39],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [355] */
+ /* [374] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[675],
- /* return matcher indices */ &kMatcherIndices[21],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[787],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [356] */
+ /* [375] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[13],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[683],
- /* return matcher indices */ &kMatcherIndices[40],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[789],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [357] */
+ /* [376] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[812],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[829],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [358] */
+ /* [377] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[823],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[828],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [359] */
+ /* [378] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[807],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[1002],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [360] */
+ /* [379] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[808],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[996],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [361] */
+ /* [380] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[805],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[832],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [362] */
+ /* [381] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[806],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[831],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [363] */
+ /* [382] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[803],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[834],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [364] */
+ /* [383] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[804],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+ /* parameters */ &kParameters[833],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [365] */
- /* num parameters */ 2,
- /* num template types */ 0,
+ /* [384] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[17],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[793],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[870],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [366] */
- /* num parameters */ 2,
+ /* [385] */
+ /* num parameters */ 1,
/* num template types */ 0,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[795],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[869],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [367] */
+ /* [386] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[845],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[837],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [368] */
+ /* [387] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[14],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[836],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [388] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[844],
- /* return matcher indices */ &kMatcherIndices[44],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[657],
+ /* return matcher indices */ &kMatcherIndices[16],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [369] */
+ /* [389] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[15],
+ /* template numbers */ &kTemplateNumbers[6],
+ /* parameters */ &kParameters[653],
+ /* return matcher indices */ &kMatcherIndices[39],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [390] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[811],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[839],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [370] */
+ /* [391] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[810],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[838],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [371] */
+ /* [392] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[814],
+ /* parameters */ &kParameters[841],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [372] */
+ /* [393] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[813],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[840],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [373] */
- /* num parameters */ 2,
+ /* [394] */
+ /* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[13],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[601],
- /* return matcher indices */ &kMatcherIndices[21],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[537],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::clamp,
},
{
- /* [374] */
- /* num parameters */ 2,
+ /* [395] */
+ /* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 1,
/* template types */ &kTemplateTypes[13],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[599],
- /* return matcher indices */ &kMatcherIndices[40],
- /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* parameters */ &kParameters[534],
+ /* return matcher indices */ &kMatcherIndices[30],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ &ConstEval::clamp,
},
{
- /* [375] */
+ /* [396] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[816],
+ /* parameters */ &kParameters[843],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [376] */
+ /* [397] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[815],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[842],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [377] */
+ /* [398] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[818],
+ /* parameters */ &kParameters[845],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [378] */
+ /* [399] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
/* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[817],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[844],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [379] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [400] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[820],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[613],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::atan2,
},
{
- /* [380] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [401] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[12],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[819],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[751],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::atan2,
},
{
- /* [381] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [402] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[822],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[659],
+ /* return matcher indices */ &kMatcherIndices[16],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [382] */
- /* num parameters */ 1,
- /* num template types */ 0,
+ /* [403] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[821],
- /* return matcher indices */ &kMatcherIndices[31],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[599],
+ /* return matcher indices */ &kMatcherIndices[39],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [383] */
- /* num parameters */ 3,
+ /* [404] */
+ /* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[453],
- /* return matcher indices */ &kMatcherIndices[1],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[663],
+ /* return matcher indices */ &kMatcherIndices[16],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [384] */
- /* num parameters */ 3,
+ /* [405] */
+ /* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[16],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[450],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[661],
+ /* return matcher indices */ &kMatcherIndices[39],
+ /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [385] */
+ /* [406] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[832],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[934],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [386] */
+ /* [407] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[828],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[931],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [387] */
- /* num parameters */ 2,
- /* num template types */ 0,
+ /* [408] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[731],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[957],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [388] */
- /* num parameters */ 2,
- /* num template types */ 0,
+ /* [409] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[761],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[946],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [389] */
+ /* [410] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[639],
+ /* parameters */ &kParameters[691],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [390] */
+ /* [411] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[635],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[689],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [391] */
+ /* [412] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[966],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[959],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [392] */
+ /* [413] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[952],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[958],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [393] */
+ /* [414] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[976],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[975],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [394] */
+ /* [415] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
/* parameters */ &kParameters[971],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [395] */
+ /* [416] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[978],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[981],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [396] */
+ /* [417] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[986],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[977],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [397] */
+ /* [418] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[939],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[989],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [398] */
+ /* [419] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[949],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[983],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [399] */
+ /* [420] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[922],
- /* return matcher indices */ &kMatcherIndices[5],
+ /* parameters */ &kParameters[995],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [400] */
+ /* [421] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[925],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[990],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [401] */
+ /* [422] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[19],
+ /* template types */ &kTemplateTypes[25],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[862],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::OpUnaryMinus,
},
{
- /* [402] */
+ /* [423] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[19],
+ /* template types */ &kTemplateTypes[25],
/* template numbers */ &kTemplateNumbers[6],
/* parameters */ &kParameters[863],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::OpUnaryMinus,
},
{
- /* [403] */
+ /* [424] */
/* num parameters */ 1,
- /* num template types */ 1,
+ /* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[860],
- /* return matcher indices */ &kMatcherIndices[1],
+ /* parameters */ &kParameters[858],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [404] */
+ /* [425] */
/* num parameters */ 1,
- /* num template types */ 1,
+ /* num template types */ 0,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[861],
- /* return matcher indices */ &kMatcherIndices[37],
+ /* parameters */ &kParameters[859],
+ /* return matcher indices */ &kMatcherIndices[39],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [405] */
- /* num parameters */ 1,
- /* num template types */ 1,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[963],
- /* return matcher indices */ &kMatcherIndices[1],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
- },
- {
- /* [406] */
- /* num parameters */ 1,
- /* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
- /* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[900],
- /* return matcher indices */ &kMatcherIndices[37],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
- },
- {
- /* [407] */
+ /* [426] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[747],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[627],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [408] */
+ /* [427] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[749],
- /* return matcher indices */ &kMatcherIndices[40],
+ /* parameters */ &kParameters[623],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [409] */
- /* num parameters */ 1,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[904],
- /* return matcher indices */ &kMatcherIndices[103],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
- },
- {
- /* [410] */
- /* num parameters */ 2,
+ /* [428] */
+ /* num parameters */ 3,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[711],
- /* return matcher indices */ &kMatcherIndices[1],
+ /* parameters */ &kParameters[561],
+ /* return matcher indices */ &kMatcherIndices[206],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [411] */
+ /* [429] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[713],
+ /* parameters */ &kParameters[753],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [412] */
+ /* [430] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[715],
+ /* parameters */ &kParameters[755],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [413] */
+ /* [431] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[717],
+ /* parameters */ &kParameters[765],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [414] */
+ /* [432] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[719],
+ /* parameters */ &kParameters[767],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [415] */
+ /* [433] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[721],
+ /* parameters */ &kParameters[769],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [416] */
+ /* [434] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[723],
+ /* parameters */ &kParameters[771],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [417] */
+ /* [435] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[725],
- /* return matcher indices */ nullptr,
+ /* parameters */ &kParameters[773],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [418] */
- /* num parameters */ 1,
+ /* [436] */
+ /* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
+ /* template types */ &kTemplateTypes[14],
/* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[847],
+ /* parameters */ &kParameters[775],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [419] */
+ /* [437] */
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[605],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[667],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [420] */
+ /* [438] */
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[603],
- /* return matcher indices */ &kMatcherIndices[21],
+ /* parameters */ &kParameters[665],
+ /* return matcher indices */ &kMatcherIndices[16],
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [421] */
+ /* [439] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[14],
+ /* template numbers */ &kTemplateNumbers[9],
+ /* parameters */ &kParameters[591],
+ /* return matcher indices */ nullptr,
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [440] */
/* num parameters */ 1,
+ /* num template types */ 1,
+ /* num template numbers */ 1,
+ /* template types */ &kTemplateTypes[14],
+ /* template numbers */ &kTemplateNumbers[9],
+ /* parameters */ &kParameters[847],
+ /* return matcher indices */ &kMatcherIndices[1],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [441] */
+ /* num parameters */ 0,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[967],
- /* return matcher indices */ &kMatcherIndices[62],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* parameters */ &kParameters[1004],
+ /* return matcher indices */ nullptr,
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [422] */
+ /* [442] */
/* num parameters */ 0,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
+ /* parameters */ &kParameters[1004],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [423] */
+ /* [443] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[901],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[937],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [424] */
+ /* [444] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[902],
- /* return matcher indices */ &kMatcherIndices[45],
+ /* parameters */ &kParameters[947],
+ /* return matcher indices */ &kMatcherIndices[126],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [425] */
+ /* [445] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[903],
- /* return matcher indices */ &kMatcherIndices[103],
+ /* parameters */ &kParameters[948],
+ /* return matcher indices */ &kMatcherIndices[134],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [426] */
- /* num parameters */ 2,
- /* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
- /* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[709],
- /* return matcher indices */ &kMatcherIndices[1],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* [446] */
+ /* num parameters */ 1,
+ /* num template types */ 0,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[961],
+ /* return matcher indices */ &kMatcherIndices[134],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [427] */
+ /* [447] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[987],
- /* return matcher indices */ &kMatcherIndices[103],
+ /* parameters */ &kParameters[962],
+ /* return matcher indices */ &kMatcherIndices[134],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [428] */
+ /* [448] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 2,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[5],
- /* parameters */ &kParameters[908],
- /* return matcher indices */ &kMatcherIndices[23],
+ /* parameters */ &kParameters[972],
+ /* return matcher indices */ &kMatcherIndices[18],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [429] */
- /* num parameters */ 0,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[990],
- /* return matcher indices */ nullptr,
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
- },
- {
- /* [430] */
+ /* [449] */
/* num parameters */ 3,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[507],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[525],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [431] */
+ /* [450] */
/* num parameters */ 2,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[767],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[697],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [432] */
+ /* [451] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[989],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* parameters */ &kParameters[868],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [433] */
+ /* [452] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[958],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* parameters */ &kParameters[867],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [434] */
+ /* [453] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[972],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* parameters */ &kParameters[866],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [435] */
+ /* [454] */
/* num parameters */ 1,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[977],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* parameters */ &kParameters[865],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [436] */
+ /* [455] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[982],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[857],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [437] */
+ /* [456] */
+ /* num parameters */ 2,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[11],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[785],
+ /* return matcher indices */ &kMatcherIndices[112],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* const eval */ nullptr,
+ },
+ {
+ /* [457] */
/* num parameters */ 3,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[504],
- /* return matcher indices */ &kMatcherIndices[31],
+ /* parameters */ &kParameters[453],
+ /* return matcher indices */ &kMatcherIndices[30],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [438] */
+ /* [458] */
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[597],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* parameters */ &kParameters[795],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [439] */
+ /* [459] */
/* num parameters */ 2,
/* num template types */ 0,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[26],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[799],
- /* return matcher indices */ &kMatcherIndices[44],
+ /* parameters */ &kParameters[793],
+ /* return matcher indices */ &kMatcherIndices[34],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [440] */
+ /* [460] */
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[8],
+ /* template types */ &kTemplateTypes[15],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[797],
+ /* parameters */ &kParameters[791],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [441] */
+ /* [461] */
/* num parameters */ 1,
- /* num template types */ 0,
+ /* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[20],
+ /* template types */ &kTemplateTypes[11],
/* template numbers */ &kTemplateNumbers[6],
- /* parameters */ &kParameters[809],
- /* return matcher indices */ &kMatcherIndices[5],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
- },
- {
- /* [442] */
- /* num parameters */ 2,
- /* num template types */ 0,
- /* num template numbers */ 0,
- /* template types */ &kTemplateTypes[20],
- /* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[791],
- /* return matcher indices */ &kMatcherIndices[121],
+ /* parameters */ &kParameters[827],
+ /* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [443] */
+ /* [462] */
/* num parameters */ 1,
/* num template types */ 1,
/* num template numbers */ 1,
- /* template types */ &kTemplateTypes[14],
+ /* template types */ &kTemplateTypes[19],
/* template numbers */ &kTemplateNumbers[8],
- /* parameters */ &kParameters[981],
- /* return matcher indices */ &kMatcherIndices[62],
+ /* parameters */ &kParameters[960],
+ /* return matcher indices */ &kMatcherIndices[35],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
{
- /* [444] */
- /* num parameters */ 3,
- /* num template types */ 1,
- /* num template numbers */ 1,
- /* template types */ &kTemplateTypes[11],
- /* template numbers */ &kTemplateNumbers[9],
- /* parameters */ &kParameters[591],
- /* return matcher indices */ &kMatcherIndices[173],
- /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* [463] */
+ /* num parameters */ 1,
+ /* num template types */ 0,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[26],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[864],
+ /* return matcher indices */ &kMatcherIndices[35],
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
},
};
@@ -13016,559 +13736,573 @@ constexpr OverloadInfo kOverloads[] = {
constexpr IntrinsicInfo kBuiltins[] = {
{
/* [0] */
- /* fn abs<T : fiu32>(T) -> T */
- /* fn abs<N : num, T : fiu32>(vec<N, T>) -> vec<N, T> */
+ /* fn abs<T : fiu32_f16>(T) -> T */
+ /* fn abs<N : num, T : fiu32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[405],
+ /* overloads */ &kOverloads[378],
},
{
/* [1] */
- /* fn acos(f32) -> f32 */
- /* fn acos<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn acos<T : f32_f16>(T) -> T */
+ /* fn acos<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[399],
+ /* overloads */ &kOverloads[420],
},
{
/* [2] */
+ /* fn acosh<T : f32_f16>(T) -> T */
+ /* fn acosh<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[418],
+ },
+ {
+ /* [3] */
/* fn all(bool) -> bool */
/* fn all<N : num>(vec<N, bool>) -> bool */
/* num overloads */ 2,
- /* overloads */ &kOverloads[397],
+ /* overloads */ &kOverloads[416],
},
{
- /* [3] */
+ /* [4] */
/* fn any(bool) -> bool */
/* fn any<N : num>(vec<N, bool>) -> bool */
/* num overloads */ 2,
- /* overloads */ &kOverloads[395],
+ /* overloads */ &kOverloads[414],
},
{
- /* [4] */
+ /* [5] */
/* fn arrayLength<T, A : access>(ptr<storage, array<T>, A>) -> u32 */
/* num overloads */ 1,
- /* overloads */ &kOverloads[443],
- },
- {
- /* [5] */
- /* fn asin(f32) -> f32 */
- /* fn asin<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[393],
+ /* overloads */ &kOverloads[462],
},
{
/* [6] */
- /* fn atan(f32) -> f32 */
- /* fn atan<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn asin<T : f32_f16>(T) -> T */
+ /* fn asin<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[391],
+ /* overloads */ &kOverloads[412],
},
{
/* [7] */
- /* fn atan2(f32, f32) -> f32 */
- /* fn atan2<N : num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
+ /* fn asinh<T : f32_f16>(T) -> T */
+ /* fn asinh<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[387],
+ /* overloads */ &kOverloads[408],
},
{
/* [8] */
- /* fn ceil(f32) -> f32 */
- /* fn ceil<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn atan<T : f32_f16>(T) -> T */
+ /* fn atan<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[385],
+ /* overloads */ &kOverloads[406],
},
{
/* [9] */
- /* fn clamp<T : fiu32>(T, T, T) -> T */
- /* fn clamp<N : num, T : fiu32>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* fn atan2<T : fa_f32_f16>(T, T) -> T */
+ /* fn atan2<T : fa_f32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[383],
+ /* overloads */ &kOverloads[400],
},
{
/* [10] */
- /* fn cos(f32) -> f32 */
- /* fn cos<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn atanh<T : f32_f16>(T) -> T */
+ /* fn atanh<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[381],
+ /* overloads */ &kOverloads[398],
},
{
/* [11] */
- /* fn cosh(f32) -> f32 */
- /* fn cosh<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn ceil<T : f32_f16>(T) -> T */
+ /* fn ceil<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[379],
+ /* overloads */ &kOverloads[396],
},
{
/* [12] */
+ /* fn clamp<T : fia_fiu32_f16>(T, T, T) -> T */
+ /* fn clamp<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[394],
+ },
+ {
+ /* [13] */
+ /* fn cos<T : f32_f16>(T) -> T */
+ /* fn cos<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[392],
+ },
+ {
+ /* [14] */
+ /* fn cosh<T : f32_f16>(T) -> T */
+ /* fn cosh<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[390],
+ },
+ {
+ /* [15] */
/* fn countLeadingZeros<T : iu32>(T) -> T */
/* fn countLeadingZeros<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[377],
+ /* overloads */ &kOverloads[386],
},
{
- /* [13] */
+ /* [16] */
/* fn countOneBits<T : iu32>(T) -> T */
/* fn countOneBits<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[375],
+ /* overloads */ &kOverloads[382],
},
{
- /* [14] */
+ /* [17] */
/* fn countTrailingZeros<T : iu32>(T) -> T */
/* fn countTrailingZeros<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[371],
+ /* overloads */ &kOverloads[380],
},
{
- /* [15] */
- /* fn cross(vec3<f32>, vec3<f32>) -> vec3<f32> */
+ /* [18] */
+ /* fn cross<T : f32_f16>(vec3<T>, vec3<T>) -> vec3<T> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[442],
+ /* overloads */ &kOverloads[456],
},
{
- /* [16] */
- /* fn degrees(f32) -> f32 */
- /* fn degrees<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* [19] */
+ /* fn degrees<T : f32_f16>(T) -> T */
+ /* fn degrees<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[369],
+ /* overloads */ &kOverloads[376],
},
{
- /* [17] */
- /* fn determinant<N : num>(mat<N, N, f32>) -> f32 */
+ /* [20] */
+ /* fn determinant<N : num, T : f32_f16>(mat<N, N, T>) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[441],
+ /* overloads */ &kOverloads[461],
},
{
- /* [18] */
- /* fn distance(f32, f32) -> f32 */
- /* fn distance<N : num>(vec<N, f32>, vec<N, f32>) -> f32 */
+ /* [21] */
+ /* fn distance<T : f32_f16>(T, T) -> T */
+ /* fn distance<N : num, T : f32_f16>(vec<N, T>, vec<N, T>) -> T */
/* num overloads */ 2,
- /* overloads */ &kOverloads[365],
+ /* overloads */ &kOverloads[374],
},
{
- /* [19] */
- /* fn dot<N : num, T : fiu32>(vec<N, T>, vec<N, T>) -> T */
+ /* [22] */
+ /* fn dot<N : num, T : fiu32_f16>(vec<N, T>, vec<N, T>) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[440],
+ /* overloads */ &kOverloads[460],
},
{
- /* [20] */
+ /* [23] */
/* fn dot4I8Packed(u32, u32) -> i32 */
/* num overloads */ 1,
- /* overloads */ &kOverloads[439],
+ /* overloads */ &kOverloads[459],
},
{
- /* [21] */
+ /* [24] */
/* fn dot4U8Packed(u32, u32) -> u32 */
/* num overloads */ 1,
- /* overloads */ &kOverloads[438],
+ /* overloads */ &kOverloads[458],
},
{
- /* [22] */
+ /* [25] */
/* fn dpdx(f32) -> f32 */
/* fn dpdx<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[363],
+ /* overloads */ &kOverloads[366],
},
{
- /* [23] */
+ /* [26] */
/* fn dpdxCoarse(f32) -> f32 */
/* fn dpdxCoarse<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[361],
+ /* overloads */ &kOverloads[362],
},
{
- /* [24] */
+ /* [27] */
/* fn dpdxFine(f32) -> f32 */
/* fn dpdxFine<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[359],
+ /* overloads */ &kOverloads[358],
},
{
- /* [25] */
+ /* [28] */
/* fn dpdy(f32) -> f32 */
/* fn dpdy<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[357],
+ /* overloads */ &kOverloads[338],
},
{
- /* [26] */
+ /* [29] */
/* fn dpdyCoarse(f32) -> f32 */
/* fn dpdyCoarse<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[347],
+ /* overloads */ &kOverloads[332],
},
{
- /* [27] */
+ /* [30] */
/* fn dpdyFine(f32) -> f32 */
/* fn dpdyFine<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[335],
+ /* overloads */ &kOverloads[330],
},
{
- /* [28] */
- /* fn exp(f32) -> f32 */
- /* fn exp<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* [31] */
+ /* fn exp<T : f32_f16>(T) -> T */
+ /* fn exp<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[319],
+ /* overloads */ &kOverloads[324],
},
{
- /* [29] */
- /* fn exp2(f32) -> f32 */
- /* fn exp2<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* [32] */
+ /* fn exp2<T : f32_f16>(T) -> T */
+ /* fn exp2<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[313],
+ /* overloads */ &kOverloads[322],
},
{
- /* [30] */
+ /* [33] */
/* fn extractBits<T : iu32>(T, u32, u32) -> T */
/* fn extractBits<N : num, T : iu32>(vec<N, T>, u32, u32) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[311],
+ /* overloads */ &kOverloads[320],
},
{
- /* [31] */
- /* fn faceForward<N : num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
+ /* [34] */
+ /* fn faceForward<N : num, T : f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[437],
+ /* overloads */ &kOverloads[457],
},
{
- /* [32] */
+ /* [35] */
/* fn firstLeadingBit<T : iu32>(T) -> T */
/* fn firstLeadingBit<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[305],
+ /* overloads */ &kOverloads[318],
},
{
- /* [33] */
+ /* [36] */
/* fn firstTrailingBit<T : iu32>(T) -> T */
/* fn firstTrailingBit<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[303],
- },
- {
- /* [34] */
- /* fn floor(f32) -> f32 */
- /* fn floor<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[301],
- },
- {
- /* [35] */
- /* fn fma(f32, f32, f32) -> f32 */
- /* fn fma<N : num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[297],
- },
- {
- /* [36] */
- /* fn fract(f32) -> f32 */
- /* fn fract<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[295],
+ /* overloads */ &kOverloads[352],
},
{
/* [37] */
- /* fn frexp(f32) -> __frexp_result */
- /* fn frexp<N : num>(vec<N, f32>) -> __frexp_result_vec<N> */
+ /* fn floor<T : f32_f16>(T) -> T */
+ /* fn floor<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[291],
+ /* overloads */ &kOverloads[314],
},
{
/* [38] */
- /* fn fwidth(f32) -> f32 */
- /* fn fwidth<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn fma<T : f32_f16>(T, T, T) -> T */
+ /* fn fma<N : num, T : f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[273],
+ /* overloads */ &kOverloads[310],
},
{
/* [39] */
- /* fn fwidthCoarse(f32) -> f32 */
- /* fn fwidthCoarse<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn fract<T : f32_f16>(T) -> T */
+ /* fn fract<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[271],
+ /* overloads */ &kOverloads[290],
},
{
/* [40] */
- /* fn fwidthFine(f32) -> f32 */
- /* fn fwidthFine<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn frexp<T : f32_f16>(T) -> __frexp_result<T> */
+ /* fn frexp<N : num, T : f32_f16>(vec<N, T>) -> __frexp_result_vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[299],
+ /* overloads */ &kOverloads[286],
},
{
/* [41] */
- /* fn insertBits<T : iu32>(T, T, u32, u32) -> T */
- /* fn insertBits<N : num, T : iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T> */
+ /* fn fwidth(f32) -> f32 */
+ /* fn fwidth<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[275],
+ /* overloads */ &kOverloads[288],
},
{
/* [42] */
- /* fn inverseSqrt(f32) -> f32 */
- /* fn inverseSqrt<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn fwidthCoarse(f32) -> f32 */
+ /* fn fwidthCoarse<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[277],
+ /* overloads */ &kOverloads[316],
},
{
/* [43] */
- /* fn ldexp(f32, i32) -> f32 */
- /* fn ldexp<N : num>(vec<N, f32>, vec<N, i32>) -> vec<N, f32> */
+ /* fn fwidthFine(f32) -> f32 */
+ /* fn fwidthFine<N : num>(vec<N, f32>) -> vec<N, f32> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[279],
+ /* overloads */ &kOverloads[292],
},
{
/* [44] */
- /* fn length(f32) -> f32 */
- /* fn length<N : num>(vec<N, f32>) -> f32 */
+ /* fn insertBits<T : iu32>(T, T, u32, u32) -> T */
+ /* fn insertBits<N : num, T : iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[281],
+ /* overloads */ &kOverloads[294],
},
{
/* [45] */
- /* fn log(f32) -> f32 */
- /* fn log<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn inverseSqrt<T : f32_f16>(T) -> T */
+ /* fn inverseSqrt<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[283],
+ /* overloads */ &kOverloads[296],
},
{
/* [46] */
- /* fn log2(f32) -> f32 */
- /* fn log2<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn ldexp<T : f32_f16>(T, i32) -> T */
+ /* fn ldexp<N : num, T : f32_f16>(vec<N, T>, vec<N, i32>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[285],
+ /* overloads */ &kOverloads[298],
},
{
/* [47] */
- /* fn max<T : fiu32>(T, T) -> T */
- /* fn max<N : num, T : fiu32>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* fn length<T : f32_f16>(T) -> T */
+ /* fn length<N : num, T : f32_f16>(vec<N, T>) -> T */
/* num overloads */ 2,
- /* overloads */ &kOverloads[287],
+ /* overloads */ &kOverloads[300],
},
{
/* [48] */
- /* fn min<T : fiu32>(T, T) -> T */
- /* fn min<N : num, T : fiu32>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* fn log<T : f32_f16>(T) -> T */
+ /* fn log<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[289],
+ /* overloads */ &kOverloads[302],
},
{
/* [49] */
- /* fn mix(f32, f32, f32) -> f32 */
- /* fn mix<N : num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
- /* fn mix<N : num>(vec<N, f32>, vec<N, f32>, f32) -> vec<N, f32> */
- /* num overloads */ 3,
- /* overloads */ &kOverloads[266],
+ /* fn log2<T : f32_f16>(T) -> T */
+ /* fn log2<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[304],
},
{
/* [50] */
- /* fn modf(f32) -> __modf_result */
- /* fn modf<N : num>(vec<N, f32>) -> __modf_result_vec<N> */
+ /* fn max<T : fiu32_f16>(T, T) -> T */
+ /* fn max<N : num, T : fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[293],
+ /* overloads */ &kOverloads[306],
},
{
/* [51] */
- /* fn normalize<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 1,
- /* overloads */ &kOverloads[436],
+ /* fn min<T : fiu32_f16>(T, T) -> T */
+ /* fn min<N : num, T : fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[308],
},
{
/* [52] */
- /* fn pack2x16float(vec2<f32>) -> u32 */
- /* num overloads */ 1,
- /* overloads */ &kOverloads[435],
+ /* fn mix<T : f32_f16>(T, T, T) -> T */
+ /* fn mix<N : num, T : f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* fn mix<N : num, T : f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T> */
+ /* num overloads */ 3,
+ /* overloads */ &kOverloads[281],
},
{
/* [53] */
- /* fn pack2x16snorm(vec2<f32>) -> u32 */
- /* num overloads */ 1,
- /* overloads */ &kOverloads[434],
+ /* fn modf<T : f32_f16>(T) -> __modf_result<T> */
+ /* fn modf<N : num, T : f32_f16>(vec<N, T>) -> __modf_result_vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[312],
},
{
/* [54] */
- /* fn pack2x16unorm(vec2<f32>) -> u32 */
+ /* fn normalize<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[421],
+ /* overloads */ &kOverloads[455],
},
{
/* [55] */
- /* fn pack4x8snorm(vec4<f32>) -> u32 */
+ /* fn pack2x16float(vec2<f32>) -> u32 */
/* num overloads */ 1,
- /* overloads */ &kOverloads[433],
+ /* overloads */ &kOverloads[463],
},
{
/* [56] */
- /* fn pack4x8unorm(vec4<f32>) -> u32 */
+ /* fn pack2x16snorm(vec2<f32>) -> u32 */
/* num overloads */ 1,
- /* overloads */ &kOverloads[432],
+ /* overloads */ &kOverloads[454],
},
{
/* [57] */
- /* fn pow(f32, f32) -> f32 */
- /* fn pow<N : num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[307],
+ /* fn pack2x16unorm(vec2<f32>) -> u32 */
+ /* num overloads */ 1,
+ /* overloads */ &kOverloads[453],
},
{
/* [58] */
- /* fn radians(f32) -> f32 */
- /* fn radians<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[309],
+ /* fn pack4x8snorm(vec4<f32>) -> u32 */
+ /* num overloads */ 1,
+ /* overloads */ &kOverloads[452],
},
{
/* [59] */
- /* fn reflect<N : num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
+ /* fn pack4x8unorm(vec4<f32>) -> u32 */
/* num overloads */ 1,
- /* overloads */ &kOverloads[431],
+ /* overloads */ &kOverloads[451],
},
{
/* [60] */
- /* fn refract<N : num>(vec<N, f32>, vec<N, f32>, f32) -> vec<N, f32> */
- /* num overloads */ 1,
- /* overloads */ &kOverloads[430],
+ /* fn pow<T : f32_f16>(T, T) -> T */
+ /* fn pow<N : num, T : f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[326],
},
{
/* [61] */
- /* fn reverseBits<T : iu32>(T) -> T */
- /* fn reverseBits<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
+ /* fn radians<T : f32_f16>(T) -> T */
+ /* fn radians<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[315],
+ /* overloads */ &kOverloads[328],
},
{
/* [62] */
- /* fn round(f32) -> f32 */
- /* fn round<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[317],
+ /* fn reflect<N : num, T : f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 1,
+ /* overloads */ &kOverloads[450],
},
{
/* [63] */
- /* fn select<T : scalar>(T, T, bool) -> T */
- /* fn select<T : scalar, N : num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T> */
- /* fn select<N : num, T : scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T> */
- /* num overloads */ 3,
- /* overloads */ &kOverloads[257],
+ /* fn refract<N : num, T : f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T> */
+ /* num overloads */ 1,
+ /* overloads */ &kOverloads[449],
},
{
/* [64] */
- /* fn sign(f32) -> f32 */
- /* fn sign<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn reverseBits<T : iu32>(T) -> T */
+ /* fn reverseBits<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[321],
+ /* overloads */ &kOverloads[334],
},
{
/* [65] */
- /* fn sin(f32) -> f32 */
- /* fn sin<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn round<T : f32_f16>(T) -> T */
+ /* fn round<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[323],
+ /* overloads */ &kOverloads[336],
},
{
/* [66] */
- /* fn sinh(f32) -> f32 */
- /* fn sinh<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[325],
+ /* fn select<T : scalar>(T, T, bool) -> T */
+ /* fn select<T : scalar, N : num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T> */
+ /* fn select<N : num, T : scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T> */
+ /* num overloads */ 3,
+ /* overloads */ &kOverloads[275],
},
{
/* [67] */
- /* fn smoothstep(f32, f32, f32) -> f32 */
- /* fn smoothstep<N : num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
+ /* fn sign<T : f32_f16>(T) -> T */
+ /* fn sign<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[327],
+ /* overloads */ &kOverloads[340],
},
{
/* [68] */
- /* fn smoothStep(f32, f32, f32) -> f32 */
- /* fn smoothStep<N : num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
+ /* fn sin<T : f32_f16>(T) -> T */
+ /* fn sin<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[329],
+ /* overloads */ &kOverloads[342],
},
{
/* [69] */
- /* fn sqrt(f32) -> f32 */
- /* fn sqrt<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn sinh<T : f32_f16>(T) -> T */
+ /* fn sinh<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[331],
+ /* overloads */ &kOverloads[344],
},
{
/* [70] */
- /* fn step(f32, f32) -> f32 */
- /* fn step<N : num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
+ /* fn smoothstep<T : f32_f16>(T, T, T) -> T */
+ /* fn smoothstep<N : num, T : f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[333],
+ /* overloads */ &kOverloads[346],
},
{
/* [71] */
- /* fn storageBarrier() */
- /* num overloads */ 1,
- /* overloads */ &kOverloads[429],
+ /* fn sqrt<T : f32_f16>(T) -> T */
+ /* fn sqrt<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[348],
},
{
/* [72] */
- /* fn tan(f32) -> f32 */
- /* fn tan<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn step<T : f32_f16>(T, T) -> T */
+ /* fn step<N : num, T : f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[337],
+ /* overloads */ &kOverloads[350],
},
{
/* [73] */
- /* fn tanh(f32) -> f32 */
- /* fn tanh<N : num>(vec<N, f32>) -> vec<N, f32> */
- /* num overloads */ 2,
- /* overloads */ &kOverloads[339],
+ /* fn storageBarrier() */
+ /* num overloads */ 1,
+ /* overloads */ &kOverloads[441],
},
{
/* [74] */
- /* fn transpose<M : num, N : num>(mat<M, N, f32>) -> mat<N, M, f32> */
- /* num overloads */ 1,
- /* overloads */ &kOverloads[428],
+ /* fn tan<T : f32_f16>(T) -> T */
+ /* fn tan<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[354],
},
{
/* [75] */
- /* fn trunc(f32) -> f32 */
- /* fn trunc<N : num>(vec<N, f32>) -> vec<N, f32> */
+ /* fn tanh<T : f32_f16>(T) -> T */
+ /* fn tanh<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[343],
+ /* overloads */ &kOverloads[356],
},
{
/* [76] */
- /* fn unpack2x16float(u32) -> vec2<f32> */
+ /* fn transpose<M : num, N : num, T : f32_f16>(mat<M, N, T>) -> mat<N, M, T> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[427],
+ /* overloads */ &kOverloads[448],
},
{
/* [77] */
+ /* fn trunc<T : f32_f16>(T) -> T */
+ /* fn trunc<N : num, T : f32_f16>(vec<N, T>) -> vec<N, T> */
+ /* num overloads */ 2,
+ /* overloads */ &kOverloads[360],
+ },
+ {
+ /* [78] */
+ /* fn unpack2x16float(u32) -> vec2<f32> */
+ /* num overloads */ 1,
+ /* overloads */ &kOverloads[447],
+ },
+ {
+ /* [79] */
/* fn unpack2x16snorm(u32) -> vec2<f32> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[409],
+ /* overloads */ &kOverloads[446],
},
{
- /* [78] */
+ /* [80] */
/* fn unpack2x16unorm(u32) -> vec2<f32> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[425],
+ /* overloads */ &kOverloads[445],
},
{
- /* [79] */
+ /* [81] */
/* fn unpack4x8snorm(u32) -> vec4<f32> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[424],
+ /* overloads */ &kOverloads[444],
},
{
- /* [80] */
+ /* [82] */
/* fn unpack4x8unorm(u32) -> vec4<f32> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[423],
+ /* overloads */ &kOverloads[443],
},
{
- /* [81] */
+ /* [83] */
/* fn workgroupBarrier() */
/* num overloads */ 1,
- /* overloads */ &kOverloads[422],
+ /* overloads */ &kOverloads[442],
},
{
- /* [82] */
+ /* [84] */
/* fn textureDimensions<T : fiu32>(texture: texture_1d<T>) -> i32 */
/* fn textureDimensions<T : fiu32>(texture: texture_1d<T>, level: i32) -> i32 */
/* fn textureDimensions<T : fiu32>(texture: texture_2d<T>) -> vec2<i32> */
@@ -13591,16 +14325,16 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureDimensions(texture: texture_depth_cube_array) -> vec2<i32> */
/* fn textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2<i32> */
/* fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<i32> */
- /* fn textureDimensions<F : texel_format, A : write_only>(texture: texture_storage_1d<F, A>) -> i32 */
- /* fn textureDimensions<F : texel_format, A : write_only>(texture: texture_storage_2d<F, A>) -> vec2<i32> */
- /* fn textureDimensions<F : texel_format, A : write_only>(texture: texture_storage_2d_array<F, A>) -> vec2<i32> */
- /* fn textureDimensions<F : texel_format, A : write_only>(texture: texture_storage_3d<F, A>) -> vec3<i32> */
+ /* fn textureDimensions<F : texel_format, A : write>(texture: texture_storage_1d<F, A>) -> i32 */
+ /* fn textureDimensions<F : texel_format, A : write>(texture: texture_storage_2d<F, A>) -> vec2<i32> */
+ /* fn textureDimensions<F : texel_format, A : write>(texture: texture_storage_2d_array<F, A>) -> vec2<i32> */
+ /* fn textureDimensions<F : texel_format, A : write>(texture: texture_storage_3d<F, A>) -> vec3<i32> */
/* fn textureDimensions(texture: texture_external) -> vec2<i32> */
/* num overloads */ 27,
/* overloads */ &kOverloads[0],
},
{
- /* [83] */
+ /* [85] */
/* fn textureGather<T : fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T> */
/* fn textureGather<T : fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T> */
/* fn textureGather<T : fiu32>(@const component: i32, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: i32) -> vec4<T> */
@@ -13614,10 +14348,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureGather(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> vec4<f32> */
/* fn textureGather(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: i32) -> vec4<f32> */
/* num overloads */ 12,
- /* overloads */ &kOverloads[71],
+ /* overloads */ &kOverloads[72],
},
{
- /* [84] */
+ /* [86] */
/* fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> vec4<f32> */
/* fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32> */
/* fn textureGatherCompare(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: i32, depth_ref: f32) -> vec4<f32> */
@@ -13625,20 +14359,20 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureGatherCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> vec4<f32> */
/* fn textureGatherCompare(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: i32, depth_ref: f32) -> vec4<f32> */
/* num overloads */ 6,
- /* overloads */ &kOverloads[157],
+ /* overloads */ &kOverloads[190],
},
{
- /* [85] */
+ /* [87] */
/* fn textureNumLayers<T : fiu32>(texture: texture_2d_array<T>) -> i32 */
/* fn textureNumLayers<T : fiu32>(texture: texture_cube_array<T>) -> i32 */
/* fn textureNumLayers(texture: texture_depth_2d_array) -> i32 */
/* fn textureNumLayers(texture: texture_depth_cube_array) -> i32 */
- /* fn textureNumLayers<F : texel_format, A : write_only>(texture: texture_storage_2d_array<F, A>) -> i32 */
+ /* fn textureNumLayers<F : texel_format, A : write>(texture: texture_storage_2d_array<F, A>) -> i32 */
/* num overloads */ 5,
- /* overloads */ &kOverloads[205],
+ /* overloads */ &kOverloads[237],
},
{
- /* [86] */
+ /* [88] */
/* fn textureNumLevels<T : fiu32>(texture: texture_1d<T>) -> i32 */
/* fn textureNumLevels<T : fiu32>(texture: texture_2d<T>) -> i32 */
/* fn textureNumLevels<T : fiu32>(texture: texture_2d_array<T>) -> i32 */
@@ -13650,17 +14384,17 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureNumLevels(texture: texture_depth_cube) -> i32 */
/* fn textureNumLevels(texture: texture_depth_cube_array) -> i32 */
/* num overloads */ 10,
- /* overloads */ &kOverloads[105],
+ /* overloads */ &kOverloads[107],
},
{
- /* [87] */
+ /* [89] */
/* fn textureNumSamples<T : fiu32>(texture: texture_multisampled_2d<T>) -> i32 */
/* fn textureNumSamples(texture: texture_depth_multisampled_2d) -> i32 */
/* num overloads */ 2,
- /* overloads */ &kOverloads[367],
+ /* overloads */ &kOverloads[384],
},
{
- /* [88] */
+ /* [90] */
/* fn textureSample(texture: texture_1d<f32>, sampler: sampler, coords: f32) -> vec4<f32> */
/* fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32> */
/* fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32> */
@@ -13677,10 +14411,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureSample(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> f32 */
/* fn textureSample(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: i32) -> f32 */
/* num overloads */ 15,
- /* overloads */ &kOverloads[27],
+ /* overloads */ &kOverloads[42],
},
{
- /* [89] */
+ /* [91] */
/* fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32) -> vec4<f32> */
/* fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32, @const offset: vec2<i32>) -> vec4<f32> */
/* fn textureSampleBias(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: i32, bias: f32) -> vec4<f32> */
@@ -13690,10 +14424,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureSampleBias(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32> */
/* fn textureSampleBias(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: i32, bias: f32) -> vec4<f32> */
/* num overloads */ 8,
- /* overloads */ &kOverloads[133],
+ /* overloads */ &kOverloads[152],
},
{
- /* [90] */
+ /* [92] */
/* fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32 */
/* fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32 */
/* fn textureSampleCompare(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: i32, depth_ref: f32) -> f32 */
@@ -13701,10 +14435,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureSampleCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32 */
/* fn textureSampleCompare(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: i32, depth_ref: f32) -> f32 */
/* num overloads */ 6,
- /* overloads */ &kOverloads[169],
+ /* overloads */ &kOverloads[166],
},
{
- /* [91] */
+ /* [93] */
/* fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32 */
/* fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32 */
/* fn textureSampleCompareLevel(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: i32, depth_ref: f32) -> f32 */
@@ -13712,10 +14446,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureSampleCompareLevel(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32 */
/* fn textureSampleCompareLevel(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: i32, depth_ref: f32) -> f32 */
/* num overloads */ 6,
- /* overloads */ &kOverloads[163],
+ /* overloads */ &kOverloads[184],
},
{
- /* [92] */
+ /* [94] */
/* fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32> */
/* fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32> */
/* fn textureSampleGrad(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: i32, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32> */
@@ -13725,10 +14459,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureSampleGrad(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32> */
/* fn textureSampleGrad(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: i32, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32> */
/* num overloads */ 8,
- /* overloads */ &kOverloads[141],
+ /* overloads */ &kOverloads[144],
},
{
- /* [93] */
+ /* [95] */
/* fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32) -> vec4<f32> */
/* fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32, @const offset: vec2<i32>) -> vec4<f32> */
/* fn textureSampleLevel(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: i32, level: f32) -> vec4<f32> */
@@ -13745,10 +14479,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureSampleLevel(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: i32, level: i32) -> f32 */
/* fn textureSampleLevel(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32> */
/* num overloads */ 15,
- /* overloads */ &kOverloads[42],
+ /* overloads */ &kOverloads[57],
},
{
- /* [94] */
+ /* [96] */
/* fn textureStore(texture: texture_storage_1d<f32_texel_format, write>, coords: i32, value: vec4<f32>) */
/* fn textureStore(texture: texture_storage_2d<f32_texel_format, write>, coords: vec2<i32>, value: vec4<f32>) */
/* fn textureStore(texture: texture_storage_2d_array<f32_texel_format, write>, coords: vec2<i32>, array_index: i32, value: vec4<f32>) */
@@ -13762,10 +14496,10 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureStore(texture: texture_storage_2d_array<u32_texel_format, write>, coords: vec2<i32>, array_index: i32, value: vec4<u32>) */
/* fn textureStore(texture: texture_storage_3d<u32_texel_format, write>, coords: vec3<i32>, value: vec4<u32>) */
/* num overloads */ 12,
- /* overloads */ &kOverloads[83],
+ /* overloads */ &kOverloads[84],
},
{
- /* [95] */
+ /* [97] */
/* fn textureLoad<T : fiu32>(texture: texture_1d<T>, coords: i32, level: i32) -> vec4<T> */
/* fn textureLoad<T : fiu32>(texture: texture_2d<T>, coords: vec2<i32>, level: i32) -> vec4<T> */
/* fn textureLoad<T : fiu32>(texture: texture_2d_array<T>, coords: vec2<i32>, array_index: i32, level: i32) -> vec4<T> */
@@ -13776,73 +14510,73 @@ constexpr IntrinsicInfo kBuiltins[] = {
/* fn textureLoad(texture: texture_depth_multisampled_2d, coords: vec2<i32>, sample_index: i32) -> f32 */
/* fn textureLoad(texture: texture_external, coords: vec2<i32>) -> vec4<f32> */
/* num overloads */ 9,
- /* overloads */ &kOverloads[115],
+ /* overloads */ &kOverloads[126],
},
{
- /* [96] */
+ /* [98] */
/* fn atomicLoad<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[418],
+ /* overloads */ &kOverloads[440],
},
{
- /* [97] */
+ /* [99] */
/* fn atomicStore<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) */
/* num overloads */ 1,
- /* overloads */ &kOverloads[417],
+ /* overloads */ &kOverloads[439],
},
{
- /* [98] */
+ /* [100] */
/* fn atomicAdd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[416],
+ /* overloads */ &kOverloads[436],
},
{
- /* [99] */
+ /* [101] */
/* fn atomicSub<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[415],
+ /* overloads */ &kOverloads[435],
},
{
- /* [100] */
+ /* [102] */
/* fn atomicMax<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[414],
+ /* overloads */ &kOverloads[434],
},
{
- /* [101] */
+ /* [103] */
/* fn atomicMin<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[413],
+ /* overloads */ &kOverloads[433],
},
{
- /* [102] */
+ /* [104] */
/* fn atomicAnd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[412],
+ /* overloads */ &kOverloads[432],
},
{
- /* [103] */
+ /* [105] */
/* fn atomicOr<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[411],
+ /* overloads */ &kOverloads[431],
},
{
- /* [104] */
+ /* [106] */
/* fn atomicXor<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[410],
+ /* overloads */ &kOverloads[430],
},
{
- /* [105] */
+ /* [107] */
/* fn atomicExchange<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
/* num overloads */ 1,
- /* overloads */ &kOverloads[426],
+ /* overloads */ &kOverloads[429],
},
{
- /* [106] */
+ /* [108] */
/* fn atomicCompareExchangeWeak<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T, T) -> __atomic_compare_exchange_result<T> */
/* num overloads */ 1,
- /* overloads */ &kOverloads[444],
+ /* overloads */ &kOverloads[428],
},
};
@@ -13852,21 +14586,21 @@ constexpr IntrinsicInfo kUnaryOperators[] = {
/* op !(bool) -> bool */
/* op !<N : num>(vec<N, bool>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[269],
+ /* overloads */ &kOverloads[424],
},
{
/* [1] */
- /* op ~<T : iu32>(T) -> T */
- /* op ~<T : iu32, N : num>(vec<N, T>) -> vec<N, T> */
+ /* op ~<T : ia_iu32>(T) -> T */
+ /* op ~<T : ia_iu32, N : num>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[403],
+ /* overloads */ &kOverloads[284],
},
{
/* [2] */
- /* op -<T : fi32>(T) -> T */
- /* op -<T : fi32, N : num>(vec<N, T>) -> vec<N, T> */
+ /* op -<T : fia_fi32_f16>(T) -> T */
+ /* op -<T : fia_fi32_f16, N : num>(vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[401],
+ /* overloads */ &kOverloads[422],
},
};
constexpr uint8_t kUnaryOperatorNot = 0;
@@ -13876,62 +14610,62 @@ constexpr uint8_t kUnaryOperatorMinus = 2;
constexpr IntrinsicInfo kBinaryOperators[] = {
{
/* [0] */
- /* op +<T : fiu32>(T, T) -> T */
- /* op +<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
- /* op +<T : fiu32, N : num>(vec<N, T>, T) -> vec<N, T> */
- /* op +<T : fiu32, N : num>(T, vec<N, T>) -> vec<N, T> */
- /* op +<N : num, M : num>(mat<N, M, f32>, mat<N, M, f32>) -> mat<N, M, f32> */
+ /* op +<T : fia_fiu32_f16>(T, T) -> T */
+ /* op +<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* op +<T : fia_fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+ /* op +<T : fia_fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+ /* op +<T : fa_f32_f16, N : num, M : num>(mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T> */
/* num overloads */ 5,
- /* overloads */ &kOverloads[220],
+ /* overloads */ &kOverloads[242],
},
{
/* [1] */
- /* op -<T : fiu32>(T, T) -> T */
- /* op -<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
- /* op -<T : fiu32, N : num>(vec<N, T>, T) -> vec<N, T> */
- /* op -<T : fiu32, N : num>(T, vec<N, T>) -> vec<N, T> */
- /* op -<N : num, M : num>(mat<N, M, f32>, mat<N, M, f32>) -> mat<N, M, f32> */
+ /* op -<T : fia_fiu32_f16>(T, T) -> T */
+ /* op -<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* op -<T : fia_fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+ /* op -<T : fia_fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+ /* op -<T : fa_f32_f16, N : num, M : num>(mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T> */
/* num overloads */ 5,
- /* overloads */ &kOverloads[215],
+ /* overloads */ &kOverloads[232],
},
{
/* [2] */
- /* op *<T : fiu32>(T, T) -> T */
- /* op *<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
- /* op *<T : fiu32, N : num>(vec<N, T>, T) -> vec<N, T> */
- /* op *<T : fiu32, N : num>(T, vec<N, T>) -> vec<N, T> */
- /* op *<N : num, M : num>(f32, mat<N, M, f32>) -> mat<N, M, f32> */
- /* op *<N : num, M : num>(mat<N, M, f32>, f32) -> mat<N, M, f32> */
- /* op *<C : num, R : num>(mat<C, R, f32>, vec<C, f32>) -> vec<R, f32> */
- /* op *<C : num, R : num>(vec<R, f32>, mat<C, R, f32>) -> vec<C, f32> */
- /* op *<K : num, C : num, R : num>(mat<K, R, f32>, mat<C, K, f32>) -> mat<C, R, f32> */
+ /* op *<T : fiu32_f16>(T, T) -> T */
+ /* op *<T : fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* op *<T : fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+ /* op *<T : fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+ /* op *<T : f32_f16, N : num, M : num>(T, mat<N, M, T>) -> mat<N, M, T> */
+ /* op *<T : f32_f16, N : num, M : num>(mat<N, M, T>, T) -> mat<N, M, T> */
+ /* op *<T : f32_f16, C : num, R : num>(mat<C, R, T>, vec<C, T>) -> vec<R, T> */
+ /* op *<T : f32_f16, C : num, R : num>(vec<R, T>, mat<C, R, T>) -> vec<C, T> */
+ /* op *<T : f32_f16, K : num, C : num, R : num>(mat<K, R, T>, mat<C, K, T>) -> mat<C, R, T> */
/* num overloads */ 9,
- /* overloads */ &kOverloads[124],
+ /* overloads */ &kOverloads[117],
},
{
/* [3] */
- /* op /<T : fiu32>(T, T) -> T */
- /* op /<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
- /* op /<T : fiu32, N : num>(vec<N, T>, T) -> vec<N, T> */
- /* op /<T : fiu32, N : num>(T, vec<N, T>) -> vec<N, T> */
+ /* op /<T : fiu32_f16>(T, T) -> T */
+ /* op /<T : fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* op /<T : fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+ /* op /<T : fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
/* num overloads */ 4,
- /* overloads */ &kOverloads[243],
+ /* overloads */ &kOverloads[259],
},
{
/* [4] */
- /* op %<T : fiu32>(T, T) -> T */
- /* op %<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
- /* op %<T : fiu32, N : num>(vec<N, T>, T) -> vec<N, T> */
- /* op %<T : fiu32, N : num>(T, vec<N, T>) -> vec<N, T> */
+ /* op %<T : fiu32_f16>(T, T) -> T */
+ /* op %<T : fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+ /* op %<T : fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+ /* op %<T : fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
/* num overloads */ 4,
- /* overloads */ &kOverloads[239],
+ /* overloads */ &kOverloads[247],
},
{
/* [5] */
/* op ^<T : iu32>(T, T) -> T */
/* op ^<T : iu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[389],
+ /* overloads */ &kOverloads[410],
},
{
/* [6] */
@@ -13940,7 +14674,7 @@ constexpr IntrinsicInfo kBinaryOperators[] = {
/* op &<T : iu32>(T, T) -> T */
/* op &<T : iu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 4,
- /* overloads */ &kOverloads[235],
+ /* overloads */ &kOverloads[251],
},
{
/* [7] */
@@ -13949,75 +14683,75 @@ constexpr IntrinsicInfo kBinaryOperators[] = {
/* op |<T : iu32>(T, T) -> T */
/* op |<T : iu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
/* num overloads */ 4,
- /* overloads */ &kOverloads[247],
+ /* overloads */ &kOverloads[255],
},
{
/* [8] */
/* op &&(bool, bool) -> bool */
/* num overloads */ 1,
- /* overloads */ &kOverloads[419],
+ /* overloads */ &kOverloads[437],
},
{
/* [9] */
/* op ||(bool, bool) -> bool */
/* num overloads */ 1,
- /* overloads */ &kOverloads[420],
+ /* overloads */ &kOverloads[438],
},
{
/* [10] */
/* op ==<T : scalar>(T, T) -> bool */
/* op ==<T : scalar, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[373],
+ /* overloads */ &kOverloads[404],
},
{
/* [11] */
/* op !=<T : scalar>(T, T) -> bool */
/* op !=<T : scalar, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[355],
+ /* overloads */ &kOverloads[402],
},
{
/* [12] */
- /* op <<T : fiu32>(T, T) -> bool */
- /* op <<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+ /* op <<T : fiu32_f16>(T, T) -> bool */
+ /* op <<T : fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[353],
+ /* overloads */ &kOverloads[388],
},
{
/* [13] */
- /* op ><T : fiu32>(T, T) -> bool */
- /* op ><T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+ /* op ><T : fiu32_f16>(T, T) -> bool */
+ /* op ><T : fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[351],
+ /* overloads */ &kOverloads[372],
},
{
/* [14] */
- /* op <=<T : fiu32>(T, T) -> bool */
- /* op <=<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+ /* op <=<T : fiu32_f16>(T, T) -> bool */
+ /* op <=<T : fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[349],
+ /* overloads */ &kOverloads[370],
},
{
/* [15] */
- /* op >=<T : fiu32>(T, T) -> bool */
- /* op >=<T : fiu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+ /* op >=<T : fiu32_f16>(T, T) -> bool */
+ /* op >=<T : fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[407],
+ /* overloads */ &kOverloads[368],
},
{
/* [16] */
/* op <<<T : iu32>(T, u32) -> T */
/* op <<<T : iu32, N : num>(vec<N, T>, vec<N, u32>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[345],
+ /* overloads */ &kOverloads[426],
},
{
/* [17] */
/* op >><T : iu32>(T, u32) -> T */
/* op >><T : iu32, N : num>(vec<N, T>, vec<N, u32>) -> vec<N, T> */
/* num overloads */ 2,
- /* overloads */ &kOverloads[341],
+ /* overloads */ &kOverloads[364],
},
};
constexpr uint8_t kBinaryOperatorPlus = 0;
@@ -14046,7 +14780,7 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = {
/* ctor i32(i32) -> i32 */
/* conv i32<T : scalar_no_i32>(T) -> i32 */
/* num overloads */ 3,
- /* overloads */ &kOverloads[251],
+ /* overloads */ &kOverloads[263],
},
{
/* [1] */
@@ -14054,7 +14788,7 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = {
/* ctor u32(u32) -> u32 */
/* conv u32<T : scalar_no_u32>(T) -> u32 */
/* num overloads */ 3,
- /* overloads */ &kOverloads[260],
+ /* overloads */ &kOverloads[278],
},
{
/* [2] */
@@ -14062,31 +14796,40 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = {
/* ctor f32(f32) -> f32 */
/* conv f32<T : scalar_no_f32>(T) -> f32 */
/* num overloads */ 3,
- /* overloads */ &kOverloads[263],
+ /* overloads */ &kOverloads[272],
},
{
/* [3] */
+ /* ctor f16() -> f16 */
+ /* ctor f16(f16) -> f16 */
+ /* conv f16<T : scalar_no_f16>(T) -> f16 */
+ /* num overloads */ 3,
+ /* overloads */ &kOverloads[269],
+ },
+ {
+ /* [4] */
/* ctor bool() -> bool */
/* ctor bool(bool) -> bool */
/* conv bool<T : scalar_no_bool>(T) -> bool */
/* num overloads */ 3,
- /* overloads */ &kOverloads[254],
+ /* overloads */ &kOverloads[266],
},
{
- /* [4] */
+ /* [5] */
/* ctor vec2<T : scalar>() -> vec2<T> */
/* ctor vec2<T : scalar>(vec2<T>) -> vec2<T> */
/* ctor vec2<T : abstract_or_scalar>(T) -> vec2<T> */
/* ctor vec2<T : abstract_or_scalar>(x: T, y: T) -> vec2<T> */
/* conv vec2<T : f32, U : scalar_no_f32>(vec2<U>) -> vec2<f32> */
+ /* conv vec2<T : f16, U : scalar_no_f16>(vec2<U>) -> vec2<f16> */
/* conv vec2<T : i32, U : scalar_no_i32>(vec2<U>) -> vec2<i32> */
/* conv vec2<T : u32, U : scalar_no_u32>(vec2<U>) -> vec2<u32> */
/* conv vec2<T : bool, U : scalar_no_bool>(vec2<U>) -> vec2<bool> */
- /* num overloads */ 8,
- /* overloads */ &kOverloads[149],
+ /* num overloads */ 9,
+ /* overloads */ &kOverloads[135],
},
{
- /* [5] */
+ /* [6] */
/* ctor vec3<T : scalar>() -> vec3<T> */
/* ctor vec3<T : scalar>(vec3<T>) -> vec3<T> */
/* ctor vec3<T : abstract_or_scalar>(T) -> vec3<T> */
@@ -14094,14 +14837,15 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = {
/* ctor vec3<T : abstract_or_scalar>(xy: vec2<T>, z: T) -> vec3<T> */
/* ctor vec3<T : abstract_or_scalar>(x: T, yz: vec2<T>) -> vec3<T> */
/* conv vec3<T : f32, U : scalar_no_f32>(vec3<U>) -> vec3<f32> */
+ /* conv vec3<T : f16, U : scalar_no_f16>(vec3<U>) -> vec3<f16> */
/* conv vec3<T : i32, U : scalar_no_i32>(vec3<U>) -> vec3<i32> */
/* conv vec3<T : u32, U : scalar_no_u32>(vec3<U>) -> vec3<u32> */
/* conv vec3<T : bool, U : scalar_no_bool>(vec3<U>) -> vec3<bool> */
- /* num overloads */ 10,
- /* overloads */ &kOverloads[95],
+ /* num overloads */ 11,
+ /* overloads */ &kOverloads[96],
},
{
- /* [6] */
+ /* [7] */
/* ctor vec4<T : scalar>() -> vec4<T> */
/* ctor vec4<T : scalar>(vec4<T>) -> vec4<T> */
/* ctor vec4<T : abstract_or_scalar>(T) -> vec4<T> */
@@ -14113,101 +14857,111 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = {
/* ctor vec4<T : abstract_or_scalar>(xyz: vec3<T>, w: T) -> vec4<T> */
/* ctor vec4<T : abstract_or_scalar>(x: T, zyw: vec3<T>) -> vec4<T> */
/* conv vec4<T : f32, U : scalar_no_f32>(vec4<U>) -> vec4<f32> */
+ /* conv vec4<T : f16, U : scalar_no_f16>(vec4<U>) -> vec4<f16> */
/* conv vec4<T : i32, U : scalar_no_i32>(vec4<U>) -> vec4<i32> */
/* conv vec4<T : u32, U : scalar_no_u32>(vec4<U>) -> vec4<u32> */
/* conv vec4<T : bool, U : scalar_no_bool>(vec4<U>) -> vec4<bool> */
- /* num overloads */ 14,
- /* overloads */ &kOverloads[57],
- },
- {
- /* [7] */
- /* ctor mat2x2() -> mat2x2<f32> */
- /* ctor mat2x2<f32>(mat2x2<f32>) -> mat2x2<f32> */
- /* ctor mat2x2<T : af_f32>(T) -> mat2x2<T> */
- /* ctor mat2x2<T : af_f32>(T, T, T, T) -> mat2x2<T> */
- /* ctor mat2x2<T : af_f32>(vec2<T>, vec2<T>) -> mat2x2<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[190],
+ /* num overloads */ 15,
+ /* overloads */ &kOverloads[27],
},
{
/* [8] */
- /* ctor mat2x3() -> mat2x3<f32> */
- /* ctor mat2x3<f32>(mat2x3<f32>) -> mat2x3<f32> */
- /* ctor mat2x3<T : af_f32>(T) -> mat2x3<T> */
- /* ctor mat2x3<T : af_f32>(T, T, T, T, T, T) -> mat2x3<T> */
- /* ctor mat2x3<T : af_f32>(vec3<T>, vec3<T>) -> mat2x3<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[175],
+ /* ctor mat2x2<T : f32_f16>() -> mat2x2<T> */
+ /* ctor mat2x2<T : f32_f16>(mat2x2<T>) -> mat2x2<T> */
+ /* ctor mat2x2<T : fa_f32_f16>(T, T, T, T) -> mat2x2<T> */
+ /* ctor mat2x2<T : fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T> */
+ /* conv mat2x2<T : f16>(mat2x2<f32>) -> mat2x2<f16> */
+ /* conv mat2x2<T : f32>(mat2x2<f16>) -> mat2x2<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[178],
},
{
/* [9] */
- /* ctor mat2x4() -> mat2x4<f32> */
- /* ctor mat2x4<f32>(mat2x4<f32>) -> mat2x4<f32> */
- /* ctor mat2x4<T : af_f32>(T) -> mat2x4<T> */
- /* ctor mat2x4<T : af_f32>(T, T, T, T, T, T, T, T) -> mat2x4<T> */
- /* ctor mat2x4<T : af_f32>(vec4<T>, vec4<T>) -> mat2x4<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[200],
+ /* ctor mat2x3<T : f32_f16>() -> mat2x3<T> */
+ /* ctor mat2x3<T : f32_f16>(mat2x3<T>) -> mat2x3<T> */
+ /* ctor mat2x3<T : fa_f32_f16>(T, T, T, T, T, T) -> mat2x3<T> */
+ /* ctor mat2x3<T : fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T> */
+ /* conv mat2x3<T : f16>(mat2x3<f32>) -> mat2x3<f16> */
+ /* conv mat2x3<T : f32>(mat2x3<f16>) -> mat2x3<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[196],
},
{
/* [10] */
- /* ctor mat3x2() -> mat3x2<f32> */
- /* ctor mat3x2<f32>(mat3x2<f32>) -> mat3x2<f32> */
- /* ctor mat3x2<T : af_f32>(T) -> mat3x2<T> */
- /* ctor mat3x2<T : af_f32>(T, T, T, T, T, T) -> mat3x2<T> */
- /* ctor mat3x2<T : af_f32>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[195],
+ /* ctor mat2x4<T : f32_f16>() -> mat2x4<T> */
+ /* ctor mat2x4<T : f32_f16>(mat2x4<T>) -> mat2x4<T> */
+ /* ctor mat2x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat2x4<T> */
+ /* ctor mat2x4<T : fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T> */
+ /* conv mat2x4<T : f16>(mat2x4<f32>) -> mat2x4<f16> */
+ /* conv mat2x4<T : f32>(mat2x4<f16>) -> mat2x4<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[172],
},
{
/* [11] */
- /* ctor mat3x3() -> mat3x3<f32> */
- /* ctor mat3x3<f32>(mat3x3<f32>) -> mat3x3<f32> */
- /* ctor mat3x3<T : af_f32>(T) -> mat3x3<T> */
- /* ctor mat3x3<T : af_f32>(T, T, T, T, T, T, T, T, T) -> mat3x3<T> */
- /* ctor mat3x3<T : af_f32>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[230],
+ /* ctor mat3x2<T : f32_f16>() -> mat3x2<T> */
+ /* ctor mat3x2<T : f32_f16>(mat3x2<T>) -> mat3x2<T> */
+ /* ctor mat3x2<T : fa_f32_f16>(T, T, T, T, T, T) -> mat3x2<T> */
+ /* ctor mat3x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T> */
+ /* conv mat3x2<T : f16>(mat3x2<f32>) -> mat3x2<f16> */
+ /* conv mat3x2<T : f32>(mat3x2<f16>) -> mat3x2<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[226],
},
{
/* [12] */
- /* ctor mat3x4() -> mat3x4<f32> */
- /* ctor mat3x4<f32>(mat3x4<f32>) -> mat3x4<f32> */
- /* ctor mat3x4<T : af_f32>(T) -> mat3x4<T> */
- /* ctor mat3x4<T : af_f32>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat3x4<T> */
- /* ctor mat3x4<T : af_f32>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[180],
+ /* ctor mat3x3<T : f32_f16>() -> mat3x3<T> */
+ /* ctor mat3x3<T : f32_f16>(mat3x3<T>) -> mat3x3<T> */
+ /* ctor mat3x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T) -> mat3x3<T> */
+ /* ctor mat3x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T> */
+ /* conv mat3x3<T : f16>(mat3x3<f32>) -> mat3x3<f16> */
+ /* conv mat3x3<T : f32>(mat3x3<f16>) -> mat3x3<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[220],
},
{
/* [13] */
- /* ctor mat4x2() -> mat4x2<f32> */
- /* ctor mat4x2<f32>(mat4x2<f32>) -> mat4x2<f32> */
- /* ctor mat4x2<T : af_f32>(T) -> mat4x2<T> */
- /* ctor mat4x2<T : af_f32>(T, T, T, T, T, T, T, T) -> mat4x2<T> */
- /* ctor mat4x2<T : af_f32>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[185],
+ /* ctor mat3x4<T : f32_f16>() -> mat3x4<T> */
+ /* ctor mat3x4<T : f32_f16>(mat3x4<T>) -> mat3x4<T> */
+ /* ctor mat3x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat3x4<T> */
+ /* ctor mat3x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T> */
+ /* conv mat3x4<T : f16>(mat3x4<f32>) -> mat3x4<f16> */
+ /* conv mat3x4<T : f32>(mat3x4<f16>) -> mat3x4<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[214],
},
{
/* [14] */
- /* ctor mat4x3() -> mat4x3<f32> */
- /* ctor mat4x3<f32>(mat4x3<f32>) -> mat4x3<f32> */
- /* ctor mat4x3<T : af_f32>(T) -> mat4x3<T> */
- /* ctor mat4x3<T : af_f32>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x3<T> */
- /* ctor mat4x3<T : af_f32>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[210],
+ /* ctor mat4x2<T : f32_f16>() -> mat4x2<T> */
+ /* ctor mat4x2<T : f32_f16>(mat4x2<T>) -> mat4x2<T> */
+ /* ctor mat4x2<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat4x2<T> */
+ /* ctor mat4x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T> */
+ /* conv mat4x2<T : f16>(mat4x2<f32>) -> mat4x2<f16> */
+ /* conv mat4x2<T : f32>(mat4x2<f16>) -> mat4x2<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[202],
},
{
/* [15] */
- /* ctor mat4x4() -> mat4x4<f32> */
- /* ctor mat4x4<f32>(mat4x4<f32>) -> mat4x4<f32> */
- /* ctor mat4x4<T : af_f32>(T) -> mat4x4<T> */
- /* ctor mat4x4<T : af_f32>(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x4<T> */
- /* ctor mat4x4<T : af_f32>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T> */
- /* num overloads */ 5,
- /* overloads */ &kOverloads[225],
+ /* ctor mat4x3<T : f32_f16>() -> mat4x3<T> */
+ /* ctor mat4x3<T : f32_f16>(mat4x3<T>) -> mat4x3<T> */
+ /* ctor mat4x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x3<T> */
+ /* ctor mat4x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T> */
+ /* conv mat4x3<T : f16>(mat4x3<f32>) -> mat4x3<f16> */
+ /* conv mat4x3<T : f32>(mat4x3<f16>) -> mat4x3<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[208],
+ },
+ {
+ /* [16] */
+ /* ctor mat4x4<T : f32_f16>() -> mat4x4<T> */
+ /* ctor mat4x4<T : f32_f16>(mat4x4<T>) -> mat4x4<T> */
+ /* ctor mat4x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x4<T> */
+ /* ctor mat4x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T> */
+ /* conv mat4x4<T : f16>(mat4x4<f32>) -> mat4x4<f16> */
+ /* conv mat4x4<T : f32>(mat4x4<f16>) -> mat4x4<f32> */
+ /* num overloads */ 6,
+ /* overloads */ &kOverloads[160],
},
};
diff --git a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl.tmpl b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl.tmpl
index 663013ed7f1..750c29f381e 100644
--- a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl.tmpl
+++ b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table.inl.tmpl
@@ -1,17 +1,20 @@
{{- /*
--------------------------------------------------------------------------------
-Template file for use with tools/builtin-gen to generate builtin_table.inl
+Template file for use with tools/src/cmd/gen to generate builtin_table.inl
Used by BuiltinTable.cc for builtin overload resolution.
+To update the generated file, run:
+ ./tools/run gen
+
See:
-* tools/cmd/intrinsic-gen/gen for structures used by this template
+* tools/src/cmd/gen for structures used by this template
* https://golang.org/pkg/text/template/ for documentation on the template syntax
--------------------------------------------------------------------------------
*/ -}}
// clang-format off
-{{ with .Sem -}}
+{{ with Sem -}}
{{ range .Types -}}
{{ template "Type" . }}
{{ end -}}
@@ -103,7 +106,7 @@ constexpr OverloadInfo kOverloads[] = {
{{- end }}
{{- if $o.IsDeprecated}}, OverloadFlag::kIsDeprecated{{end }}),
/* const eval */
-{{- if $o.ConstEvalFunction }} const_eval::{{$o.ConstEvalFunction}},
+{{- if $o.ConstEvalFunction }} {{template "ConstEvalFn" $o}},
{{- else }} nullptr,
{{- end }}
},
@@ -137,7 +140,7 @@ constexpr IntrinsicInfo kUnaryOperators[] = {
};
{{- range $i, $o := .UnaryOperators }}
-constexpr uint8_t kUnaryOperator{{template "OperatorName" $o.Name}} = {{$i}};
+constexpr uint8_t kUnaryOperator{{ template "ExpandName" $o.Name}} = {{$i}};
{{- end }}
constexpr IntrinsicInfo kBinaryOperators[] = {
@@ -154,7 +157,7 @@ constexpr IntrinsicInfo kBinaryOperators[] = {
};
{{- range $i, $o := .BinaryOperators }}
-constexpr uint8_t kBinaryOperator{{template "OperatorName" $o.Name}} = {{$i}};
+constexpr uint8_t kBinaryOperator{{ template "ExpandName" $o.Name}} = {{$i}};
{{- end }}
constexpr IntrinsicInfo kConstructorsAndConverters[] = {
@@ -179,7 +182,6 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = {
{{- $class := PascalCase .Name -}}
/// TypeMatcher for 'type {{.Name}}'
{{- if .Decl.Source.S.Filepath }}
-/// @see {{.Decl.Source}}
{{- end }}
class {{$class}} : public TypeMatcher {
public:
@@ -234,7 +236,6 @@ std::string {{$class}}::String(MatchState*{{if .TemplateParams}} state{{end}}) c
{{- $class := PascalCase .Name -}}
/// TypeMatcher for 'match {{.Name}}'
{{- if .Decl.Source.S.Filepath }}
-/// @see {{.Decl.Source}}
{{- end }}
class {{$class}} : public TypeMatcher {
public:
@@ -282,7 +283,6 @@ std::string {{$class}}::String(MatchState*) const {
{{- $enum := PascalCase .Enum.Name -}}
/// EnumMatcher for 'match {{.Name}}'
{{- if .Decl.Source.S.Filepath }}
-/// @see {{.Decl.Source}}
{{- end }}
class {{$class}} : public NumberMatcher {
public:
@@ -339,27 +339,27 @@ class Matchers {
private:
{{- $t_names := Map -}}
{{- $n_names := Map -}}
-{{- range Iterate .Sem.MaxTemplateTypes -}}
+{{- range Iterate Sem.MaxTemplateTypes -}}
{{- $name := printf "template_type_%v" . -}}
{{- $t_names.Put . $name }}
TemplateTypeMatcher {{$name}}_{ {{- . -}} };
{{- end }}
-{{- range Iterate .Sem.MaxTemplateNumbers -}}
+{{- range Iterate Sem.MaxTemplateNumbers -}}
{{- $name := printf "template_number_%v" . -}}
{{- $n_names.Put . $name }}
TemplateNumberMatcher {{$name}}_{ {{- . -}} };
{{- end }}
-{{- range .Sem.Types -}}
+{{- range Sem.Types -}}
{{- $name := PascalCase .Name -}}
{{- $t_names.Put . $name }}
{{$name}} {{$name}}_;
{{- end }}
-{{- range .Sem.TypeMatchers -}}
+{{- range Sem.TypeMatchers -}}
{{- $name := PascalCase .Name -}}
{{- $t_names.Put . $name }}
{{$name}} {{$name}}_;
{{- end }}
-{{- range .Sem.EnumMatchers -}}
+{{- range Sem.EnumMatchers -}}
{{- $name := PascalCase .Name -}}
{{- $n_names.Put . $name }}
{{$name}} {{$name}}_;
@@ -455,7 +455,7 @@ Matchers::~Matchers() = default;
{{- end -}}
{{- /* ------------------------------------------------------------------ */ -}}
-{{- define "OperatorName" -}}
+{{- define "ExpandName" -}}
{{- /* ------------------------------------------------------------------ */ -}}
{{- if eq . "<<" -}}ShiftLeft
{{- else if eq . "&" -}}And
@@ -478,6 +478,16 @@ Matchers::~Matchers() = default;
{{- else if eq . "*" -}}Star
{{- else if eq . "/" -}}Divide
{{- else if eq . "%" -}}Modulo
-{{- else -}}<unknown-{{.}}>
+{{- else -}}{{.}}
{{- end -}}
{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- define "ConstEvalFn" -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+ &ConstEval::
+{{- if eq .Kind "operator" -}}Op{{end -}}
+ {{template "ExpandName" .ConstEvalFunction}}
+{{- end -}}
+
diff --git a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table_test.cc b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table_test.cc
index e2c651e8745..02c97f7aac8 100644
--- a/chromium/third_party/dawn/src/tint/resolver/intrinsic_table_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/intrinsic_table_test.cc
@@ -53,18 +53,18 @@ class IntrinsicTableTest : public testing::Test, public ProgramBuilder {
TEST_F(IntrinsicTableTest, MatchF32) {
auto* f32 = create<sem::F32>();
- auto result = table->Lookup(BuiltinType::kCos, {f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kCos, utils::Vector{f32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCos);
EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
}
TEST_F(IntrinsicTableTest, MismatchF32) {
auto* i32 = create<sem::I32>();
- auto result = table->Lookup(BuiltinType::kCos, {i32}, Source{});
+ auto result = table->Lookup(BuiltinType::kCos, utils::Vector{i32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -73,18 +73,18 @@ TEST_F(IntrinsicTableTest, MatchU32) {
auto* f32 = create<sem::F32>();
auto* u32 = create<sem::U32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
- auto result = table->Lookup(BuiltinType::kUnpack2x16float, {u32}, Source{});
+ auto result = table->Lookup(BuiltinType::kUnpack2x16float, utils::Vector{u32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kUnpack2x16float);
EXPECT_EQ(result.sem->ReturnType(), vec2_f32);
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
}
TEST_F(IntrinsicTableTest, MismatchU32) {
auto* f32 = create<sem::F32>();
- auto result = table->Lookup(BuiltinType::kUnpack2x16float, {f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kUnpack2x16float, utils::Vector{f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -94,12 +94,12 @@ TEST_F(IntrinsicTableTest, MatchI32) {
auto* i32 = create<sem::I32>();
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
- auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, i32, i32}, Source{});
+ auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, i32, i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), i32);
@@ -111,48 +111,48 @@ TEST_F(IntrinsicTableTest, MatchI32) {
TEST_F(IntrinsicTableTest, MismatchI32) {
auto* f32 = create<sem::F32>();
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
- auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
auto* i32 = create<sem::I32>();
- auto result = table->Lookup(BuiltinType::kCountOneBits, {i32}, Source{});
+ auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits);
EXPECT_EQ(result.sem->ReturnType(), i32);
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), i32);
}
TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
auto* u32 = create<sem::U32>();
- auto result = table->Lookup(BuiltinType::kCountOneBits, {u32}, Source{});
+ auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{u32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits);
EXPECT_EQ(result.sem->ReturnType(), u32);
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
}
TEST_F(IntrinsicTableTest, MismatchIU32) {
auto* f32 = create<sem::F32>();
- auto result = table->Lookup(BuiltinType::kCountOneBits, {f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
auto* i32 = create<sem::I32>();
- auto result = table->Lookup(BuiltinType::kClamp, {i32, i32, i32}, Source{});
+ auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{i32, i32, i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
EXPECT_EQ(result.sem->ReturnType(), i32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), i32);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), i32);
EXPECT_EQ(result.sem->Parameters()[2]->Type(), i32);
@@ -160,12 +160,12 @@ TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
auto* u32 = create<sem::U32>();
- auto result = table->Lookup(BuiltinType::kClamp, {u32, u32, u32}, Source{});
+ auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{u32, u32, u32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
EXPECT_EQ(result.sem->ReturnType(), u32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), u32);
EXPECT_EQ(result.sem->Parameters()[2]->Type(), u32);
@@ -173,12 +173,12 @@ TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
auto* f32 = create<sem::F32>();
- auto result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), f32);
EXPECT_EQ(result.sem->Parameters()[2]->Type(), f32);
@@ -186,7 +186,7 @@ TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
TEST_F(IntrinsicTableTest, MismatchFIU32) {
auto* bool_ = create<sem::Bool>();
- auto result = table->Lookup(BuiltinType::kClamp, {bool_, bool_, bool_}, Source{});
+ auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{bool_, bool_, bool_}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -194,12 +194,12 @@ TEST_F(IntrinsicTableTest, MismatchFIU32) {
TEST_F(IntrinsicTableTest, MatchBool) {
auto* f32 = create<sem::F32>();
auto* bool_ = create<sem::Bool>();
- auto result = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
+ auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), f32);
EXPECT_EQ(result.sem->Parameters()[2]->Type(), bool_);
@@ -207,7 +207,7 @@ TEST_F(IntrinsicTableTest, MatchBool) {
TEST_F(IntrinsicTableTest, MismatchBool) {
auto* f32 = create<sem::F32>();
- auto result = table->Lookup(BuiltinType::kSelect, {f32, f32, f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -217,19 +217,19 @@ TEST_F(IntrinsicTableTest, MatchPointer) {
auto* atomicI32 = create<sem::Atomic>(i32);
auto* ptr =
create<sem::Pointer>(atomicI32, ast::StorageClass::kWorkgroup, ast::Access::kReadWrite);
- auto result = table->Lookup(BuiltinType::kAtomicLoad, {ptr}, Source{});
+ auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{ptr}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kAtomicLoad);
EXPECT_EQ(result.sem->ReturnType(), i32);
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), ptr);
}
TEST_F(IntrinsicTableTest, MismatchPointer) {
auto* i32 = create<sem::I32>();
auto* atomicI32 = create<sem::Atomic>(i32);
- auto result = table->Lookup(BuiltinType::kAtomicLoad, {atomicI32}, Source{});
+ auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{atomicI32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -237,12 +237,12 @@ TEST_F(IntrinsicTableTest, MismatchPointer) {
TEST_F(IntrinsicTableTest, MatchArray) {
auto* arr = create<sem::Array>(create<sem::U32>(), 0u, 4u, 4u, 4u, 4u);
auto* arr_ptr = create<sem::Pointer>(arr, ast::StorageClass::kStorage, ast::Access::kReadWrite);
- auto result = table->Lookup(BuiltinType::kArrayLength, {arr_ptr}, Source{});
+ auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{arr_ptr}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kArrayLength);
EXPECT_TRUE(result.sem->ReturnType()->Is<sem::U32>());
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
auto* param_type = result.sem->Parameters()[0]->Type();
ASSERT_TRUE(param_type->Is<sem::Pointer>());
EXPECT_TRUE(param_type->As<sem::Pointer>()->StoreType()->Is<sem::Array>());
@@ -250,7 +250,7 @@ TEST_F(IntrinsicTableTest, MatchArray) {
TEST_F(IntrinsicTableTest, MismatchArray) {
auto* f32 = create<sem::F32>();
- auto result = table->Lookup(BuiltinType::kArrayLength, {f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -261,12 +261,13 @@ TEST_F(IntrinsicTableTest, MatchSampler) {
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
- auto result = table->Lookup(BuiltinType::kTextureSample, {tex, sampler, vec2_f32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, sampler, vec2_f32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureSample);
EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), sampler);
@@ -279,7 +280,8 @@ TEST_F(IntrinsicTableTest, MismatchSampler) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
- auto result = table->Lookup(BuiltinType::kTextureSample, {tex, f32, vec2_f32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, f32, vec2_f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -290,12 +292,13 @@ TEST_F(IntrinsicTableTest, MatchSampledTexture) {
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
- auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32);
@@ -310,12 +313,13 @@ TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
- auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32);
@@ -329,12 +333,13 @@ TEST_F(IntrinsicTableTest, MatchDepthTexture) {
auto* i32 = create<sem::I32>();
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
- auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32);
@@ -348,12 +353,13 @@ TEST_F(IntrinsicTableTest, MatchDepthMultisampledTexture) {
auto* i32 = create<sem::I32>();
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* tex = create<sem::DepthMultisampledTexture>(ast::TextureDimension::k2d);
- auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32);
@@ -368,12 +374,12 @@ TEST_F(IntrinsicTableTest, MatchExternalTexture) {
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::ExternalTexture>();
- auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32}, Source{});
+ auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().size(), 2u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 2u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32);
@@ -389,12 +395,13 @@ TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
auto* tex = create<sem::StorageTexture>(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
ast::Access::kWrite, subtype);
- auto result = table->Lookup(BuiltinType::kTextureStore, {tex, vec2_i32, vec4_f32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kTextureStore, utils::Vector{tex, vec2_i32, vec4_f32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureStore);
EXPECT_TRUE(result.sem->ReturnType()->Is<sem::Void>());
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32);
@@ -407,7 +414,7 @@ TEST_F(IntrinsicTableTest, MismatchTexture) {
auto* f32 = create<sem::F32>();
auto* i32 = create<sem::I32>();
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
- auto result = table->Lookup(BuiltinType::kTextureLoad, {f32, vec2_i32}, Source{});
+ auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{f32, vec2_i32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -416,19 +423,21 @@ TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(
BuiltinType::kCos,
- {create<sem::Reference>(f32, ast::StorageClass::kFunction, ast::Access::kReadWrite)},
+ utils::Vector{
+ create<sem::Reference>(f32, ast::StorageClass::kFunction, ast::Access::kReadWrite),
+ },
Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCos);
EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
}
TEST_F(IntrinsicTableTest, MatchTemplateType) {
auto* f32 = create<sem::F32>();
- auto result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
@@ -441,7 +450,7 @@ TEST_F(IntrinsicTableTest, MatchTemplateType) {
TEST_F(IntrinsicTableTest, MismatchTemplateType) {
auto* f32 = create<sem::F32>();
auto* u32 = create<sem::U32>();
- auto result = table->Lookup(BuiltinType::kClamp, {f32, u32, f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, u32, f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -449,12 +458,13 @@ TEST_F(IntrinsicTableTest, MismatchTemplateType) {
TEST_F(IntrinsicTableTest, MatchOpenSizeVector) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
- auto result = table->Lookup(BuiltinType::kClamp, {vec2_f32, vec2_f32, vec2_f32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, vec2_f32, vec2_f32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
EXPECT_EQ(result.sem->ReturnType(), vec2_f32);
- ASSERT_EQ(result.sem->Parameters().size(), 3u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), vec2_f32);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_f32);
EXPECT_EQ(result.sem->Parameters()[2]->Type(), vec2_f32);
@@ -464,7 +474,8 @@ TEST_F(IntrinsicTableTest, MismatchOpenSizeVector) {
auto* f32 = create<sem::F32>();
auto* u32 = create<sem::U32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
- auto result = table->Lookup(BuiltinType::kClamp, {vec2_f32, u32, vec2_f32}, Source{});
+ auto result =
+ table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, u32, vec2_f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -473,12 +484,12 @@ TEST_F(IntrinsicTableTest, MatchOpenSizeMatrix) {
auto* f32 = create<sem::F32>();
auto* vec3_f32 = create<sem::Vector>(f32, 3u);
auto* mat3_f32 = create<sem::Matrix>(vec3_f32, 3u);
- auto result = table->Lookup(BuiltinType::kDeterminant, {mat3_f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3_f32}, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kDeterminant);
EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().size(), 1u);
+ ASSERT_EQ(result.sem->Parameters().Length(), 1u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), mat3_f32);
}
@@ -486,7 +497,7 @@ TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
auto* mat3x2_f32 = create<sem::Matrix>(vec2_f32, 3u);
- auto result = table->Lookup(BuiltinType::kDeterminant, {mat3x2_f32}, Source{});
+ auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3x2_f32}, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -495,7 +506,7 @@ TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
// None of the arguments match, so expect the overloads with 2 parameters to
// come first
auto* bool_ = create<sem::Bool>();
- table->Lookup(BuiltinType::kTextureDimensions, {bool_, bool_}, Source{});
+ table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{bool_, bool_}, Source{});
ASSERT_EQ(Diagnostics().str(),
R"(error: no matching call to textureDimensions(bool, bool)
@@ -533,7 +544,7 @@ TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
auto* bool_ = create<sem::Bool>();
- table->Lookup(BuiltinType::kTextureDimensions, {tex, bool_}, Source{});
+ table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{tex, bool_}, Source{});
ASSERT_EQ(Diagnostics().str(),
R"(error: no matching call to textureDimensions(texture_depth_2d, bool)
@@ -572,14 +583,15 @@ TEST_F(IntrinsicTableTest, SameOverloadReturnsSameBuiltinPointer) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2u);
auto* bool_ = create<sem::Bool>();
- auto a = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
+ auto a = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_}, Source{});
ASSERT_NE(a.sem, nullptr) << Diagnostics().str();
- auto b = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
+ auto b = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_}, Source{});
ASSERT_NE(b.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- auto c = table->Lookup(BuiltinType::kSelect, {vec2_f32, vec2_f32, bool_}, Source{});
+ auto c =
+ table->Lookup(BuiltinType::kSelect, utils::Vector{vec2_f32, vec2_f32, bool_}, Source{});
ASSERT_NE(c.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
@@ -604,8 +616,8 @@ TEST_F(IntrinsicTableTest, MismatchUnaryOp) {
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator - (bool)
2 candidate operators:
- operator - (T) -> T where: T is f32 or i32
- operator - (vecN<T>) -> vecN<T> where: T is f32 or i32
+ operator - (T) -> T where: T is abstract-float, abstract-int, f32, i32 or f16
+ operator - (vecN<T>) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32 or f16
)");
}
@@ -629,15 +641,15 @@ TEST_F(IntrinsicTableTest, MismatchBinaryOp) {
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator * (f32, bool)
9 candidate operators:
- operator * (T, T) -> T where: T is f32, i32 or u32
- operator * (vecN<T>, T) -> vecN<T> where: T is f32, i32 or u32
- operator * (T, vecN<T>) -> vecN<T> where: T is f32, i32 or u32
- operator * (f32, matNxM<f32>) -> matNxM<f32>
- operator * (vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32 or u32
- operator * (matNxM<f32>, f32) -> matNxM<f32>
- operator * (matCxR<f32>, vecC<f32>) -> vecR<f32>
- operator * (vecR<f32>, matCxR<f32>) -> vecC<f32>
- operator * (matKxR<f32>, matCxK<f32>) -> matCxR<f32>
+ operator * (T, T) -> T where: T is f32, i32, u32 or f16
+ operator * (vecN<T>, T) -> vecN<T> where: T is f32, i32, u32 or f16
+ operator * (T, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
+ operator * (T, matNxM<T>) -> matNxM<T> where: T is f32 or f16
+ operator * (matNxM<T>, T) -> matNxM<T> where: T is f32 or f16
+ operator * (vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
+ operator * (matCxR<T>, vecC<T>) -> vecR<T> where: T is f32 or f16
+ operator * (vecR<T>, matCxR<T>) -> vecC<T> where: T is f32 or f16
+ operator * (matKxR<T>, matCxK<T>) -> matCxR<T> where: T is f32 or f16
)");
}
@@ -661,90 +673,97 @@ TEST_F(IntrinsicTableTest, MismatchCompoundOp) {
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator *= (f32, bool)
9 candidate operators:
- operator *= (T, T) -> T where: T is f32, i32 or u32
- operator *= (vecN<T>, T) -> vecN<T> where: T is f32, i32 or u32
- operator *= (T, vecN<T>) -> vecN<T> where: T is f32, i32 or u32
- operator *= (f32, matNxM<f32>) -> matNxM<f32>
- operator *= (vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32 or u32
- operator *= (matNxM<f32>, f32) -> matNxM<f32>
- operator *= (matCxR<f32>, vecC<f32>) -> vecR<f32>
- operator *= (vecR<f32>, matCxR<f32>) -> vecC<f32>
- operator *= (matKxR<f32>, matCxK<f32>) -> matCxR<f32>
+ operator *= (T, T) -> T where: T is f32, i32, u32 or f16
+ operator *= (vecN<T>, T) -> vecN<T> where: T is f32, i32, u32 or f16
+ operator *= (T, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
+ operator *= (T, matNxM<T>) -> matNxM<T> where: T is f32 or f16
+ operator *= (matNxM<T>, T) -> matNxM<T> where: T is f32 or f16
+ operator *= (vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
+ operator *= (matCxR<T>, vecC<T>) -> vecR<T> where: T is f32 or f16
+ operator *= (vecR<T>, matCxR<T>) -> vecC<T> where: T is f32 or f16
+ operator *= (matKxR<T>, matCxK<T>) -> matCxR<T> where: T is f32 or f16
)");
}
TEST_F(IntrinsicTableTest, MatchTypeConstructorImplicit) {
auto* i32 = create<sem::I32>();
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
- auto* result =
- table->Lookup(CtorConvIntrinsic::kVec3, nullptr, {i32, i32, i32}, Source{{12, 34}});
- ASSERT_NE(result, nullptr);
- EXPECT_EQ(result->ReturnType(), vec3_i32);
- EXPECT_TRUE(result->Is<sem::TypeConstructor>());
- ASSERT_EQ(result->Parameters().size(), 3u);
- EXPECT_EQ(result->Parameters()[0]->Type(), i32);
- EXPECT_EQ(result->Parameters()[1]->Type(), i32);
- EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+ auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, utils::Vector{i32, i32, i32},
+ Source{{12, 34}});
+ ASSERT_NE(result.target, nullptr);
+ EXPECT_EQ(result.target->ReturnType(), vec3_i32);
+ EXPECT_TRUE(result.target->Is<sem::TypeConstructor>());
+ ASSERT_EQ(result.target->Parameters().Length(), 3u);
+ EXPECT_EQ(result.target->Parameters()[0]->Type(), i32);
+ EXPECT_EQ(result.target->Parameters()[1]->Type(), i32);
+ EXPECT_EQ(result.target->Parameters()[2]->Type(), i32);
+ EXPECT_NE(result.const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MatchTypeConstructorExplicit) {
auto* i32 = create<sem::I32>();
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
- auto* result = table->Lookup(CtorConvIntrinsic::kVec3, i32, {i32, i32, i32}, Source{{12, 34}});
- ASSERT_NE(result, nullptr);
- EXPECT_EQ(result->ReturnType(), vec3_i32);
- EXPECT_TRUE(result->Is<sem::TypeConstructor>());
- ASSERT_EQ(result->Parameters().size(), 3u);
- EXPECT_EQ(result->Parameters()[0]->Type(), i32);
- EXPECT_EQ(result->Parameters()[1]->Type(), i32);
- EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+ auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, utils::Vector{i32, i32, i32},
+ Source{{12, 34}});
+ ASSERT_NE(result.target, nullptr);
+ EXPECT_EQ(result.target->ReturnType(), vec3_i32);
+ EXPECT_TRUE(result.target->Is<sem::TypeConstructor>());
+ ASSERT_EQ(result.target->Parameters().Length(), 3u);
+ EXPECT_EQ(result.target->Parameters()[0]->Type(), i32);
+ EXPECT_EQ(result.target->Parameters()[1]->Type(), i32);
+ EXPECT_EQ(result.target->Parameters()[2]->Type(), i32);
+ EXPECT_NE(result.const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MismatchTypeConstructorImplicit) {
auto* i32 = create<sem::I32>();
auto* f32 = create<sem::F32>();
- auto* result =
- table->Lookup(CtorConvIntrinsic::kVec3, nullptr, {i32, f32, i32}, Source{{12, 34}});
- ASSERT_EQ(result, nullptr);
- EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching constructor for vec3(i32, f32, i32)
+ auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, utils::Vector{i32, f32, i32},
+ Source{{12, 34}});
+ ASSERT_EQ(result.target, nullptr);
+ EXPECT_EQ(Diagnostics().str(),
+ R"(12:34 error: no matching constructor for vec3(i32, f32, i32)
6 candidate constructors:
- vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(vec3<T>) -> vec3<T> where: T is f32, i32, u32 or bool
- vec3() -> vec3<T> where: T is f32, i32, u32 or bool
-
-4 candidate conversions:
- vec3(vec3<U>) -> vec3<f32> where: T is f32, U is i32, u32 or bool
- vec3(vec3<U>) -> vec3<i32> where: T is i32, U is f32, u32 or bool
- vec3(vec3<U>) -> vec3<u32> where: T is u32, U is f32, i32 or bool
- vec3(vec3<U>) -> vec3<bool> where: T is bool, U is f32, i32 or u32
+ vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
+ vec3() -> vec3<T> where: T is f32, f16, i32, u32 or bool
+
+5 candidate conversions:
+ vec3(vec3<U>) -> vec3<f32> where: T is f32, U is i32, f16, u32 or bool
+ vec3(vec3<U>) -> vec3<f16> where: T is f16, U is f32, i32, u32 or bool
+ vec3(vec3<U>) -> vec3<i32> where: T is i32, U is f32, f16, u32 or bool
+ vec3(vec3<U>) -> vec3<u32> where: T is u32, U is f32, f16, i32 or bool
+ vec3(vec3<U>) -> vec3<bool> where: T is bool, U is f32, f16, i32 or u32
)");
}
TEST_F(IntrinsicTableTest, MismatchTypeConstructorExplicit) {
auto* i32 = create<sem::I32>();
auto* f32 = create<sem::F32>();
- auto* result = table->Lookup(CtorConvIntrinsic::kVec3, i32, {i32, f32, i32}, Source{{12, 34}});
- ASSERT_EQ(result, nullptr);
+ auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, utils::Vector{i32, f32, i32},
+ Source{{12, 34}});
+ ASSERT_EQ(result.target, nullptr);
EXPECT_EQ(Diagnostics().str(),
R"(12:34 error: no matching constructor for vec3<i32>(i32, f32, i32)
6 candidate constructors:
- vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(vec3<T>) -> vec3<T> where: T is f32, i32, u32 or bool
- vec3() -> vec3<T> where: T is f32, i32, u32 or bool
-
-4 candidate conversions:
- vec3(vec3<U>) -> vec3<f32> where: T is f32, U is i32, u32 or bool
- vec3(vec3<U>) -> vec3<i32> where: T is i32, U is f32, u32 or bool
- vec3(vec3<U>) -> vec3<u32> where: T is u32, U is f32, i32 or bool
- vec3(vec3<U>) -> vec3<bool> where: T is bool, U is f32, i32 or u32
+ vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
+ vec3() -> vec3<T> where: T is f32, f16, i32, u32 or bool
+
+5 candidate conversions:
+ vec3(vec3<U>) -> vec3<f32> where: T is f32, U is i32, f16, u32 or bool
+ vec3(vec3<U>) -> vec3<f16> where: T is f16, U is f32, i32, u32 or bool
+ vec3(vec3<U>) -> vec3<i32> where: T is i32, U is f32, f16, u32 or bool
+ vec3(vec3<U>) -> vec3<u32> where: T is u32, U is f32, f16, i32 or bool
+ vec3(vec3<U>) -> vec3<bool> where: T is bool, U is f32, f16, i32 or u32
)");
}
@@ -753,41 +772,45 @@ TEST_F(IntrinsicTableTest, MatchTypeConversion) {
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
auto* f32 = create<sem::F32>();
auto* vec3_f32 = create<sem::Vector>(f32, 3u);
- auto* result = table->Lookup(CtorConvIntrinsic::kVec3, i32, {vec3_f32}, Source{{12, 34}});
- ASSERT_NE(result, nullptr);
- EXPECT_EQ(result->ReturnType(), vec3_i32);
- EXPECT_TRUE(result->Is<sem::TypeConversion>());
- ASSERT_EQ(result->Parameters().size(), 1u);
- EXPECT_EQ(result->Parameters()[0]->Type(), vec3_f32);
+ auto result =
+ table->Lookup(CtorConvIntrinsic::kVec3, i32, utils::Vector{vec3_f32}, Source{{12, 34}});
+ ASSERT_NE(result.target, nullptr);
+ EXPECT_EQ(result.target->ReturnType(), vec3_i32);
+ EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
+ ASSERT_EQ(result.target->Parameters().Length(), 1u);
+ EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_f32);
}
TEST_F(IntrinsicTableTest, MismatchTypeConversion) {
auto* arr = create<sem::Array>(create<sem::U32>(), 0u, 4u, 4u, 4u, 4u);
auto* f32 = create<sem::F32>();
- auto* result = table->Lookup(CtorConvIntrinsic::kVec3, f32, {arr}, Source{{12, 34}});
- ASSERT_EQ(result, nullptr);
+ auto result =
+ table->Lookup(CtorConvIntrinsic::kVec3, f32, utils::Vector{arr}, Source{{12, 34}});
+ ASSERT_EQ(result.target, nullptr);
EXPECT_EQ(Diagnostics().str(),
R"(12:34 error: no matching constructor for vec3<f32>(array<u32>)
6 candidate constructors:
- vec3(vec3<T>) -> vec3<T> where: T is f32, i32, u32 or bool
- vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3() -> vec3<T> where: T is f32, i32, u32 or bool
- vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, i32, u32 or bool
-
-4 candidate conversions:
- vec3(vec3<U>) -> vec3<f32> where: T is f32, U is i32, u32 or bool
- vec3(vec3<U>) -> vec3<i32> where: T is i32, U is f32, u32 or bool
- vec3(vec3<U>) -> vec3<u32> where: T is u32, U is f32, i32 or bool
- vec3(vec3<U>) -> vec3<bool> where: T is bool, U is f32, i32 or u32
+ vec3(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
+ vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3() -> vec3<T> where: T is f32, f16, i32, u32 or bool
+ vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+
+5 candidate conversions:
+ vec3(vec3<U>) -> vec3<f32> where: T is f32, U is i32, f16, u32 or bool
+ vec3(vec3<U>) -> vec3<f16> where: T is f16, U is f32, i32, u32 or bool
+ vec3(vec3<U>) -> vec3<i32> where: T is i32, U is f32, f16, u32 or bool
+ vec3(vec3<U>) -> vec3<u32> where: T is u32, U is f32, f16, i32 or bool
+ vec3(vec3<U>) -> vec3<bool> where: T is bool, U is f32, f16, i32 or u32
)");
}
TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605
auto* f32 = create<sem::F32>();
- std::vector<const sem::Type*> arg_tys(257, f32);
+ utils::Vector<const sem::Type*, 0> arg_tys;
+ arg_tys.Resize(257, f32);
auto result = table->Lookup(BuiltinType::kAbs, std::move(arg_tys), Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -800,18 +823,17 @@ TEST_F(IntrinsicTableTest, OverloadResolution) {
// The first should win overload resolution.
auto* ai = create<sem::AbstractInt>();
auto* i32 = create<sem::I32>();
- auto result = table->Lookup(CtorConvIntrinsic::kI32, nullptr, {ai}, Source{});
- ASSERT_NE(result, nullptr);
- EXPECT_EQ(result->ReturnType(), i32);
- EXPECT_EQ(result->Parameters().size(), 1u);
- EXPECT_EQ(result->Parameters()[0]->Type(), i32);
+ auto result = table->Lookup(CtorConvIntrinsic::kI32, nullptr, utils::Vector{ai}, Source{});
+ ASSERT_NE(result.target, nullptr);
+ EXPECT_EQ(result.target->ReturnType(), i32);
+ EXPECT_EQ(result.target->Parameters().Length(), 1u);
+ EXPECT_EQ(result.target->Parameters()[0]->Type(), i32);
}
////////////////////////////////////////////////////////////////////////////////
// AbstractBinaryTests
////////////////////////////////////////////////////////////////////////////////
namespace AbstractBinaryTests {
-
struct Case {
template <typename RESULT,
typename PARAM_LHS,
@@ -864,20 +886,21 @@ INSTANTIATE_TEST_SUITE_P(AFloat_AInt,
IntrinsicTableAbstractBinaryTest,
testing::Values( // clang-format off
// result | param lhs | param rhs | arg lhs | arg rhs
-Case::Create<f32, f32, f32, AFloat, AFloat>(),
-Case::Create<f32, f32, f32, AFloat, AInt>(),
-Case::Create<f32, f32, f32, AInt, AFloat>(),
-Case::Create<i32, i32, i32, AInt, AInt>()
+Case::Create<AFloat, AFloat, AFloat, AFloat, AFloat>(),
+Case::Create<AFloat, AFloat, AFloat, AFloat, AInt>(),
+Case::Create<AFloat, AFloat, AFloat, AInt, AFloat>(),
+Case::Create<AInt, AInt, AInt, AInt, AInt>()
)); // clang-format on
-INSTANTIATE_TEST_SUITE_P(VecAFloat_VecAInt,
- IntrinsicTableAbstractBinaryTest,
- testing::Values( // clang-format off
+INSTANTIATE_TEST_SUITE_P(
+ VecAFloat_VecAInt,
+ IntrinsicTableAbstractBinaryTest,
+ testing::Values( // clang-format off
// result | param lhs | param rhs | arg lhs | arg rhs
-Case::Create<f32V, f32V, f32V, AFloatV, AFloatV>(),
-Case::Create<f32V, f32V, f32V, AFloatV, AIntV>(),
-Case::Create<f32V, f32V, f32V, AIntV, AFloatV>(),
-Case::Create<i32V, i32V, i32V, AIntV, AIntV>()
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AFloatV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AIntV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AIntV, AFloatV>(),
+Case::Create<AIntV, AIntV, AIntV, AIntV, AIntV>()
)); // clang-format on
INSTANTIATE_TEST_SUITE_P(AFloat_f32,
@@ -986,7 +1009,6 @@ Case::Create<u32V, u32V, u32V, u32V, AIntV>()
// AbstractTernaryTests
////////////////////////////////////////////////////////////////////////////////
namespace AbstractTernaryTests {
-
struct Case {
template <typename RESULT,
typename PARAM_A,
@@ -1025,7 +1047,8 @@ TEST_P(IntrinsicTableAbstractTernaryTest, MatchClamp) {
auto* arg_a = GetParam().arg_a(*this);
auto* arg_b = GetParam().arg_b(*this);
auto* arg_c = GetParam().arg_c(*this);
- auto builtin = table->Lookup(sem::BuiltinType::kClamp, {arg_a, arg_b, arg_c}, Source{{12, 34}});
+ auto builtin = table->Lookup(sem::BuiltinType::kClamp, utils::Vector{arg_a, arg_b, arg_c},
+ Source{{12, 34}});
bool matched = builtin.sem != nullptr;
bool expected_match = GetParam().expected_match;
@@ -1053,14 +1076,14 @@ INSTANTIATE_TEST_SUITE_P(
IntrinsicTableAbstractTernaryTest,
testing::Values( // clang-format off
// result | param a | param b | param c | arg a | arg b | arg c
-Case::Create<f32, f32, f32, f32, AFloat, AFloat, AFloat>(),
-Case::Create<f32, f32, f32, f32, AFloat, AFloat, AInt>(),
-Case::Create<f32, f32, f32, f32, AFloat, AInt, AFloat>(),
-Case::Create<f32, f32, f32, f32, AFloat, AInt, AInt>(),
-Case::Create<f32, f32, f32, f32, AInt, AFloat, AFloat>(),
-Case::Create<f32, f32, f32, f32, AInt, AFloat, AInt>(),
-Case::Create<f32, f32, f32, f32, AInt, AInt, AFloat>(),
-Case::Create<i32, i32, i32, i32, AInt, AInt, AInt>()
+Case::Create<AFloat, AFloat, AFloat, AFloat, AFloat, AFloat, AFloat>(),
+Case::Create<AFloat, AFloat, AFloat, AFloat, AFloat, AFloat, AInt>(),
+Case::Create<AFloat, AFloat, AFloat, AFloat, AFloat, AInt, AFloat>(),
+Case::Create<AFloat, AFloat, AFloat, AFloat, AFloat, AInt, AInt>(),
+Case::Create<AFloat, AFloat, AFloat, AFloat, AInt, AFloat, AFloat>(),
+Case::Create<AFloat, AFloat, AFloat, AFloat, AInt, AFloat, AInt>(),
+Case::Create<AFloat, AFloat, AFloat, AFloat, AInt, AInt, AFloat>(),
+Case::Create<AInt, AInt, AInt, AInt, AInt, AInt, AInt>()
// clang-format on
));
@@ -1069,14 +1092,14 @@ INSTANTIATE_TEST_SUITE_P(
IntrinsicTableAbstractTernaryTest,
testing::Values( // clang-format off
// result | param a | param b | param c | arg a | arg b | arg c
-Case::Create<f32V, f32V, f32V, f32V, AFloatV, AFloatV, AFloatV>(),
-Case::Create<f32V, f32V, f32V, f32V, AFloatV, AFloatV, AIntV>(),
-Case::Create<f32V, f32V, f32V, f32V, AFloatV, AIntV, AFloatV>(),
-Case::Create<f32V, f32V, f32V, f32V, AFloatV, AIntV, AIntV>(),
-Case::Create<f32V, f32V, f32V, f32V, AIntV, AFloatV, AFloatV>(),
-Case::Create<f32V, f32V, f32V, f32V, AIntV, AFloatV, AIntV>(),
-Case::Create<f32V, f32V, f32V, f32V, AIntV, AIntV, AFloatV>(),
-Case::Create<i32V, i32V, i32V, i32V, AIntV, AIntV, AIntV>()
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AFloatV, AFloatV, AFloatV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AFloatV, AFloatV, AIntV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AFloatV, AIntV, AFloatV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AFloatV, AIntV, AIntV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AIntV, AFloatV, AFloatV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AIntV, AFloatV, AIntV>(),
+Case::Create<AFloatV, AFloatV, AFloatV, AFloatV, AIntV, AIntV, AFloatV>(),
+Case::Create<AIntV, AIntV, AIntV, AIntV, AIntV, AIntV, AIntV>()
// clang-format on
));
@@ -1248,6 +1271,68 @@ Case::Create<u32V, u32V, u32V, u32V, u32V, u32V, AIntV>(
// clang-format on
));
+struct IntrinsicTableAbstractTernaryTest_NonConstEval : public ResolverTestWithParam<Case> {
+ std::unique_ptr<IntrinsicTable> table = IntrinsicTable::Create(*this);
+};
+
+TEST_P(IntrinsicTableAbstractTernaryTest_NonConstEval, MatchMix) {
+ auto* arg_a = GetParam().arg_a(*this);
+ auto* arg_b = GetParam().arg_b(*this);
+ auto* arg_c = GetParam().arg_c(*this);
+ auto builtin =
+ table->Lookup(sem::BuiltinType::kMix, utils::Vector{arg_a, arg_b, arg_c}, Source{{12, 34}});
+
+ bool matched = builtin.sem != nullptr;
+ bool expected_match = GetParam().expected_match;
+ EXPECT_EQ(matched, expected_match) << Diagnostics().str();
+
+ auto* result = builtin.sem ? builtin.sem->ReturnType() : nullptr;
+ auto* expected_result = GetParam().expected_result(*this);
+ EXPECT_TYPE(result, expected_result);
+
+ auto* param_a = builtin.sem ? builtin.sem->Parameters()[0]->Type() : nullptr;
+ auto* expected_param_a = GetParam().expected_param_a(*this);
+ EXPECT_TYPE(param_a, expected_param_a);
+
+ auto* param_b = builtin.sem ? builtin.sem->Parameters()[1]->Type() : nullptr;
+ auto* expected_param_b = GetParam().expected_param_b(*this);
+ EXPECT_TYPE(param_b, expected_param_b);
+
+ auto* param_c = builtin.sem ? builtin.sem->Parameters()[2]->Type() : nullptr;
+ auto* expected_param_c = GetParam().expected_param_c(*this);
+ EXPECT_TYPE(param_c, expected_param_c);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AFloat_f32,
+ IntrinsicTableAbstractTernaryTest_NonConstEval,
+ testing::Values( // clang-format off
+ // result | param a | param b | param c | arg a | arg b | arg c
+ Case::Create<f32, f32, f32, f32, AFloat, AFloat, AFloat>(),
+ Case::Create<f32, f32, f32, f32, AFloat, AFloat, f32>(),
+ Case::Create<f32, f32, f32, f32, AFloat, f32, AFloat>(),
+ Case::Create<f32, f32, f32, f32, AFloat, f32, f32>(),
+ Case::Create<f32, f32, f32, f32, f32, AFloat, AFloat>(),
+ Case::Create<f32, f32, f32, f32, f32, AFloat, f32>(),
+ Case::Create<f32, f32, f32, f32, f32, f32, AFloat>()
+ // clang-format on
+ ));
+
+INSTANTIATE_TEST_SUITE_P(
+ VecAFloat_Vecf32,
+ IntrinsicTableAbstractTernaryTest_NonConstEval,
+ testing::Values( // clang-format off
+ // result | param a | param b | param c | arg a | arg b | arg c
+ Case::Create<f32V, f32V, f32V, f32V, AFloatV, AFloatV, AFloatV>(),
+ Case::Create<f32V, f32V, f32V, f32V, AFloatV, AFloatV, f32V>(),
+ Case::Create<f32V, f32V, f32V, f32V, AFloatV, f32V, AFloatV>(),
+ Case::Create<f32V, f32V, f32V, f32V, AFloatV, f32V, f32V>(),
+ Case::Create<f32V, f32V, f32V, f32V, f32V, AFloatV, AFloatV>(),
+ Case::Create<f32V, f32V, f32V, f32V, f32V, AFloatV, f32V>(),
+ Case::Create<f32V, f32V, f32V, f32V, f32V, f32V, AFloatV> ()
+ // clang-format on
+ ));
+
} // namespace AbstractTernaryTests
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/resolver/is_host_shareable_test.cc b/chromium/third_party/dawn/src/tint/resolver/is_host_shareable_test.cc
index a1679033066..0ac335265bf 100644
--- a/chromium/third_party/dawn/src/tint/resolver/is_host_shareable_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/is_host_shareable_test.cc
@@ -35,6 +35,7 @@ TEST_F(ResolverIsHostShareable, NumericScalar) {
EXPECT_TRUE(r()->IsHostShareable(create<sem::I32>()));
EXPECT_TRUE(r()->IsHostShareable(create<sem::U32>()));
EXPECT_TRUE(r()->IsHostShareable(create<sem::F32>()));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::F16>()));
}
TEST_F(ResolverIsHostShareable, NumericVector) {
@@ -47,6 +48,9 @@ TEST_F(ResolverIsHostShareable, NumericVector) {
EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 2u)));
EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 3u)));
EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 4u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F16>(), 2u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F16>(), 3u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F16>(), 4u)));
}
TEST_F(ResolverIsHostShareable, BoolVector) {
@@ -62,19 +66,32 @@ TEST_F(ResolverIsHostShareable, BoolVector) {
}
TEST_F(ResolverIsHostShareable, Matrix) {
- auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
- auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
- auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
-
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 2u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 3u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 4u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 2u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 3u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 4u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 2u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 3u)));
- EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 4u)));
+ auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2u);
+ auto* vec3_f32 = create<sem::Vector>(create<sem::F32>(), 3u);
+ auto* vec4_f32 = create<sem::Vector>(create<sem::F32>(), 4u);
+ auto* vec2_f16 = create<sem::Vector>(create<sem::F16>(), 2u);
+ auto* vec3_f16 = create<sem::Vector>(create<sem::F16>(), 3u);
+ auto* vec4_f16 = create<sem::Vector>(create<sem::F16>(), 4u);
+
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2_f32, 2u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2_f32, 3u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2_f32, 4u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3_f32, 2u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3_f32, 3u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3_f32, 4u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4_f32, 2u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4_f32, 3u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4_f32, 4u)));
+
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2_f16, 2u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2_f16, 3u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2_f16, 4u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3_f16, 2u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3_f16, 3u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3_f16, 4u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4_f16, 2u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4_f16, 3u)));
+ EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4_f16, 4u)));
}
TEST_F(ResolverIsHostShareable, Pointer) {
diff --git a/chromium/third_party/dawn/src/tint/resolver/is_storeable_test.cc b/chromium/third_party/dawn/src/tint/resolver/is_storeable_test.cc
index 2d37d8b6e31..0423f72510c 100644
--- a/chromium/third_party/dawn/src/tint/resolver/is_storeable_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/is_storeable_test.cc
@@ -32,6 +32,7 @@ TEST_F(ResolverIsStorableTest, Scalar) {
EXPECT_TRUE(r()->IsStorable(create<sem::I32>()));
EXPECT_TRUE(r()->IsStorable(create<sem::U32>()));
EXPECT_TRUE(r()->IsStorable(create<sem::F32>()));
+ EXPECT_TRUE(r()->IsStorable(create<sem::F16>()));
}
TEST_F(ResolverIsStorableTest, Vector) {
@@ -44,21 +45,36 @@ TEST_F(ResolverIsStorableTest, Vector) {
EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 2u)));
EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 3u)));
EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 4u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F16>(), 2u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F16>(), 3u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F16>(), 4u)));
}
TEST_F(ResolverIsStorableTest, Matrix) {
- auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
- auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
- auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 2u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 3u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 4u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 2u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 3u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 4u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 2u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 3u)));
- EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 4u)));
+ auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2u);
+ auto* vec3_f32 = create<sem::Vector>(create<sem::F32>(), 3u);
+ auto* vec4_f32 = create<sem::Vector>(create<sem::F32>(), 4u);
+ auto* vec2_f16 = create<sem::Vector>(create<sem::F16>(), 2u);
+ auto* vec3_f16 = create<sem::Vector>(create<sem::F16>(), 3u);
+ auto* vec4_f16 = create<sem::Vector>(create<sem::F16>(), 4u);
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2_f32, 2u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2_f32, 3u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2_f32, 4u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3_f32, 2u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3_f32, 3u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3_f32, 4u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4_f32, 2u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4_f32, 3u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4_f32, 4u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2_f16, 2u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2_f16, 3u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2_f16, 4u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3_f16, 2u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3_f16, 3u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3_f16, 4u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4_f16, 2u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4_f16, 3u)));
+ EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4_f16, 4u)));
}
TEST_F(ResolverIsStorableTest, Pointer) {
@@ -83,7 +99,7 @@ TEST_F(ResolverIsStorableTest, ArrayUnsizedOfStorable) {
}
TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
- Structure("S", {
+ Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
@@ -92,7 +108,7 @@ TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
}
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
- Structure("S", {
+ Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
});
@@ -104,11 +120,11 @@ TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
}
TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
- auto* storable = Structure("Storable", {
+ auto* storable = Structure("Storable", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Structure("S", {
+ Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.Of(storable)),
});
@@ -118,11 +134,11 @@ TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
auto* non_storable =
- Structure("nonstorable", {
+ Structure("nonstorable", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
});
- Structure("S", {
+ Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.Of(non_storable)),
});
diff --git a/chromium/third_party/dawn/src/tint/resolver/materialize_test.cc b/chromium/third_party/dawn/src/tint/resolver/materialize_test.cc
index 22d5606321c..26f109fd417 100644
--- a/chromium/third_party/dawn/src/tint/resolver/materialize_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/materialize_test.cc
@@ -27,24 +27,28 @@ namespace {
using AFloatV = builder::vec<3, AFloat>;
using AFloatM = builder::mat<3, 2, AFloat>;
+using AFloatA = builder::array<3, AFloat>;
using AIntV = builder::vec<3, AInt>;
+using AIntA = builder::array<3, AInt>;
using f32V = builder::vec<3, f32>;
using f16V = builder::vec<3, f16>;
using i32V = builder::vec<3, i32>;
using u32V = builder::vec<3, u32>;
using f32M = builder::mat<3, 2, f32>;
+using f16M = builder::mat<3, 2, f16>;
+using f32A = builder::array<3, f32>;
+using f16A = builder::array<3, f16>;
+using i32A = builder::array<3, i32>;
+using u32A = builder::array<3, u32>;
-constexpr double kHighestU32 = static_cast<double>(u32::kHighest);
-constexpr double kLowestU32 = static_cast<double>(u32::kLowest);
-constexpr double kHighestI32 = static_cast<double>(i32::kHighest);
-constexpr double kLowestI32 = static_cast<double>(i32::kLowest);
-constexpr double kHighestF32 = static_cast<double>(f32::kHighest);
-constexpr double kLowestF32 = static_cast<double>(f32::kLowest);
constexpr double kTooBigF32 = static_cast<double>(3.5e+38);
+constexpr double kTooBigF16 = static_cast<double>(6.6e+4);
constexpr double kPiF64 = 3.141592653589793;
constexpr double kPiF32 = 3.1415927410125732; // kPiF64 quantized to f32
+constexpr double kPiF16 = 3.140625; // kPiF64 quantized to f16
constexpr double kSubnormalF32 = 0x1.0p-128;
+constexpr double kSubnormalF16 = 0x1.0p-16;
enum class Expectation {
kMaterialize,
@@ -67,12 +71,69 @@ static std::ostream& operator<<(std::ostream& o, Expectation m) {
return o << "<unknown>";
}
+template <typename CASE>
+class MaterializeTest : public resolver::ResolverTestWithParam<CASE> {
+ protected:
+ using ProgramBuilder::FriendlyName;
+
+ void CheckTypesAndValues(const sem::Expression* expr,
+ const tint::sem::Type* expected_sem_ty,
+ const std::variant<AInt, AFloat>& expected_value) {
+ std::visit([&](auto v) { CheckTypesAndValuesImpl(expr, expected_sem_ty, v); },
+ expected_value);
+ }
+
+ private:
+ template <typename T>
+ void CheckTypesAndValuesImpl(const sem::Expression* expr,
+ const tint::sem::Type* expected_sem_ty,
+ T expected_value) {
+ EXPECT_TYPE(expr->Type(), expected_sem_ty);
+
+ auto* value = expr->ConstantValue();
+ ASSERT_NE(value, nullptr);
+ EXPECT_TYPE(expr->Type(), value->Type());
+
+ tint::Switch(
+ expected_sem_ty, //
+ [&](const sem::Vector* v) {
+ for (uint32_t i = 0; i < v->Width(); i++) {
+ auto* el = value->Index(i);
+ ASSERT_NE(el, nullptr);
+ EXPECT_TYPE(el->Type(), v->type());
+ EXPECT_EQ(std::get<T>(el->Value()), expected_value);
+ }
+ },
+ [&](const sem::Matrix* m) {
+ for (uint32_t c = 0; c < m->columns(); c++) {
+ auto* column = value->Index(c);
+ ASSERT_NE(column, nullptr);
+ EXPECT_TYPE(column->Type(), m->ColumnType());
+ for (uint32_t r = 0; r < m->rows(); r++) {
+ auto* el = column->Index(r);
+ ASSERT_NE(el, nullptr);
+ EXPECT_TYPE(el->Type(), m->type());
+ EXPECT_EQ(std::get<T>(el->Value()), expected_value);
+ }
+ }
+ },
+ [&](const sem::Array* a) {
+ for (uint32_t i = 0; i < a->Count(); i++) {
+ auto* el = value->Index(i);
+ ASSERT_NE(el, nullptr);
+ EXPECT_TYPE(el->Type(), a->ElemType());
+ EXPECT_EQ(std::get<T>(el->Value()), expected_value);
+ }
+ },
+ [&](Default) { EXPECT_EQ(std::get<T>(value->Value()), expected_value); });
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// MaterializeAbstractNumericToConcreteType
// Tests that an abstract-numeric will materialize to the expected concrete type
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace materialize_abstract_numeric_to_concrete_type {
-
// How should the materialization occur?
enum class Method {
// var a : target_type = abstract_expr;
@@ -145,7 +206,10 @@ enum class Method {
// @workgroup_size(target_expr, abstract_expr, 123)
// @compute
// fn f() {}
- kWorkgroupSize
+ kWorkgroupSize,
+
+ // abstract_expr[runtime-index]
+ kRuntimeIndex,
};
static std::ostream& operator<<(std::ostream& o, Method m) {
@@ -180,6 +244,8 @@ static std::ostream& operator<<(std::ostream& o, Method m) {
return o << "switch-case-with-abstract";
case Method::kWorkgroupSize:
return o << "workgroup-size";
+ case Method::kRuntimeIndex:
+ return o << "runtime-index";
}
return o << "<unknown>";
}
@@ -241,11 +307,10 @@ static std::ostream& operator<<(std::ostream& o, const Data& c) {
}
using MaterializeAbstractNumericToConcreteType =
- resolver::ResolverTestWithParam<std::tuple<Expectation, Method, Data>>;
+ MaterializeTest<std::tuple<Expectation, Method, Data>>;
TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
- // Once F16 is properly supported, we'll need to enable this:
- // Enable(ast::Extension::kF16);
+ Enable(ast::Extension::kF16);
const auto& param = GetParam();
const auto& expectation = std::get<0>(param);
@@ -269,20 +334,20 @@ TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
WrapInFunction(Assign(Phony(), abstract_expr));
break;
case Method::kFnArg:
- Func("F", {Param("P", target_ty())}, ty.void_(), {});
+ Func("F", utils::Vector{Param("P", target_ty())}, ty.void_(), utils::Empty);
WrapInFunction(CallStmt(Call("F", abstract_expr)));
break;
case Method::kBuiltinArg:
WrapInFunction(CallStmt(Call("min", target_expr(), abstract_expr)));
break;
case Method::kReturn:
- Func("F", {}, target_ty(), {Return(abstract_expr)});
+ Func("F", utils::Empty, target_ty(), utils::Vector{Return(abstract_expr)});
break;
case Method::kArray:
WrapInFunction(Construct(ty.array(target_ty(), 1_i), abstract_expr));
break;
case Method::kStruct:
- Structure("S", {Member("v", target_ty())});
+ Structure("S", utils::Vector{Member("v", target_ty())});
WrapInFunction(Construct(ty.type_name("S"), abstract_expr));
break;
case Method::kBinaryOp:
@@ -311,36 +376,22 @@ TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
DefaultCase()));
break;
case Method::kWorkgroupSize:
- Func("f", {}, ty.void_(), {},
- {WorkgroupSize(target_expr(), abstract_expr, Expr(123_a)),
- Stage(ast::PipelineStage::kCompute)});
+ Func("f", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{WorkgroupSize(target_expr(), abstract_expr, Expr(123_a)),
+ Stage(ast::PipelineStage::kCompute)});
+ break;
+ case Method::kRuntimeIndex:
+ auto* runtime_index = Var("runtime_index", nullptr, Expr(1_i));
+ WrapInFunction(runtime_index, IndexAccessor(abstract_expr, runtime_index));
break;
}
- auto check_types_and_values = [&](const sem::Expression* expr) {
- auto* target_sem_ty = data.target_sem_ty(*this);
-
- EXPECT_TYPE(expr->Type(), target_sem_ty);
- EXPECT_TYPE(expr->ConstantValue().Type(), target_sem_ty);
-
- uint32_t num_elems = 0;
- const sem::Type* target_sem_el_ty = sem::Type::ElementOf(target_sem_ty, &num_elems);
- EXPECT_TYPE(expr->ConstantValue().ElementType(), target_sem_el_ty);
- expr->ConstantValue().WithElements([&](auto&& vec) {
- using VEC_TY = std::decay_t<decltype(vec)>;
- using EL_TY = typename VEC_TY::value_type;
- ASSERT_TRUE(std::holds_alternative<EL_TY>(data.materialized_value));
- VEC_TY expected(num_elems, std::get<EL_TY>(data.materialized_value));
- EXPECT_EQ(vec, expected);
- });
- };
-
switch (expectation) {
case Expectation::kMaterialize: {
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* materialize = Sem().Get<sem::Materialize>(abstract_expr);
ASSERT_NE(materialize, nullptr);
- check_types_and_values(materialize);
+ CheckTypesAndValues(materialize, data.target_sem_ty(*this), data.materialized_value);
break;
}
case Expectation::kNoMaterialize: {
@@ -348,7 +399,7 @@ TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
auto* sem = Sem().Get(abstract_expr);
ASSERT_NE(sem, nullptr);
EXPECT_FALSE(sem->Is<sem::Materialize>());
- check_types_and_values(sem);
+ CheckTypesAndValues(sem, data.target_sem_ty(*this), data.materialized_value);
break;
}
case Expectation::kInvalidConversion: {
@@ -397,6 +448,12 @@ constexpr Method kMatrixMethods[] = {
Method::kReturn, Method::kArray, Method::kStruct, Method::kBinaryOp,
};
+/// Methods that support array materialization
+constexpr Method kArrayMethods[] = {
+ Method::kLet, Method::kVar, Method::kAssign, Method::kFnArg,
+ Method::kReturn, Method::kArray, Method::kStruct,
+};
+
/// Methods that support materialization for switch cases
constexpr Method kSwitchMethods[] = {
Method::kSwitchCond,
@@ -407,94 +464,207 @@ constexpr Method kSwitchMethods[] = {
/// Methods that do not materialize
constexpr Method kNoMaterializeMethods[] = {
- Method::kPhonyAssign,
- // TODO(crbug.com/tint/1504): Enable once we have abstract overloads of builtins / binary ops:
- // Method::kBuiltinArg, Method::kBinaryOp,
+ Method::kPhonyAssign, //
+ Method::kBinaryOp,
+ // TODO(crbug.com/tint/1504): Enable once "min" supports const evaluation
+ // Method::kBuiltinArg,
};
INSTANTIATE_TEST_SUITE_P(
MaterializeScalar,
MaterializeAbstractNumericToConcreteType,
- testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kScalarMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, 0.0), //
- Types<i32, AInt>(1_a, 1.0), //
- Types<i32, AInt>(-1_a, -1.0), //
- Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
- Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
- Types<u32, AInt>(0_a, 0.0), //
- Types<u32, AInt>(1_a, 1.0), //
- Types<u32, AInt>(AInt(kHighestU32), kHighestU32), //
- Types<u32, AInt>(AInt(kLowestU32), kLowestU32), //
- Types<f32, AFloat>(0.0_a, 0.0), //
- Types<f32, AFloat>(AFloat(kHighestF32), kHighestF32), //
- Types<f32, AFloat>(AFloat(kLowestF32), kLowestF32), //
- Types<f32, AFloat>(AFloat(kPiF32), kPiF64), //
- Types<f32, AFloat>(AFloat(kSubnormalF32), kSubnormalF32), //
- Types<f32, AFloat>(AFloat(-kSubnormalF32), -kSubnormalF32), //
- /* Types<f16, AFloat>(1.0_a), */ //
- /* Types<f16, AFloat>(1.0_a), */ //
- })));
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kScalarMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32, AInt>(0_a, 0.0), //
+ Types<i32, AInt>(1_a, 1.0), //
+ Types<i32, AInt>(-1_a, -1.0), //
+ Types<i32, AInt>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32, AInt>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<u32, AInt>(0_a, 0.0), //
+ Types<u32, AInt>(1_a, 1.0), //
+ Types<u32, AInt>(AInt(u32::Highest()), u32::Highest()), //
+ Types<u32, AInt>(AInt(u32::Lowest()), u32::Lowest()), //
+ Types<f32, AFloat>(0.0_a, 0.0), //
+ Types<f32, AFloat>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32, AFloat>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32, AFloat>(AFloat(kPiF32), kPiF64), //
+ Types<f32, AFloat>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32, AFloat>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ Types<f16, AFloat>(0.0_a, 0.0), //
+ Types<f16, AFloat>(1.0_a, 1.0), //
+ Types<f16, AFloat>(AFloat(f16::Highest()), static_cast<double>(f16::Highest())), //
+ Types<f16, AFloat>(AFloat(f16::Lowest()), static_cast<double>(f16::Lowest())), //
+ Types<f16, AFloat>(AFloat(kPiF16), kPiF64), //
+ Types<f16, AFloat>(AFloat(kSubnormalF16), kSubnormalF16), //
+ Types<f16, AFloat>(AFloat(-kSubnormalF16), -kSubnormalF16), //
+ })));
INSTANTIATE_TEST_SUITE_P(
MaterializeVector,
MaterializeAbstractNumericToConcreteType,
- testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kVectorMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32V, AIntV>(0_a, 0.0), //
- Types<i32V, AIntV>(1_a, 1.0), //
- Types<i32V, AIntV>(-1_a, -1.0), //
- Types<i32V, AIntV>(AInt(kHighestI32), kHighestI32), //
- Types<i32V, AIntV>(AInt(kLowestI32), kLowestI32), //
- Types<u32V, AIntV>(0_a, 0.0), //
- Types<u32V, AIntV>(1_a, 1.0), //
- Types<u32V, AIntV>(AInt(kHighestU32), kHighestU32), //
- Types<u32V, AIntV>(AInt(kLowestU32), kLowestU32), //
- Types<f32V, AFloatV>(0.0_a, 0.0), //
- Types<f32V, AFloatV>(1.0_a, 1.0), //
- Types<f32V, AFloatV>(-1.0_a, -1.0), //
- Types<f32V, AFloatV>(AFloat(kHighestF32), kHighestF32), //
- Types<f32V, AFloatV>(AFloat(kLowestF32), kLowestF32), //
- Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
- Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
- Types<f32V, AFloatV>(AFloat(-kSubnormalF32), -kSubnormalF32), //
- /* Types<f16V, AFloatV>(1.0_a), */ //
- /* Types<f16V, AFloatV>(1.0_a), */ //
- })));
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kVectorMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32V, AIntV>(0_a, 0.0), //
+ Types<i32V, AIntV>(1_a, 1.0), //
+ Types<i32V, AIntV>(-1_a, -1.0), //
+ Types<i32V, AIntV>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32V, AIntV>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<u32V, AIntV>(0_a, 0.0), //
+ Types<u32V, AIntV>(1_a, 1.0), //
+ Types<u32V, AIntV>(AInt(u32::Highest()), u32::Highest()), //
+ Types<u32V, AIntV>(AInt(u32::Lowest()), u32::Lowest()), //
+ Types<f32V, AFloatV>(0.0_a, 0.0), //
+ Types<f32V, AFloatV>(1.0_a, 1.0), //
+ Types<f32V, AFloatV>(-1.0_a, -1.0), //
+ Types<f32V, AFloatV>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32V, AFloatV>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
+ Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32V, AFloatV>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ Types<f16V, AFloatV>(0.0_a, 0.0), //
+ Types<f16V, AFloatV>(1.0_a, 1.0), //
+ Types<f16V, AFloatV>(-1.0_a, -1.0), //
+ Types<f16V, AFloatV>(AFloat(f16::Highest()), static_cast<double>(f16::Highest())), //
+ Types<f16V, AFloatV>(AFloat(f16::Lowest()), static_cast<double>(f16::Lowest())), //
+ Types<f16V, AFloatV>(AFloat(kPiF16), kPiF64), //
+ Types<f16V, AFloatV>(AFloat(kSubnormalF16), kSubnormalF16), //
+ Types<f16V, AFloatV>(AFloat(-kSubnormalF16), -kSubnormalF16), //
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
+ MaterializeVectorRuntimeIndex,
+ MaterializeAbstractNumericToConcreteType,
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::Values(Method::kRuntimeIndex),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32V, AIntV>(0_a, 0.0), //
+ Types<i32V, AIntV>(1_a, 1.0), //
+ Types<i32V, AIntV>(-1_a, -1.0), //
+ Types<i32V, AIntV>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32V, AIntV>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<f32V, AFloatV>(0.0_a, 0.0), //
+ Types<f32V, AFloatV>(1.0_a, 1.0), //
+ Types<f32V, AFloatV>(-1.0_a, -1.0), //
+ Types<f32V, AFloatV>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32V, AFloatV>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
+ Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32V, AFloatV>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ })));
INSTANTIATE_TEST_SUITE_P(
MaterializeMatrix,
MaterializeAbstractNumericToConcreteType,
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kMatrixMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<f32M, AFloatM>(0.0_a, 0.0), //
+ Types<f32M, AFloatM>(1.0_a, 1.0), //
+ Types<f32M, AFloatM>(-1.0_a, -1.0), //
+ Types<f32M, AFloatM>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32M, AFloatM>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
+ Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32M, AFloatM>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ Types<f16M, AFloatM>(0.0_a, 0.0), //
+ Types<f16M, AFloatM>(1.0_a, 1.0), //
+ Types<f16M, AFloatM>(-1.0_a, -1.0), //
+ Types<f16M, AFloatM>(AFloat(f16::Highest()), static_cast<double>(f16::Highest())), //
+ Types<f16M, AFloatM>(AFloat(f16::Lowest()), static_cast<double>(f16::Lowest())), //
+ Types<f16M, AFloatM>(AFloat(kPiF16), kPiF64), //
+ Types<f16M, AFloatM>(AFloat(kSubnormalF16), kSubnormalF16), //
+ Types<f16M, AFloatM>(AFloat(-kSubnormalF16), -kSubnormalF16), //
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
+ MaterializeMatrixRuntimeIndex,
+ MaterializeAbstractNumericToConcreteType,
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::Values(Method::kRuntimeIndex),
+ testing::ValuesIn(std::vector<Data>{
+ Types<f32M, AFloatM>(0.0_a, 0.0), //
+ Types<f32M, AFloatM>(1.0_a, 1.0), //
+ Types<f32M, AFloatM>(-1.0_a, -1.0), //
+ Types<f32M, AFloatM>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32M, AFloatM>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
+ Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32M, AFloatM>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
+ MaterializeSwitch,
+ MaterializeAbstractNumericToConcreteType,
testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kMatrixMethods),
+ testing::ValuesIn(kSwitchMethods),
testing::ValuesIn(std::vector<Data>{
- Types<f32M, AFloatM>(0.0_a, 0.0), //
- Types<f32M, AFloatM>(1.0_a, 1.0), //
- Types<f32M, AFloatM>(-1.0_a, -1.0), //
- Types<f32M, AFloatM>(AFloat(kHighestF32), kHighestF32), //
- Types<f32M, AFloatM>(AFloat(kLowestF32), kLowestF32), //
- Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
- Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
- Types<f32M, AFloatM>(AFloat(-kSubnormalF32), -kSubnormalF32), //
- /* Types<f16V, AFloatM>(1.0_a), */ //
+ Types<i32, AInt>(0_a, 0.0), //
+ Types<i32, AInt>(1_a, 1.0), //
+ Types<i32, AInt>(-1_a, -1.0), //
+ Types<i32, AInt>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32, AInt>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<u32, AInt>(0_a, 0.0), //
+ Types<u32, AInt>(1_a, 1.0), //
+ Types<u32, AInt>(AInt(u32::Highest()), u32::Highest()), //
+ Types<u32, AInt>(AInt(u32::Lowest()), u32::Lowest()), //
})));
-INSTANTIATE_TEST_SUITE_P(MaterializeSwitch,
- MaterializeAbstractNumericToConcreteType,
- testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kSwitchMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, 0.0), //
- Types<i32, AInt>(1_a, 1.0), //
- Types<i32, AInt>(-1_a, -1.0), //
- Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
- Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
- Types<u32, AInt>(0_a, 0.0), //
- Types<u32, AInt>(1_a, 1.0), //
- Types<u32, AInt>(AInt(kHighestU32), kHighestU32), //
- Types<u32, AInt>(AInt(kLowestU32), kLowestU32), //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ MaterializeArray,
+ MaterializeAbstractNumericToConcreteType,
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kArrayMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32A, AIntA>(0_a, 0.0), //
+ Types<i32A, AIntA>(1_a, 1.0), //
+ Types<i32A, AIntA>(-1_a, -1.0), //
+ Types<i32A, AIntA>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32A, AIntA>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<u32A, AIntA>(0_a, 0.0), //
+ Types<u32A, AIntA>(1_a, 1.0), //
+ Types<u32A, AIntA>(AInt(u32::Highest()), u32::Highest()), //
+ Types<u32A, AIntA>(AInt(u32::Lowest()), u32::Lowest()), //
+ Types<f32A, AFloatA>(0.0_a, 0.0), //
+ Types<f32A, AFloatA>(1.0_a, 1.0), //
+ Types<f32A, AFloatA>(-1.0_a, -1.0), //
+ Types<f32A, AFloatA>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32A, AFloatA>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32A, AFloatA>(AFloat(kPiF32), kPiF64), //
+ Types<f32A, AFloatA>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32A, AFloatA>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ Types<f16A, AFloatA>(0.0_a, 0.0), //
+ Types<f16A, AFloatA>(1.0_a, 1.0), //
+ Types<f16A, AFloatA>(-1.0_a, -1.0), //
+ Types<f16A, AFloatA>(AFloat(f16::Highest()), static_cast<double>(f16::Highest())), //
+ Types<f16A, AFloatA>(AFloat(f16::Lowest()), static_cast<double>(f16::Lowest())), //
+ Types<f16A, AFloatA>(AFloat(kPiF16), kPiF64), //
+ Types<f16A, AFloatA>(AFloat(kSubnormalF16), kSubnormalF16), //
+ Types<f16A, AFloatA>(AFloat(-kSubnormalF16), -kSubnormalF16), //
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
+ MaterializeArrayRuntimeIndex,
+ MaterializeAbstractNumericToConcreteType,
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::Values(Method::kRuntimeIndex),
+ testing::ValuesIn(std::vector<Data>{
+ Types<f32A, AFloatA>(0.0_a, 0.0), //
+ Types<f32A, AFloatA>(1.0_a, 1.0), //
+ Types<f32A, AFloatA>(-1.0_a, -1.0), //
+ Types<f32A, AFloatA>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32A, AFloatA>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32A, AFloatA>(AFloat(kPiF32), kPiF64), //
+ Types<f32A, AFloatA>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32A, AFloatA>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ })));
INSTANTIATE_TEST_SUITE_P(MaterializeWorkgroupSize,
MaterializeAbstractNumericToConcreteType,
@@ -530,37 +700,43 @@ INSTANTIATE_TEST_SUITE_P(InvalidConversion,
Types<u32, AFloat>(), //
Types<i32V, AFloatV>(), //
Types<u32V, AFloatV>(), //
+ Types<i32A, AInt>(), //
+ Types<i32A, AIntV>(), //
+ Types<i32A, AFloat>(), //
+ Types<i32A, AFloatV>(), //
})));
-INSTANTIATE_TEST_SUITE_P(ScalarValueCannotBeRepresented,
- MaterializeAbstractNumericToConcreteType,
- testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
- testing::ValuesIn(kScalarMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, kHighestI32 + 1), //
- Types<i32, AInt>(0_a, kLowestI32 - 1), //
- Types<u32, AInt>(0_a, kHighestU32 + 1), //
- Types<u32, AInt>(0_a, kLowestU32 - 1), //
- Types<f32, AFloat>(0.0_a, kTooBigF32), //
- Types<f32, AFloat>(0.0_a, -kTooBigF32), //
- /* Types<f16, AFloat>(), */ //
- /* Types<f16, AFloat>(), */ //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ ScalarValueCannotBeRepresented,
+ MaterializeAbstractNumericToConcreteType,
+ testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
+ testing::ValuesIn(kScalarMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kHighestValue) + 1), //
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kLowestValue) - 1), //
+ Types<u32, AInt>(0_a, static_cast<double>(u32::kHighestValue) + 1), //
+ Types<u32, AInt>(0_a, static_cast<double>(u32::kLowestValue) - 1), //
+ Types<f32, AFloat>(0.0_a, kTooBigF32), //
+ Types<f32, AFloat>(0.0_a, -kTooBigF32), //
+ Types<f16, AFloat>(0.0_a, kTooBigF16), //
+ Types<f16, AFloat>(0.0_a, -kTooBigF16), //
+ })));
-INSTANTIATE_TEST_SUITE_P(VectorValueCannotBeRepresented,
- MaterializeAbstractNumericToConcreteType,
- testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
- testing::ValuesIn(kVectorMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32V, AIntV>(0_a, kHighestI32 + 1), //
- Types<i32V, AIntV>(0_a, kLowestI32 - 1), //
- Types<u32V, AIntV>(0_a, kHighestU32 + 1), //
- Types<u32V, AIntV>(0_a, kLowestU32 - 1), //
- Types<f32V, AFloatV>(0.0_a, kTooBigF32), //
- Types<f32V, AFloatV>(0.0_a, -kTooBigF32), //
- /* Types<f16V, AFloatV>(), */ //
- /* Types<f16V, AFloatV>(), */ //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ VectorValueCannotBeRepresented,
+ MaterializeAbstractNumericToConcreteType,
+ testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
+ testing::ValuesIn(kVectorMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32V, AIntV>(0_a, static_cast<double>(i32::kHighestValue) + 1), //
+ Types<i32V, AIntV>(0_a, static_cast<double>(i32::kLowestValue) - 1), //
+ Types<u32V, AIntV>(0_a, static_cast<double>(u32::kHighestValue) + 1), //
+ Types<u32V, AIntV>(0_a, static_cast<double>(u32::kLowestValue) - 1), //
+ Types<f32V, AFloatV>(0.0_a, kTooBigF32), //
+ Types<f32V, AFloatV>(0.0_a, -kTooBigF32), //
+ Types<f16V, AFloatV>(0.0_a, kTooBigF16), //
+ Types<f16V, AFloatV>(0.0_a, -kTooBigF16), //
+ })));
INSTANTIATE_TEST_SUITE_P(MatrixValueCannotBeRepresented,
MaterializeAbstractNumericToConcreteType,
@@ -569,8 +745,8 @@ INSTANTIATE_TEST_SUITE_P(MatrixValueCannotBeRepresented,
testing::ValuesIn(std::vector<Data>{
Types<f32M, AFloatM>(0.0_a, kTooBigF32), //
Types<f32M, AFloatM>(0.0_a, -kTooBigF32), //
- /* Types<f16M, AFloatM>(), */ //
- /* Types<f16M, AFloatM>(), */ //
+ Types<f16M, AFloatM>(0.0_a, kTooBigF16), //
+ Types<f16M, AFloatM>(0.0_a, -kTooBigF16), //
})));
} // namespace materialize_abstract_numeric_to_concrete_type
@@ -614,6 +790,9 @@ enum class Method {
// arr[abstract_expr]
kIndex,
+
+ // abstract_expr[runtime-index]
+ kRuntimeIndex,
};
static std::ostream& operator<<(std::ostream& o, Method m) {
@@ -636,6 +815,8 @@ static std::ostream& operator<<(std::ostream& o, Method m) {
return o << "workgroup-size";
case Method::kIndex:
return o << "index";
+ case Method::kRuntimeIndex:
+ return o << "runtime-index";
}
return o << "<unknown>";
}
@@ -675,21 +856,18 @@ static std::ostream& operator<<(std::ostream& o, const Data& c) {
}
using MaterializeAbstractNumericToDefaultType =
- resolver::ResolverTestWithParam<std::tuple<Expectation, Method, Data>>;
+ MaterializeTest<std::tuple<Expectation, Method, Data>>;
TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
- // Once F16 is properly supported, we'll need to enable this:
- // Enable(ast::Extension::kF16);
-
const auto& param = GetParam();
const auto& expectation = std::get<0>(param);
const auto& method = std::get<1>(param);
const auto& data = std::get<2>(param);
- ast::ExpressionList abstract_exprs;
+ utils::Vector<const ast::Expression*, 4> abstract_exprs;
auto abstract_expr = [&] {
auto* expr = data.abstract_expr(*this, data.literal_value);
- abstract_exprs.emplace_back(expr);
+ abstract_exprs.Push(expr);
return expr;
};
switch (method) {
@@ -717,40 +895,28 @@ TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
DefaultCase()));
break;
case Method::kWorkgroupSize:
- Func("f", {}, ty.void_(), {},
- {WorkgroupSize(abstract_expr()), Stage(ast::PipelineStage::kCompute)});
+ Func(
+ "f", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{WorkgroupSize(abstract_expr()), Stage(ast::PipelineStage::kCompute)});
break;
case Method::kIndex:
- Global("arr", ty.array<i32, 4>(), ast::StorageClass::kPrivate);
+ GlobalVar("arr", ty.array<i32, 4>(), ast::StorageClass::kPrivate);
WrapInFunction(IndexAccessor("arr", abstract_expr()));
break;
+ case Method::kRuntimeIndex:
+ auto* runtime_index = Var("runtime_index", nullptr, Expr(1_i));
+ WrapInFunction(runtime_index, IndexAccessor(abstract_expr(), runtime_index));
+ break;
}
- auto check_types_and_values = [&](const sem::Expression* expr) {
- auto* expected_sem_ty = data.expected_sem_ty(*this);
-
- EXPECT_TYPE(expr->Type(), expected_sem_ty);
- EXPECT_TYPE(expr->ConstantValue().Type(), expected_sem_ty);
-
- uint32_t num_elems = 0;
- const sem::Type* expected_sem_el_ty = sem::Type::ElementOf(expected_sem_ty, &num_elems);
- EXPECT_TYPE(expr->ConstantValue().ElementType(), expected_sem_el_ty);
- expr->ConstantValue().WithElements([&](auto&& vec) {
- using VEC_TY = std::decay_t<decltype(vec)>;
- using EL_TY = typename VEC_TY::value_type;
- ASSERT_TRUE(std::holds_alternative<EL_TY>(data.materialized_value));
- VEC_TY expected(num_elems, std::get<EL_TY>(data.materialized_value));
- EXPECT_EQ(vec, expected);
- });
- };
-
switch (expectation) {
case Expectation::kMaterialize: {
ASSERT_TRUE(r()->Resolve()) << r()->error();
for (auto* expr : abstract_exprs) {
auto* materialize = Sem().Get<sem::Materialize>(expr);
ASSERT_NE(materialize, nullptr);
- check_types_and_values(materialize);
+ CheckTypesAndValues(materialize, data.expected_sem_ty(*this),
+ data.materialized_value);
}
break;
}
@@ -798,10 +964,8 @@ constexpr Method kAIntMethods[] = {
/// Methods that support vector materialization
constexpr Method kVectorMethods[] = {
- Method::kLet,
- Method::kVar,
- Method::kBuiltinArg,
- Method::kBitcastVec3F32Arg,
+ Method::kLet, Method::kVar, Method::kBuiltinArg, Method::kBitcastVec3F32Arg,
+ Method::kRuntimeIndex,
};
/// Methods that support matrix materialization
@@ -810,72 +974,104 @@ constexpr Method kMatrixMethods[] = {
Method::kVar,
};
+/// Methods that support array materialization
+constexpr Method kArrayMethods[] = {
+ Method::kLet,
+ Method::kVar,
+};
+
INSTANTIATE_TEST_SUITE_P(
MaterializeScalar,
MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kScalarMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, 0.0), //
- Types<i32, AInt>(1_a, 1.0), //
- Types<i32, AInt>(-1_a, -1.0), //
- Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
- Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
- Types<f32, AFloat>(0.0_a, 0.0), //
- Types<f32, AFloat>(AFloat(kHighestF32), kHighestF32), //
- Types<f32, AFloat>(AFloat(kLowestF32), kLowestF32), //
- Types<f32, AFloat>(AFloat(kPiF32), kPiF64), //
- Types<f32, AFloat>(AFloat(kSubnormalF32), kSubnormalF32), //
- Types<f32, AFloat>(AFloat(-kSubnormalF32), -kSubnormalF32), //
- })));
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kScalarMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32, AInt>(0_a, 0.0), //
+ Types<i32, AInt>(1_a, 1.0), //
+ Types<i32, AInt>(-1_a, -1.0), //
+ Types<i32, AInt>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32, AInt>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<f32, AFloat>(0.0_a, 0.0), //
+ Types<f32, AFloat>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32, AFloat>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32, AFloat>(AFloat(kPiF32), kPiF64), //
+ Types<f32, AFloat>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32, AFloat>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ })));
INSTANTIATE_TEST_SUITE_P(
MaterializeVector,
MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kVectorMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32V, AIntV>(0_a, 0.0), //
- Types<i32V, AIntV>(1_a, 1.0), //
- Types<i32V, AIntV>(-1_a, -1.0), //
- Types<i32V, AIntV>(AInt(kHighestI32), kHighestI32), //
- Types<i32V, AIntV>(AInt(kLowestI32), kLowestI32), //
- Types<f32V, AFloatV>(0.0_a, 0.0), //
- Types<f32V, AFloatV>(1.0_a, 1.0), //
- Types<f32V, AFloatV>(-1.0_a, -1.0), //
- Types<f32V, AFloatV>(AFloat(kHighestF32), kHighestF32), //
- Types<f32V, AFloatV>(AFloat(kLowestF32), kLowestF32), //
- Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
- Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
- Types<f32V, AFloatV>(AFloat(-kSubnormalF32), -kSubnormalF32), //
- })));
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kVectorMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32V, AIntV>(0_a, 0.0), //
+ Types<i32V, AIntV>(1_a, 1.0), //
+ Types<i32V, AIntV>(-1_a, -1.0), //
+ Types<i32V, AIntV>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32V, AIntV>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<f32V, AFloatV>(0.0_a, 0.0), //
+ Types<f32V, AFloatV>(1.0_a, 1.0), //
+ Types<f32V, AFloatV>(-1.0_a, -1.0), //
+ Types<f32V, AFloatV>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32V, AFloatV>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
+ Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32V, AFloatV>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ })));
INSTANTIATE_TEST_SUITE_P(
MaterializeMatrix,
MaterializeAbstractNumericToDefaultType,
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kMatrixMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<f32M, AFloatM>(0.0_a, 0.0), //
+ Types<f32M, AFloatM>(1.0_a, 1.0), //
+ Types<f32M, AFloatM>(-1.0_a, -1.0), //
+ Types<f32M, AFloatM>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32M, AFloatM>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
+ Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32M, AFloatM>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ })));
+
+INSTANTIATE_TEST_SUITE_P(
+ MaterializeAInt,
+ MaterializeAbstractNumericToDefaultType,
testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kMatrixMethods),
+ testing::ValuesIn(kAIntMethods),
testing::ValuesIn(std::vector<Data>{
- Types<f32M, AFloatM>(0.0_a, 0.0), //
- Types<f32M, AFloatM>(1.0_a, 1.0), //
- Types<f32M, AFloatM>(-1.0_a, -1.0), //
- Types<f32M, AFloatM>(AFloat(kHighestF32), kHighestF32), //
- Types<f32M, AFloatM>(AFloat(kLowestF32), kLowestF32), //
- Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
- Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
- Types<f32M, AFloatM>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ Types<i32, AInt>(0_a, 0.0), //
+ Types<i32, AInt>(10_a, 10.0), //
+ Types<i32, AInt>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32, AInt>(AInt(i32::Lowest()), i32::Lowest()), //
})));
-INSTANTIATE_TEST_SUITE_P(MaterializeAInt,
- MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kMaterialize),
- testing::ValuesIn(kAIntMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, 0.0), //
- Types<i32, AInt>(10_a, 10.0), //
- Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
- Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ MaterializeArray,
+ MaterializeAbstractNumericToDefaultType,
+ testing::Combine(
+ testing::Values(Expectation::kMaterialize),
+ testing::ValuesIn(kArrayMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32A, AIntA>(0_a, 0.0), //
+ Types<i32A, AIntA>(1_a, 1.0), //
+ Types<i32A, AIntA>(-1_a, -1.0), //
+ Types<i32A, AIntA>(AInt(i32::Highest()), i32::Highest()), //
+ Types<i32A, AIntA>(AInt(i32::Lowest()), i32::Lowest()), //
+ Types<f32A, AFloatA>(0.0_a, 0.0), //
+ Types<f32A, AFloatA>(1.0_a, 1.0), //
+ Types<f32A, AFloatA>(-1.0_a, -1.0), //
+ Types<f32A, AFloatA>(AFloat(f32::Highest()), static_cast<double>(f32::Highest())), //
+ Types<f32A, AFloatA>(AFloat(f32::Lowest()), static_cast<double>(f32::Lowest())), //
+ Types<f32A, AFloatA>(AFloat(kPiF32), kPiF64), //
+ Types<f32A, AFloatA>(AFloat(kSubnormalF32), kSubnormalF32), //
+ Types<f32A, AFloatA>(AFloat(-kSubnormalF32), -kSubnormalF32), //
+ })));
INSTANTIATE_TEST_SUITE_P(
MaterializeArrayLength,
@@ -886,7 +1082,7 @@ INSTANTIATE_TEST_SUITE_P(
Types<i32, AInt>(1_a, 1.0), //
Types<i32, AInt>(10_a, 10.0), //
Types<i32, AInt>(1000_a, 1000.0), //
- // Note: kHighestI32 cannot be used due to max-byte-size validation
+ // Note: i32::Highest() cannot be used due to max-byte-size validation
})));
INSTANTIATE_TEST_SUITE_P(MaterializeWorkgroupSize,
@@ -899,28 +1095,30 @@ INSTANTIATE_TEST_SUITE_P(MaterializeWorkgroupSize,
Types<i32, AInt>(65535_a, 65535.0), //
})));
-INSTANTIATE_TEST_SUITE_P(ScalarValueCannotBeRepresented,
- MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
- testing::ValuesIn(kScalarMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, kHighestI32 + 1), //
- Types<i32, AInt>(0_a, kLowestI32 - 1), //
- Types<f32, AFloat>(0.0_a, kTooBigF32), //
- Types<f32, AFloat>(0.0_a, -kTooBigF32), //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ ScalarValueCannotBeRepresented,
+ MaterializeAbstractNumericToDefaultType,
+ testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
+ testing::ValuesIn(kScalarMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kHighestValue) + 1), //
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kLowestValue) - 1), //
+ Types<f32, AFloat>(0.0_a, kTooBigF32), //
+ Types<f32, AFloat>(0.0_a, -kTooBigF32), //
+ })));
-INSTANTIATE_TEST_SUITE_P(VectorValueCannotBeRepresented,
- MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
- testing::ValuesIn(kVectorMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32V, AIntV>(0_a, kHighestI32 + 1), //
- Types<i32V, AIntV>(0_a, kLowestI32 - 1), //
- Types<i32V, AIntV>(0_a, kHighestU32 + 1), //
- Types<f32V, AFloatV>(0.0_a, kTooBigF32), //
- Types<f32V, AFloatV>(0.0_a, -kTooBigF32), //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ VectorValueCannotBeRepresented,
+ MaterializeAbstractNumericToDefaultType,
+ testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
+ testing::ValuesIn(kVectorMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32V, AIntV>(0_a, static_cast<double>(i32::kHighestValue) + 1), //
+ Types<i32V, AIntV>(0_a, static_cast<double>(i32::kLowestValue) - 1), //
+ Types<i32V, AIntV>(0_a, static_cast<double>(u32::kHighestValue) + 1), //
+ Types<f32V, AFloatV>(0.0_a, kTooBigF32), //
+ Types<f32V, AFloatV>(0.0_a, -kTooBigF32), //
+ })));
INSTANTIATE_TEST_SUITE_P(MatrixValueCannotBeRepresented,
MaterializeAbstractNumericToDefaultType,
@@ -931,33 +1129,60 @@ INSTANTIATE_TEST_SUITE_P(MatrixValueCannotBeRepresented,
Types<f32M, AFloatM>(0.0_a, -kTooBigF32), //
})));
-INSTANTIATE_TEST_SUITE_P(AIntValueCannotBeRepresented,
- MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
- testing::ValuesIn(kAIntMethods),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, kHighestI32 + 1), //
- Types<i32, AInt>(0_a, kLowestI32 - 1), //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ AIntValueCannotBeRepresented,
+ MaterializeAbstractNumericToDefaultType,
+ testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
+ testing::ValuesIn(kAIntMethods),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kHighestValue) + 1), //
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kLowestValue) - 1), //
+ })));
-INSTANTIATE_TEST_SUITE_P(WorkgroupSizeValueCannotBeRepresented,
- MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
- testing::Values(Method::kWorkgroupSize),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, kHighestI32 + 1), //
- Types<i32, AInt>(0_a, kLowestI32 - 1), //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ WorkgroupSizeValueCannotBeRepresented,
+ MaterializeAbstractNumericToDefaultType,
+ testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
+ testing::Values(Method::kWorkgroupSize),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kHighestValue) + 1), //
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kLowestValue) - 1), //
+ })));
-INSTANTIATE_TEST_SUITE_P(ArrayLengthValueCannotBeRepresented,
- MaterializeAbstractNumericToDefaultType,
- testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
- testing::Values(Method::kArrayLength),
- testing::ValuesIn(std::vector<Data>{
- Types<i32, AInt>(0_a, kHighestI32 + 1), //
- })));
+INSTANTIATE_TEST_SUITE_P(
+ ArrayLengthValueCannotBeRepresented,
+ MaterializeAbstractNumericToDefaultType,
+ testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
+ testing::Values(Method::kArrayLength),
+ testing::ValuesIn(std::vector<Data>{
+ Types<i32, AInt>(0_a, static_cast<double>(i32::kHighestValue) + 1), //
+ })));
} // namespace materialize_abstract_numeric_to_default_type
+namespace materialize_abstract_numeric_to_unrelated_type {
+
+using MaterializeAbstractNumericToUnrelatedType = resolver::ResolverTest;
+
+TEST_F(MaterializeAbstractNumericToUnrelatedType, AIntToStructVarCtor) {
+ Structure("S", utils::Vector{Member("a", ty.i32())});
+ WrapInFunction(Decl(Var("v", ty.type_name("S"), Expr(Source{{12, 34}}, 1_a))));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(
+ r()->error(),
+ testing::HasSubstr("error: cannot convert value of type 'abstract-int' to type 'S'"));
+}
+
+TEST_F(MaterializeAbstractNumericToUnrelatedType, AIntToStructLetCtor) {
+ Structure("S", utils::Vector{Member("a", ty.i32())});
+ WrapInFunction(Decl(Let("v", ty.type_name("S"), Expr(Source{{12, 34}}, 1_a))));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(
+ r()->error(),
+ testing::HasSubstr("error: cannot convert value of type 'abstract-int' to type 'S'"));
+}
+
+} // namespace materialize_abstract_numeric_to_unrelated_type
+
} // namespace
} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/pipeline_overridable_constant_test.cc b/chromium/third_party/dawn/src/tint/resolver/override_test.cc
index 035936c3f3e..2615d73c4f7 100644
--- a/chromium/third_party/dawn/src/tint/resolver/pipeline_overridable_constant_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/override_test.cc
@@ -21,23 +21,23 @@ using namespace tint::number_suffixes; // NOLINT
namespace tint::resolver {
namespace {
-class ResolverPipelineOverridableConstantTest : public ResolverTest {
+class ResolverOverrideTest : public ResolverTest {
protected:
/// Verify that the AST node `var` was resolved to an overridable constant
/// with an ID equal to `id`.
/// @param var the overridable constant AST node
/// @param id the expected constant ID
- void ExpectConstantId(const ast::Variable* var, uint16_t id) {
+ void ExpectOverrideId(const ast::Variable* var, uint16_t id) {
auto* sem = Sem().Get<sem::GlobalVariable>(var);
ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Declaration(), var);
- EXPECT_TRUE(sem->IsOverridable());
- EXPECT_EQ(sem->ConstantId(), id);
+ EXPECT_TRUE(sem->Declaration()->Is<ast::Override>());
+ EXPECT_EQ(sem->OverrideId().value, id);
EXPECT_FALSE(sem->ConstantValue());
}
};
-TEST_F(ResolverPipelineOverridableConstantTest, NonOverridable) {
+TEST_F(ResolverOverrideTest, NonOverridable) {
auto* a = GlobalConst("a", ty.f32(), Expr(1_f));
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -45,62 +45,72 @@ TEST_F(ResolverPipelineOverridableConstantTest, NonOverridable) {
auto* sem_a = Sem().Get<sem::GlobalVariable>(a);
ASSERT_NE(sem_a, nullptr);
EXPECT_EQ(sem_a->Declaration(), a);
- EXPECT_FALSE(sem_a->IsOverridable());
+ EXPECT_FALSE(sem_a->Declaration()->Is<ast::Override>());
EXPECT_TRUE(sem_a->ConstantValue());
}
-TEST_F(ResolverPipelineOverridableConstantTest, WithId) {
- auto* a = Override("a", ty.f32(), Expr(1_f), {Id(7u)});
+TEST_F(ResolverOverrideTest, WithId) {
+ auto* a = Override("a", ty.f32(), Expr(1_f), utils::Vector{Id(7u)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ExpectConstantId(a, 7u);
+ ExpectOverrideId(a, 7u);
}
-TEST_F(ResolverPipelineOverridableConstantTest, WithoutId) {
+TEST_F(ResolverOverrideTest, WithoutId) {
auto* a = Override("a", ty.f32(), Expr(1_f));
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ExpectConstantId(a, 0u);
+ ExpectOverrideId(a, 0u);
}
-TEST_F(ResolverPipelineOverridableConstantTest, WithAndWithoutIds) {
+TEST_F(ResolverOverrideTest, WithAndWithoutIds) {
std::vector<ast::Variable*> variables;
auto* a = Override("a", ty.f32(), Expr(1_f));
auto* b = Override("b", ty.f32(), Expr(1_f));
- auto* c = Override("c", ty.f32(), Expr(1_f), {Id(2u)});
- auto* d = Override("d", ty.f32(), Expr(1_f), {Id(4u)});
+ auto* c = Override("c", ty.f32(), Expr(1_f), utils::Vector{Id(2u)});
+ auto* d = Override("d", ty.f32(), Expr(1_f), utils::Vector{Id(4u)});
auto* e = Override("e", ty.f32(), Expr(1_f));
- auto* f = Override("f", ty.f32(), Expr(1_f), {Id(1u)});
+ auto* f = Override("f", ty.f32(), Expr(1_f), utils::Vector{Id(1u)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
// Verify that constant id allocation order is deterministic.
- ExpectConstantId(a, 0u);
- ExpectConstantId(b, 3u);
- ExpectConstantId(c, 2u);
- ExpectConstantId(d, 4u);
- ExpectConstantId(e, 5u);
- ExpectConstantId(f, 1u);
+ ExpectOverrideId(a, 0u);
+ ExpectOverrideId(b, 3u);
+ ExpectOverrideId(c, 2u);
+ ExpectOverrideId(d, 4u);
+ ExpectOverrideId(e, 5u);
+ ExpectOverrideId(f, 1u);
}
-TEST_F(ResolverPipelineOverridableConstantTest, DuplicateIds) {
- Override("a", ty.f32(), Expr(1_f), {Id(Source{{12, 34}}, 7u)});
- Override("b", ty.f32(), Expr(1_f), {Id(Source{{56, 78}}, 7u)});
+TEST_F(ResolverOverrideTest, DuplicateIds) {
+ Override("a", ty.f32(), Expr(1_f), utils::Vector{Id(Source{{12, 34}}, 7u)});
+ Override("b", ty.f32(), Expr(1_f), utils::Vector{Id(Source{{56, 78}}, 7u)});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(56:78 error: pipeline constant IDs must be unique
-12:34 note: a pipeline constant with an ID of 7 was previously declared here:)");
+ EXPECT_EQ(r()->error(), R"(56:78 error: override IDs must be unique
+12:34 note: a override with an ID of 7 was previously declared here:)");
}
-TEST_F(ResolverPipelineOverridableConstantTest, IdTooLarge) {
- Override("a", ty.f32(), Expr(1_f), {Id(Source{{12, 34}}, 65536u)});
+TEST_F(ResolverOverrideTest, IdTooLarge) {
+ Override("a", ty.f32(), Expr(1_f), utils::Vector{Id(Source{{12, 34}}, 65536u)});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: pipeline constant IDs must be between 0 and 65535");
+ EXPECT_EQ(r()->error(), "12:34 error: override IDs must be between 0 and 65535");
+}
+
+TEST_F(ResolverOverrideTest, F16_TemporallyBan) {
+ Enable(ast::Extension::kF16);
+
+ Override(Source{{12, 34}}, "a", ty.f16(), Expr(1_h), utils::Vector{Id(1u)});
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), "12:34 error: 'override' of type f16 is not implemented yet");
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/resolver/ptr_ref_test.cc b/chromium/third_party/dawn/src/tint/resolver/ptr_ref_test.cc
index 69b7e54051f..0a757b49554 100644
--- a/chromium/third_party/dawn/src/tint/resolver/ptr_ref_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/ptr_ref_test.cc
@@ -57,20 +57,20 @@ TEST_F(ResolverPtrRefTest, AddressOfThenDeref) {
TEST_F(ResolverPtrRefTest, DefaultPtrStorageClass) {
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
- auto* buf = Structure("S", {Member("m", ty.i32())});
+ auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
auto* function = Var("f", ty.i32());
- auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
- auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
- auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
- auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
+ auto* private_ = GlobalVar("p", ty.i32(), ast::StorageClass::kPrivate);
+ auto* workgroup = GlobalVar("w", ty.i32(), ast::StorageClass::kWorkgroup);
+ auto* uniform = GlobalVar("ub", ty.Of(buf), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+ auto* storage = GlobalVar("sb", ty.Of(buf), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
auto* function_ptr =
Let("f_ptr", ty.pointer(ty.i32(), ast::StorageClass::kFunction), AddressOf(function));
diff --git a/chromium/third_party/dawn/src/tint/resolver/ptr_ref_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/ptr_ref_validation_test.cc
index b011dd03821..5de50074d4e 100644
--- a/chromium/third_party/dawn/src/tint/resolver/ptr_ref_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/ptr_ref_validation_test.cc
@@ -54,7 +54,8 @@ TEST_F(ResolverPtrRefValidationTest, AddressOfLet) {
TEST_F(ResolverPtrRefValidationTest, AddressOfHandle) {
// @group(0) @binding(0) var t: texture_3d<f32>;
// &t
- Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()), GroupAndBinding(0u, 0u));
+ GlobalVar("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()),
+ GroupAndBinding(0u, 0u));
auto* expr = AddressOf(Expr(Source{{12, 34}}, "t"));
WrapInFunction(expr);
@@ -93,7 +94,8 @@ TEST_F(ResolverPtrRefValidationTest, AddressOfVectorComponent_IndexAccessor) {
TEST_F(ResolverPtrRefValidationTest, IndirectOfAddressOfHandle) {
// @group(0) @binding(0) var t: texture_3d<f32>;
// *&t
- Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()), GroupAndBinding(0u, 0u));
+ GlobalVar("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()),
+ GroupAndBinding(0u, 0u));
auto* expr = Deref(AddressOf(Expr(Source{{12, 34}}, "t")));
WrapInFunction(expr);
@@ -139,13 +141,13 @@ TEST_F(ResolverPtrRefValidationTest, InferredPtrAccessMismatch) {
// fn f() {
// let p : pointer<storage, i32> = &s.inner.arr[2i];
// }
- auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
- auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
- auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
+ auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
+ auto* storage = GlobalVar("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
auto* ptr =
diff --git a/chromium/third_party/dawn/src/tint/resolver/resolver.cc b/chromium/third_party/dawn/src/tint/resolver/resolver.cc
index 90ae4b08223..cd8bdc81750 100644
--- a/chromium/third_party/dawn/src/tint/resolver/resolver.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/resolver.cc
@@ -49,6 +49,7 @@
#include "src/tint/ast/unary_op_expression.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/vector.h"
+#include "src/tint/ast/while_statement.h"
#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/resolver/uniformity.h"
#include "src/tint/sem/abstract_float.h"
@@ -61,6 +62,7 @@
#include "src/tint/sem/for_loop_statement.h"
#include "src/tint/sem/function.h"
#include "src/tint/sem/if_statement.h"
+#include "src/tint/sem/index_accessor_expression.h"
#include "src/tint/sem/loop_statement.h"
#include "src/tint/sem/materialize.h"
#include "src/tint/sem/member_accessor_expression.h"
@@ -77,17 +79,20 @@
#include "src/tint/sem/type_constructor.h"
#include "src/tint/sem/type_conversion.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/sem/while_statement.h"
#include "src/tint/utils/defer.h"
#include "src/tint/utils/math.h"
#include "src/tint/utils/reverse.h"
#include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/transform.h"
+#include "src/tint/utils/vector.h"
namespace tint::resolver {
Resolver::Resolver(ProgramBuilder* builder)
: builder_(builder),
diagnostics_(builder->Diagnostics()),
+ const_eval_(*builder),
intrinsic_table_(IntrinsicTable::Create(*builder)),
sem_(builder, dependencies_),
validator_(builder, sem_) {}
@@ -99,6 +104,11 @@ bool Resolver::Resolve() {
return false;
}
+ builder_->Sem().Reserve(builder_->LastAllocatedNodeID());
+
+ // Pre-allocate the marked bitset with the total number of AST nodes.
+ marked_.Resize(builder_->ASTNodes().Count());
+
if (!DependencyGraph::Build(builder_->AST(), builder_->Symbols(), builder_->Diagnostics(),
dependencies_)) {
return false;
@@ -130,6 +140,7 @@ bool Resolver::ResolveInternal() {
[&](const ast::TypeDecl* td) { return TypeDecl(td); },
[&](const ast::Function* func) { return Function(func); },
[&](const ast::Variable* var) { return GlobalVariable(var); },
+ [&](const ast::StaticAssert* sa) { return StaticAssert(sa); },
[&](Default) {
TINT_UNREACHABLE(Resolver, diagnostics_)
<< "unhandled global declaration: " << decl->TypeInfo().name;
@@ -139,7 +150,9 @@ bool Resolver::ResolveInternal() {
}
}
- AllocateOverridableConstantIds();
+ if (!AllocateOverridableConstantIds()) {
+ return false;
+ }
SetShadows();
@@ -147,7 +160,11 @@ bool Resolver::ResolveInternal() {
return false;
}
- if (!enabled_extensions_.contains(ast::Extension::kChromiumDisableUniformityAnalysis)) {
+ if (!validator_.PushConstants(entry_points_)) {
+ return false;
+ }
+
+ if (!enabled_extensions_.Contains(ast::Extension::kChromiumDisableUniformityAnalysis)) {
if (!AnalyzeUniformity(builder_, dependencies_)) {
// TODO(jrprice): Reject programs that fail uniformity analysis.
}
@@ -155,7 +172,7 @@ bool Resolver::ResolveInternal() {
bool result = true;
for (auto* node : builder_->ASTNodes().Objects()) {
- if (marked_.count(node) == 0) {
+ if (!marked_[node->node_id.value]) {
TINT_ICE(Resolver, diagnostics_)
<< "AST node '" << node->TypeInfo().name << "' was not reached by the resolver\n"
<< "At: " << node->source << "\n"
@@ -177,7 +194,7 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
[&](const ast::U32*) { return builder_->create<sem::U32>(); },
[&](const ast::F16* t) -> sem::F16* {
// Validate if f16 type is allowed.
- if (!enabled_extensions_.contains(ast::Extension::kF16)) {
+ if (!enabled_extensions_.Contains(ast::Extension::kF16)) {
AddError("f16 used without 'f16' extension enabled", t->source);
return nullptr;
}
@@ -238,13 +255,21 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
[&](const ast::Sampler* t) { return builder_->create<sem::Sampler>(t->kind); },
[&](const ast::SampledTexture* t) -> sem::SampledTexture* {
if (auto* el = Type(t->type)) {
- return builder_->create<sem::SampledTexture>(t->dim, el);
+ auto* sem = builder_->create<sem::SampledTexture>(t->dim, el);
+ if (!validator_.SampledTexture(sem, t->source)) {
+ return nullptr;
+ }
+ return sem;
}
return nullptr;
},
[&](const ast::MultisampledTexture* t) -> sem::MultisampledTexture* {
if (auto* el = Type(t->type)) {
- return builder_->create<sem::MultisampledTexture>(t->dim, el);
+ auto* sem = builder_->create<sem::MultisampledTexture>(t->dim, el);
+ if (!validator_.MultisampledTexture(sem, t->source)) {
+ return nullptr;
+ }
+ return sem;
}
return nullptr;
},
@@ -301,9 +326,188 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
return s;
}
-sem::Variable* Resolver::Variable(const ast::Variable* var,
- VariableKind kind,
- uint32_t index /* = 0 */) {
+sem::Variable* Resolver::Variable(const ast::Variable* v, bool is_global) {
+ return Switch(
+ v, //
+ [&](const ast::Var* var) { return Var(var, is_global); },
+ [&](const ast::Let* let) { return Let(let, is_global); },
+ [&](const ast::Override* override) { return Override(override); },
+ [&](const ast::Const* const_) { return Const(const_, is_global); },
+ [&](Default) {
+ TINT_ICE(Resolver, diagnostics_)
+ << "Resolver::GlobalVariable() called with a unknown variable type: "
+ << v->TypeInfo().name;
+ return nullptr;
+ });
+}
+
+sem::Variable* Resolver::Let(const ast::Let* v, bool is_global) {
+ const sem::Type* ty = nullptr;
+
+ // If the variable has a declared type, resolve it.
+ if (v->type) {
+ ty = Type(v->type);
+ if (!ty) {
+ return nullptr;
+ }
+ }
+
+ if (!v->constructor) {
+ AddError("'let' declaration must have an initializer", v->source);
+ return nullptr;
+ }
+
+ auto* rhs = Materialize(Expression(v->constructor), ty);
+ if (!rhs) {
+ return nullptr;
+ }
+
+ // If the variable has no declared type, infer it from the RHS
+ if (!ty) {
+ ty = rhs->Type()->UnwrapRef(); // Implicit load of RHS
+ }
+
+ if (rhs && !validator_.VariableInitializer(v, ast::StorageClass::kNone, ty, rhs)) {
+ return nullptr;
+ }
+
+ if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, const_cast<sem::Type*>(ty),
+ v->source)) {
+ AddNote("while instantiating 'let' " + builder_->Symbols().NameFor(v->symbol), v->source);
+ return nullptr;
+ }
+
+ sem::Variable* sem = nullptr;
+ if (is_global) {
+ sem = builder_->create<sem::GlobalVariable>(
+ v, ty, sem::EvaluationStage::kRuntime, ast::StorageClass::kNone,
+ ast::Access::kUndefined, /* constant_value */ nullptr, sem::BindingPoint{});
+ } else {
+ sem = builder_->create<sem::LocalVariable>(v, ty, sem::EvaluationStage::kRuntime,
+ ast::StorageClass::kNone,
+ ast::Access::kUndefined, current_statement_,
+ /* constant_value */ nullptr);
+ }
+
+ sem->SetConstructor(rhs);
+ builder_->Sem().Add(v, sem);
+ return sem;
+}
+
+sem::Variable* Resolver::Override(const ast::Override* v) {
+ const sem::Type* ty = nullptr;
+
+ // If the variable has a declared type, resolve it.
+ if (v->type) {
+ ty = Type(v->type);
+ if (!ty) {
+ return nullptr;
+ }
+ }
+
+ const sem::Expression* rhs = nullptr;
+
+ // Does the variable have a constructor?
+ if (v->constructor) {
+ rhs = Materialize(Expression(v->constructor), ty);
+ if (!rhs) {
+ return nullptr;
+ }
+
+ // If the variable has no declared type, infer it from the RHS
+ if (!ty) {
+ ty = rhs->Type()->UnwrapRef(); // Implicit load of RHS
+ }
+ } else if (!ty) {
+ AddError("override declaration requires a type or initializer", v->source);
+ return nullptr;
+ }
+
+ if (rhs && !validator_.VariableInitializer(v, ast::StorageClass::kNone, ty, rhs)) {
+ return nullptr;
+ }
+
+ if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, const_cast<sem::Type*>(ty),
+ v->source)) {
+ AddNote("while instantiating 'override' " + builder_->Symbols().NameFor(v->symbol),
+ v->source);
+ return nullptr;
+ }
+
+ auto* sem = builder_->create<sem::GlobalVariable>(
+ v, ty, sem::EvaluationStage::kOverride, ast::StorageClass::kNone, ast::Access::kUndefined,
+ /* constant_value */ nullptr, sem::BindingPoint{});
+
+ if (auto* id = ast::GetAttribute<ast::IdAttribute>(v->attributes)) {
+ sem->SetOverrideId(OverrideId{static_cast<decltype(OverrideId::value)>(id->value)});
+ }
+
+ sem->SetConstructor(rhs);
+ builder_->Sem().Add(v, sem);
+ return sem;
+}
+
+sem::Variable* Resolver::Const(const ast::Const* c, bool is_global) {
+ const sem::Type* ty = nullptr;
+
+ // If the variable has a declared type, resolve it.
+ if (c->type) {
+ ty = Type(c->type);
+ if (!ty) {
+ return nullptr;
+ }
+ }
+
+ if (!c->constructor) {
+ AddError("'const' declaration must have an initializer", c->source);
+ return nullptr;
+ }
+
+ const auto* rhs = Expression(c->constructor);
+ if (!rhs) {
+ return nullptr;
+ }
+
+ if (ty) {
+ // If an explicit type was specified, materialize to that type
+ rhs = Materialize(rhs, ty);
+ if (!rhs) {
+ return nullptr;
+ }
+ } else {
+ // If no type was specified, infer it from the RHS
+ ty = rhs->Type();
+ }
+
+ const auto value = rhs->ConstantValue();
+ if (!value) {
+ AddError("'const' initializer must be constant expression", c->constructor->source);
+ return nullptr;
+ }
+
+ if (!validator_.VariableInitializer(c, ast::StorageClass::kNone, ty, rhs)) {
+ return nullptr;
+ }
+
+ if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, const_cast<sem::Type*>(ty),
+ c->source)) {
+ AddNote("while instantiating 'const' " + builder_->Symbols().NameFor(c->symbol), c->source);
+ return nullptr;
+ }
+
+ auto* sem = is_global ? static_cast<sem::Variable*>(builder_->create<sem::GlobalVariable>(
+ c, ty, sem::EvaluationStage::kConstant, ast::StorageClass::kNone,
+ ast::Access::kUndefined, value, sem::BindingPoint{}))
+ : static_cast<sem::Variable*>(builder_->create<sem::LocalVariable>(
+ c, ty, sem::EvaluationStage::kConstant, ast::StorageClass::kNone,
+ ast::Access::kUndefined, current_statement_, value));
+
+ sem->SetConstructor(rhs);
+ builder_->Sem().Add(c, sem);
+ return sem;
+}
+
+sem::Variable* Resolver::Var(const ast::Var* var, bool is_global) {
const sem::Type* storage_ty = nullptr;
// If the variable has a declared type, resolve it.
@@ -322,38 +526,21 @@ sem::Variable* Resolver::Variable(const ast::Variable* var,
if (!rhs) {
return nullptr;
}
-
// If the variable has no declared type, infer it from the RHS
if (!storage_ty) {
- if (!var->is_const && kind == VariableKind::kGlobal) {
- AddError("global var declaration must specify a type", var->source);
- return nullptr;
- }
-
storage_ty = rhs->Type()->UnwrapRef(); // Implicit load of RHS
}
- } else if (var->is_const && !var->is_overridable && kind != VariableKind::kParameter) {
- AddError("let declaration must have an initializer", var->source);
- return nullptr;
- } else if (!var->type) {
- AddError((kind == VariableKind::kGlobal)
- ? "module scope var declaration requires a type and initializer"
- : "function scope var declaration requires a type or initializer",
- var->source);
- return nullptr;
}
if (!storage_ty) {
- TINT_ICE(Resolver, diagnostics_) << "failed to determine storage type for variable '" +
- builder_->Symbols().NameFor(var->symbol) + "'\n"
- << "Source: " << var->source;
+ AddError("var declaration requires a type or initializer", var->source);
return nullptr;
}
auto storage_class = var->declared_storage_class;
- if (storage_class == ast::StorageClass::kNone && !var->is_const) {
+ if (storage_class == ast::StorageClass::kNone) {
// No declared storage class. Infer from usage / type.
- if (kind == VariableKind::kLocal) {
+ if (!is_global) {
storage_class = ast::StorageClass::kFunction;
} else if (storage_ty->UnwrapRef()->is_handle()) {
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
@@ -364,11 +551,10 @@ sem::Variable* Resolver::Variable(const ast::Variable* var,
}
}
- if (kind == VariableKind::kLocal && !var->is_const &&
- storage_class != ast::StorageClass::kFunction &&
+ if (!is_global && storage_class != ast::StorageClass::kFunction &&
validator_.IsValidationEnabled(var->attributes,
ast::DisabledValidation::kIgnoreStorageClass)) {
- AddError("function variable has a non-function storage class", var->source);
+ AddError("function-scope 'var' declaration must use 'function' storage class", var->source);
return nullptr;
}
@@ -377,80 +563,76 @@ sem::Variable* Resolver::Variable(const ast::Variable* var,
access = DefaultAccessForStorageClass(storage_class);
}
- auto* var_ty = storage_ty;
- if (!var->is_const) {
- // Variable declaration. Unlike `let`, `var` has storage.
- // Variables are always of a reference type to the declared storage type.
- var_ty = builder_->create<sem::Reference>(storage_ty, storage_class, access);
- }
-
- if (rhs && !validator_.VariableConstructorOrCast(var, storage_class, storage_ty, rhs->Type())) {
+ if (rhs && !validator_.VariableInitializer(var, storage_class, storage_ty, rhs)) {
return nullptr;
}
- if (!ApplyStorageClassUsageToType(storage_class, const_cast<sem::Type*>(var_ty), var->source)) {
- AddNote(std::string("while instantiating ") +
- ((kind == VariableKind::kParameter) ? "parameter " : "variable ") +
- builder_->Symbols().NameFor(var->symbol),
+ auto* var_ty = builder_->create<sem::Reference>(storage_ty, storage_class, access);
+
+ if (!ApplyStorageClassUsageToType(storage_class, var_ty, var->source)) {
+ AddNote("while instantiating 'var' " + builder_->Symbols().NameFor(var->symbol),
var->source);
return nullptr;
}
- if (kind == VariableKind::kParameter) {
- if (auto* ptr = var_ty->As<sem::Pointer>()) {
- // For MSL, we push module-scope variables into the entry point as pointer
- // parameters, so we also need to handle their store type.
- if (!ApplyStorageClassUsageToType(
- ptr->StorageClass(), const_cast<sem::Type*>(ptr->StoreType()), var->source)) {
- AddNote("while instantiating parameter " + builder_->Symbols().NameFor(var->symbol),
- var->source);
- return nullptr;
- }
+ sem::Variable* sem = nullptr;
+ if (is_global) {
+ sem::BindingPoint binding_point;
+ if (auto bp = var->BindingPoint()) {
+ binding_point = {bp.group->value, bp.binding->value};
}
+ sem = builder_->create<sem::GlobalVariable>(var, var_ty, sem::EvaluationStage::kRuntime,
+ storage_class, access,
+ /* constant_value */ nullptr, binding_point);
+
+ } else {
+ sem = builder_->create<sem::LocalVariable>(var, var_ty, sem::EvaluationStage::kRuntime,
+ storage_class, access, current_statement_,
+ /* constant_value */ nullptr);
}
- switch (kind) {
- case VariableKind::kGlobal: {
- sem::BindingPoint binding_point;
- if (auto bp = var->BindingPoint()) {
- binding_point = {bp.group->value, bp.binding->value};
- }
+ sem->SetConstructor(rhs);
+ builder_->Sem().Add(var, sem);
+ return sem;
+}
- bool has_const_val = rhs && var->is_const && !var->is_overridable;
- auto* global = builder_->create<sem::GlobalVariable>(
- var, var_ty, storage_class, access,
- has_const_val ? rhs->ConstantValue() : sem::Constant{}, binding_point);
+sem::Parameter* Resolver::Parameter(const ast::Parameter* param, uint32_t index) {
+ auto add_note = [&] {
+ AddNote("while instantiating parameter " + builder_->Symbols().NameFor(param->symbol),
+ param->source);
+ };
- if (var->is_overridable) {
- global->SetIsOverridable();
- if (auto* id = ast::GetAttribute<ast::IdAttribute>(var->attributes)) {
- global->SetConstantId(static_cast<uint16_t>(id->value));
- }
- }
+ for (auto* attr : param->attributes) {
+ Mark(attr);
+ }
+ if (!validator_.NoDuplicateAttributes(param->attributes)) {
+ return nullptr;
+ }
- global->SetConstructor(rhs);
+ sem::Type* ty = Type(param->type);
+ if (!ty) {
+ return nullptr;
+ }
- builder_->Sem().Add(var, global);
- return global;
- }
- case VariableKind::kLocal: {
- auto* local = builder_->create<sem::LocalVariable>(
- var, var_ty, storage_class, access, current_statement_,
- (rhs && var->is_const) ? rhs->ConstantValue() : sem::Constant{});
- builder_->Sem().Add(var, local);
- local->SetConstructor(rhs);
- return local;
- }
- case VariableKind::kParameter: {
- auto* param =
- builder_->create<sem::Parameter>(var, index, var_ty, storage_class, access);
- builder_->Sem().Add(var, param);
- return param;
+ if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, ty, param->source)) {
+ add_note();
+ return nullptr;
+ }
+
+ if (auto* ptr = ty->As<sem::Pointer>()) {
+ // For MSL, we push module-scope variables into the entry point as pointer
+ // parameters, so we also need to handle their store type.
+ if (!ApplyStorageClassUsageToType(
+ ptr->StorageClass(), const_cast<sem::Type*>(ptr->StoreType()), param->source)) {
+ add_note();
+ return nullptr;
}
}
- TINT_UNREACHABLE(Resolver, diagnostics_) << "unhandled VariableKind " << static_cast<int>(kind);
- return nullptr;
+ auto* sem = builder_->create<sem::Parameter>(param, index, ty, ast::StorageClass::kNone,
+ ast::Access::kUndefined);
+ builder_->Sem().Add(param, sem);
+ return sem;
}
ast::Access Resolver::DefaultAccessForStorageClass(ast::StorageClass storage_class) {
@@ -466,40 +648,52 @@ ast::Access Resolver::DefaultAccessForStorageClass(ast::StorageClass storage_cla
return ast::Access::kReadWrite;
}
-void Resolver::AllocateOverridableConstantIds() {
+bool Resolver::AllocateOverridableConstantIds() {
+ constexpr size_t kLimit = std::numeric_limits<decltype(OverrideId::value)>::max();
// The next pipeline constant ID to try to allocate.
- uint16_t next_constant_id = 0;
+ OverrideId next_id;
+ bool ids_exhausted = false;
+
+ auto increment_next_id = [&] {
+ if (next_id.value == kLimit) {
+ ids_exhausted = true;
+ } else {
+ next_id.value = next_id.value + 1;
+ }
+ };
// Allocate constant IDs in global declaration order, so that they are
// deterministic.
// TODO(crbug.com/tint/1192): If a transform changes the order or removes an
// unused constant, the allocation may change on the next Resolver pass.
for (auto* decl : builder_->AST().GlobalDeclarations()) {
- auto* var = decl->As<ast::Variable>();
- if (!var || !var->is_overridable) {
+ auto* override = decl->As<ast::Override>();
+ if (!override) {
continue;
}
- uint16_t constant_id;
- if (auto* id_attr = ast::GetAttribute<ast::IdAttribute>(var->attributes)) {
- constant_id = static_cast<uint16_t>(id_attr->value);
+ OverrideId id;
+ if (auto* id_attr = ast::GetAttribute<ast::IdAttribute>(override->attributes)) {
+ id = OverrideId{static_cast<decltype(OverrideId::value)>(id_attr->value)};
} else {
// No ID was specified, so allocate the next available ID.
- constant_id = next_constant_id;
- while (constant_ids_.count(constant_id)) {
- if (constant_id == UINT16_MAX) {
- TINT_ICE(Resolver, builder_->Diagnostics())
- << "no more pipeline constant IDs available";
- return;
- }
- constant_id++;
+ while (!ids_exhausted && override_ids_.count(next_id)) {
+ increment_next_id();
}
- next_constant_id = constant_id + 1;
+ if (ids_exhausted) {
+ AddError(
+ "number of 'override' variables exceeded limit of " + std::to_string(kLimit),
+ decl->source);
+ return false;
+ }
+ id = next_id;
+ increment_next_id();
}
- auto* sem = sem_.Get<sem::GlobalVariable>(var);
- const_cast<sem::GlobalVariable*>(sem)->SetConstantId(constant_id);
+ auto* sem = sem_.Get<sem::GlobalVariable>(override);
+ const_cast<sem::GlobalVariable*>(sem)->SetOverrideId(id);
}
+ return true;
}
void Resolver::SetShadows() {
@@ -511,52 +705,70 @@ void Resolver::SetShadows() {
}
}
-sem::GlobalVariable* Resolver::GlobalVariable(const ast::Variable* var) {
- auto* sem = Variable(var, VariableKind::kGlobal);
+sem::GlobalVariable* Resolver::GlobalVariable(const ast::Variable* v) {
+ auto* sem = As<sem::GlobalVariable>(Variable(v, /* is_global */ true));
if (!sem) {
return nullptr;
}
- auto storage_class = sem->StorageClass();
- if (!var->is_const && storage_class == ast::StorageClass::kNone) {
- AddError("global variables must have a storage class", var->source);
- return nullptr;
- }
- if (var->is_const && storage_class != ast::StorageClass::kNone) {
- AddError("global constants shouldn't have a storage class", var->source);
- return nullptr;
- }
-
- for (auto* attr : var->attributes) {
+ for (auto* attr : v->attributes) {
Mark(attr);
if (auto* id_attr = attr->As<ast::IdAttribute>()) {
// Track the constant IDs that are specified in the shader.
- constant_ids_.emplace(id_attr->value, sem);
+ override_ids_.emplace(
+ OverrideId{static_cast<decltype(OverrideId::value)>(id_attr->value)}, sem);
}
}
- if (!validator_.NoDuplicateAttributes(var->attributes)) {
+ if (!validator_.NoDuplicateAttributes(v->attributes)) {
return nullptr;
}
- if (!validator_.GlobalVariable(sem, constant_ids_, atomic_composite_info_)) {
+ if (!validator_.GlobalVariable(sem, override_ids_, atomic_composite_info_)) {
return nullptr;
}
// TODO(bclayton): Call this at the end of resolve on all uniform and storage
// referenced structs
- if (!validator_.StorageClassLayout(sem, valid_type_storage_layouts_)) {
+ if (!validator_.StorageClassLayout(sem, enabled_extensions_, valid_type_storage_layouts_)) {
return nullptr;
}
- return sem->As<sem::GlobalVariable>();
+ return sem;
+}
+
+sem::Statement* Resolver::StaticAssert(const ast::StaticAssert* assertion) {
+ auto* expr = Expression(assertion->condition);
+ if (!expr) {
+ return nullptr;
+ }
+ auto* cond = expr->ConstantValue();
+ if (!cond) {
+ AddError("static assertion condition must be a constant expression",
+ assertion->condition->source);
+ return nullptr;
+ }
+ if (auto* ty = cond->Type(); !ty->Is<sem::Bool>()) {
+ AddError(
+ "static assertion condition must be a bool, got '" + builder_->FriendlyName(ty) + "'",
+ assertion->condition->source);
+ return nullptr;
+ }
+ if (!cond->As<bool>()) {
+ AddError("static assertion failed", assertion->source);
+ return nullptr;
+ }
+ auto* sem =
+ builder_->create<sem::Statement>(assertion, current_compound_statement_, current_function_);
+ builder_->Sem().Add(assertion, sem);
+ return sem;
}
sem::Function* Resolver::Function(const ast::Function* decl) {
uint32_t parameter_index = 0;
std::unordered_map<Symbol, Source> parameter_names;
- std::vector<sem::Parameter*> parameters;
+ utils::Vector<sem::Parameter*, 8> parameters;
// Resolve all the parameters
for (auto* param : decl->params) {
@@ -572,23 +784,19 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
}
}
- auto* var =
- As<sem::Parameter>(Variable(param, VariableKind::kParameter, parameter_index++));
- if (!var) {
+ auto* p = Parameter(param, parameter_index++);
+ if (!p) {
return nullptr;
}
- for (auto* attr : param->attributes) {
- Mark(attr);
- }
- if (!validator_.NoDuplicateAttributes(param->attributes)) {
+ if (!validator_.Parameter(decl, p)) {
return nullptr;
}
- parameters.emplace_back(var);
+ parameters.Push(p);
- auto* var_ty = const_cast<sem::Type*>(var->Type());
- if (auto* str = var_ty->As<sem::Struct>()) {
+ auto* p_ty = const_cast<sem::Type*>(p->Type());
+ if (auto* str = p_ty->As<sem::Struct>()) {
switch (decl->PipelineStage()) {
case ast::PipelineStage::kVertex:
str->AddUsage(sem::PipelineStageUsage::kVertexInput);
@@ -639,7 +847,7 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
}
}
- auto* func = builder_->create<sem::Function>(decl, return_type, parameters);
+ auto* func = builder_->create<sem::Function>(decl, return_type, std::move(parameters));
builder_->Sem().Add(decl, func);
TINT_SCOPED_ASSIGNMENT(current_function_, func);
@@ -709,7 +917,7 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
bool Resolver::WorkgroupSize(const ast::Function* func) {
// Set work-group size defaults.
sem::WorkgroupSize ws;
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
ws[i].value = 1;
ws[i].overridable_const = nullptr;
}
@@ -720,15 +928,14 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
}
auto values = attr->Values();
- std::array<const sem::Expression*, 3> args = {};
- std::array<const sem::Type*, 3> arg_tys = {};
- size_t arg_count = 0;
+ utils::Vector<const sem::Expression*, 3> args;
+ utils::Vector<const sem::Type*, 3> arg_tys;
- constexpr const char* kErrBadType =
- "workgroup_size argument must be either literal or module-scope constant of type i32 "
- "or u32";
+ constexpr const char* kErrBadExpr =
+ "workgroup_size argument must be either a literal, constant, or overridable of type "
+ "abstract-integer, i32 or u32";
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
// Each argument to this attribute can either be a literal, an identifier for a module-scope
// constants, or nullptr if not specified.
auto* value = values[i];
@@ -741,16 +948,15 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
}
auto* ty = expr->Type();
if (!ty->IsAnyOf<sem::I32, sem::U32, sem::AbstractInt>()) {
- AddError(kErrBadType, value->source);
+ AddError(kErrBadExpr, value->source);
return false;
}
- args[i] = expr;
- arg_tys[i] = ty;
- arg_count++;
+ args.Push(expr);
+ arg_tys.Push(ty);
}
- auto* common_ty = sem::Type::Common(arg_tys.data(), arg_count);
+ auto* common_ty = sem::Type::Common(arg_tys);
if (!common_ty) {
AddError("workgroup_size arguments must be of the same type, either i32 or u32",
attr->source);
@@ -762,23 +968,23 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
common_ty = builder_->create<sem::I32>();
}
- for (size_t i = 0; i < arg_count; i++) {
+ for (size_t i = 0; i < args.Length(); i++) {
auto* materialized = Materialize(args[i], common_ty);
if (!materialized) {
return false;
}
- sem::Constant value;
+ const sem::Constant* value = nullptr;
if (auto* user = args[i]->As<sem::VariableUser>()) {
// We have an variable of a module-scope constant.
auto* decl = user->Variable()->Declaration();
- if (!decl->is_const) {
- AddError(kErrBadType, values[i]->source);
+ if (!decl->IsAnyOf<ast::Const, ast::Override>()) {
+ AddError(kErrBadExpr, values[i]->source);
return false;
}
// Capture the constant if it is pipeline-overridable.
- if (decl->is_overridable) {
+ if (decl->Is<ast::Override>()) {
ws[i].overridable_const = decl;
}
@@ -792,10 +998,7 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
} else if (values[i]->Is<ast::LiteralExpression>()) {
value = materialized->ConstantValue();
} else {
- AddError(
- "workgroup_size argument must be either a literal or a "
- "module-scope constant",
- values[i]->source);
+ AddError(kErrBadExpr, values[i]->source);
return false;
}
@@ -805,19 +1008,19 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
continue;
}
// validator_.Validate and set the default value for this dimension.
- if (value.Element<AInt>(0).value < 1) {
+ if (value->As<AInt>() < 1) {
AddError("workgroup_size argument must be at least 1", values[i]->source);
return false;
}
- ws[i].value = value.Element<uint32_t>(0);
+ ws[i].value = value->As<uint32_t>();
}
current_function_->SetWorkgroupSize(std::move(ws));
return true;
}
-bool Resolver::Statements(const ast::StatementList& stmts) {
+bool Resolver::Statements(utils::VectorRef<const ast::Statement*> stmts) {
sem::Behaviors behaviors{sem::Behavior::kNext};
bool reachable = true;
@@ -852,6 +1055,7 @@ sem::Statement* Resolver::Statement(const ast::Statement* stmt) {
[&](const ast::BlockStatement* b) { return BlockStatement(b); },
[&](const ast::ForLoopStatement* l) { return ForLoopStatement(l); },
[&](const ast::LoopStatement* l) { return LoopStatement(l); },
+ [&](const ast::WhileStatement* w) { return WhileStatement(w); },
[&](const ast::IfStatement* i) { return IfStatement(i); },
[&](const ast::SwitchStatement* s) { return SwitchStatement(s); },
@@ -866,6 +1070,7 @@ sem::Statement* Resolver::Statement(const ast::Statement* stmt) {
[&](const ast::IncrementDecrementStatement* i) { return IncrementDecrementStatement(i); },
[&](const ast::ReturnStatement* r) { return ReturnStatement(r); },
[&](const ast::VariableDeclStatement* v) { return VariableDeclStatement(v); },
+ [&](const ast::StaticAssert* sa) { return StaticAssert(sa); },
// Error cases
[&](const ast::CaseStatement*) {
@@ -882,7 +1087,7 @@ sem::CaseStatement* Resolver::CaseStatement(const ast::CaseStatement* stmt) {
auto* sem =
builder_->create<sem::CaseStatement>(stmt, current_compound_statement_, current_function_);
return StatementScope(stmt, sem, [&] {
- sem->Selectors().reserve(stmt->selectors.size());
+ sem->Selectors().reserve(stmt->selectors.Length());
for (auto* sel : stmt->selectors) {
auto* expr = Expression(sel);
if (!expr) {
@@ -1037,8 +1242,41 @@ sem::ForLoopStatement* Resolver::ForLoopStatement(const ast::ForLoopStatement* s
});
}
+sem::WhileStatement* Resolver::WhileStatement(const ast::WhileStatement* stmt) {
+ auto* sem =
+ builder_->create<sem::WhileStatement>(stmt, current_compound_statement_, current_function_);
+ return StatementScope(stmt, sem, [&] {
+ auto& behaviors = sem->Behaviors();
+
+ auto* cond = Expression(stmt->condition);
+ if (!cond) {
+ return false;
+ }
+ sem->SetCondition(cond);
+ behaviors.Add(cond->Behaviors());
+
+ Mark(stmt->body);
+
+ auto* body = builder_->create<sem::LoopBlockStatement>(
+ stmt->body, current_compound_statement_, current_function_);
+ if (!StatementScope(stmt->body, body, [&] { return Statements(stmt->body->statements); })) {
+ return false;
+ }
+
+ behaviors.Add(body->Behaviors());
+ // Always consider the while as having a 'next' behaviour because it has
+ // a condition. We don't check if the condition will terminate but it isn't
+ // valid to have an infinite loop in a WGSL program, so a non-terminating
+ // condition is already an invalid program.
+ behaviors.Add(sem::Behavior::kNext);
+ behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kContinue);
+
+ return validator_.WhileStatement(sem);
+ });
+}
+
sem::Expression* Resolver::Expression(const ast::Expression* root) {
- std::vector<const ast::Expression*> sorted;
+ utils::Vector<const ast::Expression*, 64> sorted;
constexpr size_t kMaxExpressionDepth = 512U;
bool failed = false;
if (!ast::TraverseExpressions<ast::TraverseOrder::RightToLeft>(
@@ -1054,7 +1292,7 @@ sem::Expression* Resolver::Expression(const ast::Expression* root) {
failed = true;
return ast::TraverseAction::Stop;
}
- sorted.emplace_back(expr);
+ sorted.Push(expr);
return ast::TraverseAction::Descend;
})) {
return nullptr;
@@ -1087,7 +1325,9 @@ sem::Expression* Resolver::Expression(const ast::Expression* root) {
[&](const ast::UnaryOpExpression* unary) -> sem::Expression* { return UnaryOp(unary); },
[&](const ast::PhonyExpression*) -> sem::Expression* {
return builder_->create<sem::Expression>(expr, builder_->create<sem::Void>(),
- current_statement_, sem::Constant{},
+ sem::EvaluationStage::kRuntime,
+ current_statement_,
+ /* constant_value */ nullptr,
/* has_side_effects */ false);
},
[&](Default) {
@@ -1109,45 +1349,9 @@ sem::Expression* Resolver::Expression(const ast::Expression* root) {
return nullptr;
}
-const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
- const sem::Type* target_type /* = nullptr */) {
- if (!expr) {
- return nullptr; // Allow for Materialize(Expression(blah))
- }
-
- // Helper for actually creating the the materialize node, performing the constant cast, updating
- // the ast -> sem binding, and performing validation.
- auto materialize = [&](const sem::Type* target_ty) -> sem::Materialize* {
- auto* decl = expr->Declaration();
- auto expr_val = EvaluateConstantValue(decl, expr->Type());
- if (!expr_val) {
- return nullptr;
- }
- if (!expr_val->IsValid()) {
- TINT_ICE(Resolver, builder_->Diagnostics())
- << decl->source
- << "EvaluateConstantValue() returned invalid value for materialized value of type: "
- << builder_->FriendlyName(expr->Type());
- return nullptr;
- }
- auto materialized_val = ConvertValue(expr_val.Get(), target_ty, decl->source);
- if (!materialized_val) {
- return nullptr;
- }
- if (!materialized_val->IsValid()) {
- TINT_ICE(Resolver, builder_->Diagnostics())
- << decl->source << "ConvertValue(" << builder_->FriendlyName(expr_val->Type())
- << " -> " << builder_->FriendlyName(target_ty) << ") returned invalid value";
- return nullptr;
- }
- auto* m =
- builder_->create<sem::Materialize>(expr, current_statement_, materialized_val.Get());
- m->Behaviors() = expr->Behaviors();
- builder_->Sem().Replace(decl, m);
- return validator_.Materialize(m) ? m : nullptr;
- };
-
- // Helpers for constructing semantic types
+const sem::Type* Resolver::ConcreteType(const sem::Type* ty,
+ const sem::Type* target_ty,
+ const Source& source) {
auto i32 = [&] { return builder_->create<sem::I32>(); };
auto f32 = [&] { return builder_->create<sem::F32>(); };
auto i32v = [&](uint32_t width) { return builder_->create<sem::Vector>(i32(), width); };
@@ -1156,36 +1360,85 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
return builder_->create<sem::Matrix>(f32v(rows), columns);
};
- // Type dispatch based on the expression type
- return Switch<sem::Expression*>(
- expr->Type(), //
- [&](const sem::AbstractInt*) { return materialize(target_type ? target_type : i32()); },
- [&](const sem::AbstractFloat*) { return materialize(target_type ? target_type : f32()); },
+ return Switch(
+ ty, //
+ [&](const sem::AbstractInt*) { return target_ty ? target_ty : i32(); },
+ [&](const sem::AbstractFloat*) { return target_ty ? target_ty : f32(); },
[&](const sem::Vector* v) {
return Switch(
v->type(), //
- [&](const sem::AbstractInt*) {
- return materialize(target_type ? target_type : i32v(v->Width()));
- },
+ [&](const sem::AbstractInt*) { return target_ty ? target_ty : i32v(v->Width()); },
[&](const sem::AbstractFloat*) {
- return materialize(target_type ? target_type : f32v(v->Width()));
- },
- [&](Default) { return expr; });
+ return target_ty ? target_ty : f32v(v->Width());
+ });
},
[&](const sem::Matrix* m) {
- return Switch(
- m->type(), //
- [&](const sem::AbstractFloat*) {
- return materialize(target_type ? target_type : f32m(m->columns(), m->rows()));
- },
- [&](Default) { return expr; });
+ return Switch(m->type(), //
+ [&](const sem::AbstractFloat*) {
+ return target_ty ? target_ty : f32m(m->columns(), m->rows());
+ });
},
- [&](Default) { return expr; });
+ [&](const sem::Array* a) -> const sem::Type* {
+ const sem::Type* target_el_ty = nullptr;
+ if (auto* target_arr_ty = As<sem::Array>(target_ty)) {
+ target_el_ty = target_arr_ty->ElemType();
+ }
+ if (auto* el_ty = ConcreteType(a->ElemType(), target_el_ty, source)) {
+ return Array(source, el_ty, a->Count(), /* explicit_stride */ 0);
+ }
+ return nullptr;
+ });
}
-bool Resolver::MaterializeArguments(std::vector<const sem::Expression*>& args,
+const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
+ const sem::Type* target_type /* = nullptr */) {
+ if (!expr) {
+ // Allow for Materialize(Expression(blah)), where failures pass through Materialize()
+ return nullptr;
+ }
+
+ auto* decl = expr->Declaration();
+
+ auto* concrete_ty = ConcreteType(expr->Type(), target_type, decl->source);
+ if (!concrete_ty) {
+ return expr; // Does not require materialization
+ }
+
+ auto* src_ty = expr->Type();
+ if (!validator_.Materialize(concrete_ty, src_ty, decl->source)) {
+ return nullptr;
+ }
+
+ auto expr_val = expr->ConstantValue();
+ if (!expr_val) {
+ TINT_ICE(Resolver, builder_->Diagnostics())
+ << decl->source << "Materialize(" << decl->TypeInfo().name
+ << ") called on expression with no constant value";
+ return nullptr;
+ }
+
+ auto materialized_val = const_eval_.Convert(concrete_ty, expr_val, decl->source);
+ if (!materialized_val) {
+ // ConvertValue() has already failed and raised an diagnostic error.
+ return nullptr;
+ }
+
+ if (!materialized_val.Get()) {
+ TINT_ICE(Resolver, builder_->Diagnostics())
+ << decl->source << "ConvertValue(" << builder_->FriendlyName(expr_val->Type()) << " -> "
+ << builder_->FriendlyName(concrete_ty) << ") returned invalid value";
+ return nullptr;
+ }
+ auto* m = builder_->create<sem::Materialize>(expr, current_statement_, materialized_val.Get());
+ m->Behaviors() = expr->Behaviors();
+ builder_->Sem().Replace(decl, m);
+ return m;
+}
+
+template <size_t N>
+bool Resolver::MaterializeArguments(utils::Vector<const sem::Expression*, N>& args,
const sem::CallTarget* target) {
- for (size_t i = 0, n = std::min(args.size(), target->Parameters().size()); i < n; i++) {
+ for (size_t i = 0, n = std::min(args.Length(), target->Parameters().Length()); i < n; i++) {
const auto* param_ty = target->Parameters()[i]->Type();
if (ShouldMaterializeArgument(param_ty)) {
auto* materialized = Materialize(args[i], param_ty);
@@ -1199,16 +1452,48 @@ bool Resolver::MaterializeArguments(std::vector<const sem::Expression*>& args,
}
bool Resolver::ShouldMaterializeArgument(const sem::Type* parameter_ty) const {
- const auto* param_el_ty = sem::Type::ElementOf(parameter_ty);
+ const auto* param_el_ty = sem::Type::DeepestElementOf(parameter_ty);
return param_el_ty && !param_el_ty->Is<sem::AbstractNumeric>();
}
+bool Resolver::Convert(const sem::Constant*& c, const sem::Type* target_ty, const Source& source) {
+ auto r = const_eval_.Convert(target_ty, c, source);
+ if (!r) {
+ return false;
+ }
+ c = r.Get();
+ return true;
+}
+
+template <size_t N>
+utils::Result<utils::Vector<const sem::Constant*, N>> Resolver::ConvertArguments(
+ const utils::Vector<const sem::Expression*, N>& args,
+ const sem::CallTarget* target) {
+ auto const_args = utils::Transform(args, [](auto* arg) { return arg->ConstantValue(); });
+ for (size_t i = 0, n = std::min(args.Length(), target->Parameters().Length()); i < n; i++) {
+ if (!Convert(const_args[i], target->Parameters()[i]->Type(),
+ args[i]->Declaration()->source)) {
+ return utils::Failure;
+ }
+ }
+ return const_args;
+}
+
sem::Expression* Resolver::IndexAccessor(const ast::IndexAccessorExpression* expr) {
auto* idx = Materialize(sem_.Get(expr->index));
if (!idx) {
return nullptr;
}
- auto* obj = sem_.Get(expr->object);
+ const auto* obj = sem_.Get(expr->object);
+ if (idx->Stage() != sem::EvaluationStage::kConstant) {
+ // If the index is non-constant, then the resulting expression is non-constant, so we'll
+ // have to materialize the object. For example, consider:
+ // vec2(1, 2)[runtime-index]
+ obj = Materialize(obj);
+ }
+ if (!obj) {
+ return nullptr;
+ }
auto* obj_raw_ty = obj->Type();
auto* obj_ty = obj_raw_ty->UnwrapRef();
auto* ty = Switch(
@@ -1238,13 +1523,17 @@ sem::Expression* Resolver::IndexAccessor(const ast::IndexAccessorExpression* exp
ty = builder_->create<sem::Reference>(ty, ref->StorageClass(), ref->Access());
}
- auto val = EvaluateConstantValue(expr, ty);
- if (!val) {
+ auto stage = sem::EarliestStage(obj->Stage(), idx->Stage());
+ const sem::Constant* val = nullptr;
+ if (auto r = const_eval_.Index(obj, idx)) {
+ val = r.Get();
+ } else {
return nullptr;
}
bool has_side_effects = idx->HasSideEffects() || obj->HasSideEffects();
- auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_, val.Get(),
- has_side_effects, obj->SourceVariable());
+ auto* sem = builder_->create<sem::IndexAccessorExpression>(
+ expr, ty, stage, obj, idx, current_statement_, std::move(val), has_side_effects,
+ obj->SourceVariable());
sem->Behaviors() = idx->Behaviors() + obj->Behaviors();
return sem;
}
@@ -1259,12 +1548,15 @@ sem::Expression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
return nullptr;
}
- auto val = EvaluateConstantValue(expr, ty);
- if (!val) {
+ const sem::Constant* val = nullptr;
+ if (auto r = const_eval_.Bitcast(ty, inner)) {
+ val = r.Get();
+ } else {
return nullptr;
}
- auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_, val.Get(),
- inner->HasSideEffects());
+ auto stage = sem::EvaluationStage::kRuntime; // TODO(crbug.com/tint/1581)
+ auto* sem = builder_->create<sem::Expression>(expr, ty, stage, current_statement_,
+ std::move(val), inner->HasSideEffects());
sem->Behaviors() = inner->Behaviors();
@@ -1283,14 +1575,17 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
// * A type conversion.
// Resolve all of the arguments, their types and the set of behaviors.
- std::vector<const sem::Expression*> args(expr->args.size());
+ utils::Vector<const sem::Expression*, 8> args;
+ args.Reserve(expr->args.Length());
+ auto args_stage = sem::EvaluationStage::kConstant;
sem::Behaviors arg_behaviors;
- for (size_t i = 0; i < expr->args.size(); i++) {
+ for (size_t i = 0; i < expr->args.Length(); i++) {
auto* arg = sem_.Get(expr->args[i]);
if (!arg) {
return nullptr;
}
- args[i] = arg;
+ args.Push(arg);
+ args_stage = sem::EarliestStage(args_stage, arg->Stage());
arg_behaviors.Add(arg->Behaviors());
}
arg_behaviors.Remove(sem::Behavior::kNext);
@@ -1303,22 +1598,60 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
// call for a CtorConvIntrinsic with an optional template argument type.
auto ct_ctor_or_conv = [&](CtorConvIntrinsic ty, const sem::Type* template_arg) -> sem::Call* {
auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); });
- auto* call_target = intrinsic_table_->Lookup(ty, template_arg, arg_tys, expr->source);
- if (!call_target) {
+ auto ctor_or_conv = intrinsic_table_->Lookup(ty, template_arg, arg_tys, expr->source);
+ if (!ctor_or_conv.target) {
return nullptr;
}
- if (!MaterializeArguments(args, call_target)) {
+ if (!MaterializeArguments(args, ctor_or_conv.target)) {
return nullptr;
}
- auto val = EvaluateConstantValue(expr, call_target->ReturnType());
- if (!val) {
+ const sem::Constant* value = nullptr;
+ auto stage = sem::EarliestStage(ctor_or_conv.target->Stage(), args_stage);
+ if (stage == sem::EvaluationStage::kConstant) {
+ auto const_args =
+ utils::Transform(args, [](auto* arg) { return arg->ConstantValue(); });
+ if (auto r = (const_eval_.*ctor_or_conv.const_eval_fn)(
+ ctor_or_conv.target->ReturnType(), const_args, expr->source)) {
+ value = r.Get();
+ } else {
+ return nullptr;
+ }
+ }
+ return builder_->create<sem::Call>(expr, ctor_or_conv.target, stage, std::move(args),
+ current_statement_, value, has_side_effects);
+ };
+
+ // arr_or_str_ctor is a helper for building a sem::TypeConstructor for an array or structure
+ // constructor call target.
+ auto arr_or_str_ctor = [&](const sem::Type* ty,
+ const sem::CallTarget* call_target) -> sem::Call* {
+ if (!MaterializeArguments(args, call_target)) {
return nullptr;
}
- return builder_->create<sem::Call>(expr, call_target, std::move(args), current_statement_,
- val.Get(), has_side_effects);
+
+ auto stage = args_stage; // The evaluation stage of the call
+ const sem::Constant* value = nullptr; // The constant value for the call
+ if (stage == sem::EvaluationStage::kConstant) {
+ if (auto r = const_eval_.ArrayOrStructCtor(ty, args)) {
+ value = r.Get();
+ } else {
+ return nullptr;
+ }
+ if (!value) {
+ // Constant evaluation failed.
+ // Can happen for expressions that will fail validation (later).
+ // Use the kRuntime EvaluationStage, as kConstant will trigger an assertion in the
+ // sem::Expression constructor, which checks that kConstant is paired with a
+ // constant value.
+ stage = sem::EvaluationStage::kRuntime;
+ }
+ }
+
+ return builder_->create<sem::Call>(expr, call_target, stage, std::move(args),
+ current_statement_, value, has_side_effects);
};
- // ct_ctor_or_conv is a helper for building either a sem::TypeConstructor or sem::TypeConversion
+ // ty_ctor_or_conv is a helper for building either a sem::TypeConstructor or sem::TypeConversion
// call for the given semantic type.
auto ty_ctor_or_conv = [&](const sem::Type* ty) {
return Switch(
@@ -1331,39 +1664,43 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
},
[&](const sem::I32*) { return ct_ctor_or_conv(CtorConvIntrinsic::kI32, nullptr); },
[&](const sem::U32*) { return ct_ctor_or_conv(CtorConvIntrinsic::kU32, nullptr); },
+ [&](const sem::F16*) { return ct_ctor_or_conv(CtorConvIntrinsic::kF16, nullptr); },
[&](const sem::F32*) { return ct_ctor_or_conv(CtorConvIntrinsic::kF32, nullptr); },
[&](const sem::Bool*) { return ct_ctor_or_conv(CtorConvIntrinsic::kBool, nullptr); },
[&](const sem::Array* arr) -> sem::Call* {
auto* call_target = utils::GetOrCreate(
- array_ctors_, ArrayConstructorSig{{arr, args.size()}},
+ array_ctors_, ArrayConstructorSig{{arr, args.Length(), args_stage}},
[&]() -> sem::TypeConstructor* {
- sem::ParameterList params(args.size());
- for (size_t i = 0; i < args.size(); i++) {
- params[i] = builder_->create<sem::Parameter>(
+ auto params = utils::Transform(args, [&](auto, size_t i) {
+ return builder_->create<sem::Parameter>(
nullptr, // declaration
static_cast<uint32_t>(i), // index
arr->ElemType(), // type
ast::StorageClass::kNone, // storage_class
- ast::Access::kUndefined); // access
- }
- return builder_->create<sem::TypeConstructor>(arr, std::move(params));
+ ast::Access::kUndefined);
+ });
+ return builder_->create<sem::TypeConstructor>(arr, std::move(params),
+ args_stage);
});
- if (!MaterializeArguments(args, call_target)) {
+
+ auto* call = arr_or_str_ctor(arr, call_target);
+ if (!call) {
return nullptr;
}
- auto val = EvaluateConstantValue(expr, call_target->ReturnType());
- if (!val) {
+
+ // Validation must occur after argument materialization in arr_or_str_ctor().
+ if (!validator_.ArrayConstructor(expr, arr)) {
return nullptr;
}
- return builder_->create<sem::Call>(expr, call_target, std::move(args),
- current_statement_, val.Get(), has_side_effects);
+ return call;
},
[&](const sem::Struct* str) -> sem::Call* {
auto* call_target = utils::GetOrCreate(
- struct_ctors_, StructConstructorSig{{str, args.size()}},
+ struct_ctors_, StructConstructorSig{{str, args.Length(), args_stage}},
[&]() -> sem::TypeConstructor* {
- sem::ParameterList params(std::min(args.size(), str->Members().size()));
- for (size_t i = 0, n = params.size(); i < n; i++) {
+ utils::Vector<const sem::Parameter*, 8> params;
+ params.Resize(std::min(args.Length(), str->Members().size()));
+ for (size_t i = 0, n = params.Length(); i < n; i++) {
params[i] = builder_->create<sem::Parameter>(
nullptr, // declaration
static_cast<uint32_t>(i), // index
@@ -1371,17 +1708,20 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
ast::StorageClass::kNone, // storage_class
ast::Access::kUndefined); // access
}
- return builder_->create<sem::TypeConstructor>(str, std::move(params));
+ return builder_->create<sem::TypeConstructor>(str, std::move(params),
+ args_stage);
});
- if (!MaterializeArguments(args, call_target)) {
+
+ auto* call = arr_or_str_ctor(str, call_target);
+ if (!call) {
return nullptr;
}
- auto val = EvaluateConstantValue(expr, call_target->ReturnType());
- if (!val) {
+
+ // Validation must occur after argument materialization in arr_or_str_ctor().
+ if (!validator_.StructureConstructor(expr, str)) {
return nullptr;
}
- return builder_->create<sem::Call>(expr, call_target, std::move(args),
- current_statement_, val.Get(), has_side_effects);
+ return call;
},
[&](Default) {
AddError("type is not constructible", expr->source);
@@ -1429,6 +1769,59 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
}
return nullptr;
},
+ [&](const ast::Array* a) -> sem::Call* {
+ Mark(a);
+ // array element type must be inferred if it was not specified.
+ auto el_count = static_cast<uint32_t>(args.Length());
+ const sem::Type* el_ty = nullptr;
+ if (a->type) {
+ el_ty = Type(a->type);
+ if (!el_ty) {
+ return nullptr;
+ }
+ if (!a->count) {
+ AddError("cannot construct a runtime-sized array", expr->source);
+ return nullptr;
+ }
+ if (auto count = ArrayCount(a->count)) {
+ el_count = count.Get();
+ } else {
+ return nullptr;
+ }
+ // Note: validation later will detect any mismatches between explicit array
+ // size and number of constructor expressions.
+ } else {
+ auto arg_tys =
+ utils::Transform(args, [](auto* arg) { return arg->Type()->UnwrapRef(); });
+ el_ty = sem::Type::Common(arg_tys);
+ if (!el_ty) {
+ AddError(
+ "cannot infer common array element type from constructor arguments",
+ expr->source);
+ std::unordered_set<const sem::Type*> types;
+ for (size_t i = 0; i < args.Length(); i++) {
+ if (types.emplace(args[i]->Type()).second) {
+ AddNote("argument " + std::to_string(i) + " is of type '" +
+ sem_.TypeNameOf(args[i]->Type()) + "'",
+ args[i]->Declaration()->source);
+ }
+ }
+ return nullptr;
+ }
+ }
+ uint32_t explicit_stride = 0;
+ if (!ArrayAttributes(a->attributes, el_ty, explicit_stride)) {
+ return nullptr;
+ }
+
+ auto* arr = Array(a->source, el_ty, el_count, explicit_stride);
+ if (!arr) {
+ return nullptr;
+ }
+ builder_->Sem().Add(a, arr);
+
+ return ty_ctor_or_conv(arr);
+ },
[&](const ast::Type* ast) -> sem::Call* {
// Handler for AST types that do not have an optional element type.
if (auto* ty = Type(ast)) {
@@ -1458,9 +1851,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
// there's no need to infer element types.
return ty_ctor_or_conv(ty);
},
- [&](sem::Function* func) {
- return FunctionCall(expr, func, std::move(args), arg_behaviors);
- },
+ [&](sem::Function* func) { return FunctionCall(expr, func, args, arg_behaviors); },
[&](sem::Variable* var) {
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
AddError("cannot call variable '" + name + "'", ident->source);
@@ -1471,7 +1862,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
auto name = builder_->Symbols().NameFor(ident->symbol);
auto builtin_type = sem::ParseBuiltinType(name);
if (builtin_type != sem::BuiltinType::kNone) {
- return BuiltinCall(expr, builtin_type, std::move(args));
+ return BuiltinCall(expr, builtin_type, args);
}
TINT_ICE(Resolver, diagnostics_)
@@ -1489,9 +1880,10 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
return validator_.Call(call, current_statement_) ? call : nullptr;
}
+template <size_t N>
sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
sem::BuiltinType builtin_type,
- std::vector<const sem::Expression*> args) {
+ utils::Vector<const sem::Expression*, N>& args) {
IntrinsicTable::Builtin builtin;
{
auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); });
@@ -1509,31 +1901,43 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
AddWarning("use of deprecated builtin", expr->source);
}
+ auto stage = builtin.sem->Stage();
+ if (stage == sem::EvaluationStage::kConstant) { // <-- Optimization
+ // If the builtin is not annotated with @const, then it can only be evaluated
+ // at runtime, in which case there's no point checking the evaluation stage of the
+ // arguments.
+
+ // The builtin is @const annotated. Check all arguments are also constant.
+ for (auto* arg : args) {
+ stage = sem::EarliestStage(stage, arg->Stage());
+ }
+ }
+
// If the builtin is @const, and all arguments have constant values, evaluate the builtin now.
- sem::Constant constant;
- if (builtin.const_eval_fn) {
- std::vector<sem::Constant> values(args.size());
- bool is_const = true; // all arguments have constant values
- for (size_t i = 0; i < values.size(); i++) {
- if (auto v = args[i]->ConstantValue()) {
- values[i] = std::move(v);
- } else {
- is_const = false;
- break;
- }
+ const sem::Constant* value = nullptr;
+ if (stage == sem::EvaluationStage::kConstant) {
+ auto const_args = ConvertArguments(args, builtin.sem);
+ if (!const_args) {
+ return nullptr;
}
- if (is_const) {
- constant = builtin.const_eval_fn(*builder_, values.data(), args.size());
+ if (auto r = (const_eval_.*builtin.const_eval_fn)(builtin.sem->ReturnType(),
+ const_args.Get(), expr->source)) {
+ value = r.Get();
+ } else {
+ return nullptr;
}
}
bool has_side_effects =
builtin.sem->HasSideEffects() ||
std::any_of(args.begin(), args.end(), [](auto* e) { return e->HasSideEffects(); });
- auto* call = builder_->create<sem::Call>(expr, builtin.sem, std::move(args), current_statement_,
- constant, has_side_effects);
+ auto* call = builder_->create<sem::Call>(expr, builtin.sem, stage, std::move(args),
+ current_statement_, value, has_side_effects);
- current_function_->AddDirectlyCalledBuiltin(builtin.sem);
+ if (current_function_) {
+ current_function_->AddDirectlyCalledBuiltin(builtin.sem);
+ current_function_->AddDirectCall(call);
+ }
if (!validator_.RequiredExtensionForBuiltinFunction(call, enabled_extensions_)) {
return nullptr;
@@ -1550,32 +1954,32 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
return nullptr;
}
- current_function_->AddDirectCall(call);
-
return call;
}
void Resolver::CollectTextureSamplerPairs(const sem::Builtin* builtin,
- const std::vector<const sem::Expression*>& args) const {
+ utils::VectorRef<const sem::Expression*> args) const {
// Collect a texture/sampler pair for this builtin.
const auto& signature = builtin->Signature();
int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
if (texture_index == -1) {
TINT_ICE(Resolver, diagnostics_) << "texture builtin without texture parameter";
}
- auto* texture = args[texture_index]->As<sem::VariableUser>()->Variable();
+ auto* texture = args[static_cast<size_t>(texture_index)]->As<sem::VariableUser>()->Variable();
if (!texture->Type()->UnwrapRef()->Is<sem::StorageTexture>()) {
int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
const sem::Variable* sampler =
- sampler_index != -1 ? args[sampler_index]->As<sem::VariableUser>()->Variable()
- : nullptr;
+ sampler_index != -1
+ ? args[static_cast<size_t>(sampler_index)]->As<sem::VariableUser>()->Variable()
+ : nullptr;
current_function_->AddTextureSamplerPair(texture, sampler);
}
}
+template <size_t N>
sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
sem::Function* target,
- std::vector<const sem::Expression*> args,
+ utils::Vector<const sem::Expression*, N>& args,
sem::Behaviors arg_behaviors) {
auto sym = expr->target.name->symbol;
auto name = builder_->Symbols().NameFor(sym);
@@ -1587,8 +1991,9 @@ sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
// TODO(crbug.com/tint/1420): For now, assume all function calls have side
// effects.
bool has_side_effects = true;
- auto* call = builder_->create<sem::Call>(expr, target, std::move(args), current_statement_,
- sem::Constant{}, has_side_effects);
+ auto* call = builder_->create<sem::Call>(expr, target, sem::EvaluationStage::kRuntime,
+ std::move(args), current_statement_,
+ /* constant_value */ nullptr, has_side_effects);
target->AddCallSite(call);
@@ -1621,7 +2026,7 @@ sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
}
void Resolver::CollectTextureSamplerPairs(sem::Function* func,
- const std::vector<const sem::Expression*>& args) const {
+ utils::VectorRef<const sem::Expression*> args) const {
// Map all texture/sampler pairs from the target function to the
// current function. These can only be global or parameter
// variables. Resolve any parameter variables to the corresponding
@@ -1658,10 +2063,15 @@ sem::Expression* Resolver::Literal(const ast::LiteralExpression* literal) {
return nullptr;
},
[&](const ast::FloatLiteralExpression* f) -> sem::Type* {
- if (f->suffix == ast::FloatLiteralExpression::Suffix::kNone) {
- return builder_->create<sem::AbstractFloat>();
+ switch (f->suffix) {
+ case ast::FloatLiteralExpression::Suffix::kNone:
+ return builder_->create<sem::AbstractFloat>();
+ case ast::FloatLiteralExpression::Suffix::kF:
+ return builder_->create<sem::F32>();
+ case ast::FloatLiteralExpression::Suffix::kH:
+ return builder_->create<sem::F16>();
}
- return builder_->create<sem::F32>();
+ return nullptr;
},
[&](const ast::BoolLiteralExpression*) { return builder_->create<sem::Bool>(); },
[&](Default) { return nullptr; });
@@ -1672,19 +2082,27 @@ sem::Expression* Resolver::Literal(const ast::LiteralExpression* literal) {
return nullptr;
}
- auto val = EvaluateConstantValue(literal, ty);
- if (!val) {
+ if ((ty->Is<sem::F16>()) && (!enabled_extensions_.Contains(tint::ast::Extension::kF16))) {
+ AddError("f16 literal used without 'f16' extension enabled", literal->source);
+ return nullptr;
+ }
+
+ const sem::Constant* val = nullptr;
+ if (auto r = const_eval_.Literal(ty, literal)) {
+ val = r.Get();
+ } else {
return nullptr;
}
- return builder_->create<sem::Expression>(literal, ty, current_statement_, val.Get(),
+ return builder_->create<sem::Expression>(literal, ty, sem::EvaluationStage::kConstant,
+ current_statement_, std::move(val),
/* has_side_effects */ false);
}
sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
auto symbol = expr->symbol;
auto* resolved = sem_.ResolvedSymbol(expr);
- if (auto* var = As<sem::Variable>(resolved)) {
- auto* user = builder_->create<sem::VariableUser>(expr, current_statement_, var);
+ if (auto* variable = As<sem::Variable>(resolved)) {
+ auto* user = builder_->create<sem::VariableUser>(expr, current_statement_, variable);
if (current_statement_) {
// If identifier is part of a loop continuing block, make sure it
@@ -1720,12 +2138,20 @@ sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
}
if (current_function_) {
- if (auto* global = var->As<sem::GlobalVariable>()) {
+ if (auto* global = variable->As<sem::GlobalVariable>()) {
current_function_->AddDirectlyReferencedGlobal(global);
}
+ } else if (variable->Declaration()->Is<ast::Var>()) {
+ // Use of a module-scope 'var' outside of a function.
+ // Note: The spec is currently vague around the rules here. See
+ // https://github.com/gpuweb/gpuweb/issues/3081. Remove this comment when resolved.
+ std::string desc = "var '" + builder_->Symbols().NameFor(symbol) + "' ";
+ AddError(desc + "cannot not be referenced at module-scope", expr->source);
+ AddNote(desc + "declared here", variable->Declaration()->source);
+ return nullptr;
}
- var->AddUser(user);
+ variable->AddUser(user);
return user;
}
@@ -1754,14 +2180,14 @@ sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
sem::Expression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* expr) {
auto* structure = sem_.TypeOf(expr->structure);
auto* storage_ty = structure->UnwrapRef();
- auto* source_var = sem_.Get(expr->structure)->SourceVariable();
+ auto* object = sem_.Get(expr->structure);
+ auto* source_var = object->SourceVariable();
const sem::Type* ret = nullptr;
- std::vector<uint32_t> swizzle;
+ utils::Vector<uint32_t, 4> swizzle;
- // Structure may be a side-effecting expression (e.g. function call).
- auto* sem_structure = sem_.Get(expr->structure);
- bool has_side_effects = sem_structure && sem_structure->HasSideEffects();
+ // Object may be a side-effecting expression (e.g. function call).
+ bool has_side_effects = object && object->HasSideEffects();
if (auto* str = storage_ty->As<sem::Struct>()) {
Mark(expr->member);
@@ -1787,41 +2213,47 @@ sem::Expression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* e
ret = builder_->create<sem::Reference>(ret, ref->StorageClass(), ref->Access());
}
- return builder_->create<sem::StructMemberAccess>(expr, ret, current_statement_, member,
- has_side_effects, source_var);
+ const sem::Constant* val = nullptr;
+ if (auto r = const_eval_.MemberAccess(object, member)) {
+ val = r.Get();
+ } else {
+ return nullptr;
+ }
+ return builder_->create<sem::StructMemberAccess>(expr, ret, current_statement_, val, object,
+ member, has_side_effects, source_var);
}
if (auto* vec = storage_ty->As<sem::Vector>()) {
Mark(expr->member);
std::string s = builder_->Symbols().NameFor(expr->member->symbol);
auto size = s.size();
- swizzle.reserve(s.size());
+ swizzle.Reserve(s.size());
for (auto c : s) {
switch (c) {
case 'x':
case 'r':
- swizzle.emplace_back(0);
+ swizzle.Push(0u);
break;
case 'y':
case 'g':
- swizzle.emplace_back(1);
+ swizzle.Push(1u);
break;
case 'z':
case 'b':
- swizzle.emplace_back(2);
+ swizzle.Push(2u);
break;
case 'w':
case 'a':
- swizzle.emplace_back(3);
+ swizzle.Push(3u);
break;
default:
AddError("invalid vector swizzle character",
- expr->member->source.Begin() + swizzle.size());
+ expr->member->source.Begin() + swizzle.Length());
return nullptr;
}
- if (swizzle.back() >= vec->Width()) {
+ if (swizzle.Back() >= vec->Width()) {
AddError("invalid vector swizzle member", expr->member->source);
return nullptr;
}
@@ -1854,8 +2286,12 @@ sem::Expression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* e
// the swizzle.
ret = builder_->create<sem::Vector>(vec->type(), static_cast<uint32_t>(size));
}
- return builder_->create<sem::Swizzle>(expr, ret, current_statement_, std::move(swizzle),
- has_side_effects, source_var);
+ if (auto r = const_eval_.Swizzle(ret, object, swizzle)) {
+ auto* val = r.Get();
+ return builder_->create<sem::Swizzle>(expr, ret, current_statement_, val, object,
+ std::move(swizzle), has_side_effects, source_var);
+ }
+ return nullptr;
}
AddError("invalid member accessor expression. Expected vector or struct, got '" +
@@ -1887,12 +2323,31 @@ sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) {
}
}
- auto val = EvaluateConstantValue(expr, op.result);
- if (!val) {
- return nullptr;
+ const sem::Constant* value = nullptr;
+ auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage());
+ if (stage == sem::EvaluationStage::kConstant) {
+ if (op.const_eval_fn) {
+ auto const_args = utils::Vector{lhs->ConstantValue(), rhs->ConstantValue()};
+ // Implicit conversion (e.g. AInt -> AFloat)
+ if (!Convert(const_args[0], op.lhs, lhs->Declaration()->source)) {
+ return nullptr;
+ }
+ if (!Convert(const_args[1], op.rhs, rhs->Declaration()->source)) {
+ return nullptr;
+ }
+
+ if (auto r = (const_eval_.*op.const_eval_fn)(op.result, const_args, expr->source)) {
+ value = r.Get();
+ } else {
+ return nullptr;
+ }
+ } else {
+ stage = sem::EvaluationStage::kRuntime;
+ }
}
+
bool has_side_effects = lhs->HasSideEffects() || rhs->HasSideEffects();
- auto* sem = builder_->create<sem::Expression>(expr, op.result, current_statement_, val.Get(),
+ auto* sem = builder_->create<sem::Expression>(expr, op.result, stage, current_statement_, value,
has_side_effects);
sem->Behaviors() = lhs->Behaviors() + rhs->Behaviors();
@@ -1908,6 +2363,8 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
const sem::Type* ty = nullptr;
const sem::Variable* source_var = nullptr;
+ const sem::Constant* value = nullptr;
+ auto stage = sem::EvaluationStage::kRuntime;
switch (unary->op) {
case ast::UnaryOp::kAddressOf:
@@ -1959,23 +2416,33 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
return nullptr;
}
}
+ stage = expr->Stage();
+ if (stage == sem::EvaluationStage::kConstant) {
+ if (op.const_eval_fn) {
+ if (auto r = (const_eval_.*op.const_eval_fn)(
+ ty, utils::Vector{expr->ConstantValue()},
+ expr->Declaration()->source)) {
+ value = r.Get();
+ } else {
+ return nullptr;
+ }
+ } else {
+ stage = sem::EvaluationStage::kRuntime;
+ }
+ }
ty = op.result;
break;
}
}
- auto val = EvaluateConstantValue(unary, ty);
- if (!val) {
- return nullptr;
- }
- auto* sem = builder_->create<sem::Expression>(unary, ty, current_statement_, val.Get(),
+ auto* sem = builder_->create<sem::Expression>(unary, ty, stage, current_statement_, value,
expr->HasSideEffects(), source_var);
sem->Behaviors() = expr->Behaviors();
return sem;
}
bool Resolver::Enable(const ast::Enable* enable) {
- enabled_extensions_.add(enable->extension);
+ enabled_extensions_.Add(enable->extension);
return true;
}
@@ -1998,129 +2465,128 @@ sem::Type* Resolver::TypeDecl(const ast::TypeDecl* named_type) {
}
sem::Array* Resolver::Array(const ast::Array* arr) {
- auto source = arr->source;
-
- auto* elem_type = Type(arr->type);
- if (!elem_type) {
+ if (!arr->type) {
+ AddError("missing array element type", arr->source.End());
return nullptr;
}
- if (!validator_.IsPlain(elem_type)) { // Check must come before GetDefaultAlignAndSize()
- AddError(sem_.TypeNameOf(elem_type) + " cannot be used as an element type of an array",
- source);
- return nullptr;
- }
-
- uint32_t el_align = elem_type->Align();
- uint32_t el_size = elem_type->Size();
-
- if (!validator_.NoDuplicateAttributes(arr->attributes)) {
+ auto* el_ty = Type(arr->type);
+ if (!el_ty) {
return nullptr;
}
// Look for explicit stride via @stride(n) attribute
uint32_t explicit_stride = 0;
- for (auto* attr : arr->attributes) {
- Mark(attr);
- if (auto* sd = attr->As<ast::StrideAttribute>()) {
- explicit_stride = sd->stride;
- if (!validator_.ArrayStrideAttribute(sd, el_size, el_align, source)) {
- return nullptr;
- }
- continue;
- }
-
- AddError("attribute is not valid for array types", attr->source);
+ if (!ArrayAttributes(arr->attributes, el_ty, explicit_stride)) {
return nullptr;
}
- // Calculate implicit stride
- uint64_t implicit_stride = utils::RoundUp<uint64_t>(el_align, el_size);
-
- uint64_t stride = explicit_stride ? explicit_stride : implicit_stride;
+ uint32_t el_count = 0; // sem::Array uses a size of 0 for a runtime-sized array.
// Evaluate the constant array size expression.
- // sem::Array uses a size of 0 for a runtime-sized array.
- uint32_t count = 0;
if (auto* count_expr = arr->count) {
- const auto* count_sem = Materialize(Expression(count_expr));
- if (!count_sem) {
+ if (auto count = ArrayCount(count_expr)) {
+ el_count = count.Get();
+ } else {
return nullptr;
}
+ }
- auto size_source = count_expr->source;
+ auto* out = Array(arr->source, el_ty, el_count, explicit_stride);
+ if (out == nullptr) {
+ return nullptr;
+ }
- auto* ty = count_sem->Type()->UnwrapRef();
- if (!ty->is_integer_scalar()) {
- AddError("array size must be integer scalar", size_source);
- return nullptr;
+ if (el_ty->Is<sem::Atomic>()) {
+ atomic_composite_info_.emplace(out, arr->type->source);
+ } else {
+ auto found = atomic_composite_info_.find(el_ty);
+ if (found != atomic_composite_info_.end()) {
+ atomic_composite_info_.emplace(out, found->second);
}
+ }
- if (auto* ident = count_expr->As<ast::IdentifierExpression>()) {
- // Make sure the identifier is a non-overridable module-scope constant.
- auto* var = sem_.ResolvedSymbol<sem::GlobalVariable>(ident);
- if (!var || !var->Declaration()->is_const) {
- AddError("array size identifier must be a module-scope constant", size_source);
- return nullptr;
- }
- if (var->IsOverridable()) {
- AddError("array size expression must not be pipeline-overridable", size_source);
- return nullptr;
- }
+ return out;
+}
- count_expr = var->Declaration()->constructor;
- } else if (!count_expr->Is<ast::LiteralExpression>()) {
- AddError(
- "array size expression must be either a literal or a module-scope "
- "constant",
- size_source);
- return nullptr;
- }
+utils::Result<uint32_t> Resolver::ArrayCount(const ast::Expression* count_expr) {
+ // Evaluate the constant array size expression.
+ const auto* count_sem = Materialize(Expression(count_expr));
+ if (!count_sem) {
+ return utils::Failure;
+ }
- auto count_val = count_sem->ConstantValue();
- if (!count_val) {
- TINT_ICE(Resolver, diagnostics_) << "could not resolve array size expression";
- return nullptr;
- }
+ auto* count_val = count_sem->ConstantValue();
+ if (!count_val) {
+ AddError("array size must evaluate to a constant integer expression", count_expr->source);
+ return utils::Failure;
+ }
- if (count_val.Element<AInt>(0).value < 1) {
- AddError("array size must be at least 1", size_source);
- return nullptr;
+ if (auto* ty = count_val->Type(); !ty->is_integer_scalar()) {
+ AddError("array size must evaluate to a constant integer expression, but is type '" +
+ builder_->FriendlyName(ty) + "'",
+ count_expr->source);
+ return utils::Failure;
+ }
+
+ int64_t count = count_val->As<AInt>();
+ if (count < 1) {
+ AddError("array size (" + std::to_string(count) + ") must be greater than 0",
+ count_expr->source);
+ return utils::Failure;
+ }
+
+ return static_cast<uint32_t>(count);
+}
+
+bool Resolver::ArrayAttributes(utils::VectorRef<const ast::Attribute*> attributes,
+ const sem::Type* el_ty,
+ uint32_t& explicit_stride) {
+ if (!validator_.NoDuplicateAttributes(attributes)) {
+ return false;
+ }
+
+ for (auto* attr : attributes) {
+ Mark(attr);
+ if (auto* sd = attr->As<ast::StrideAttribute>()) {
+ explicit_stride = sd->stride;
+ if (!validator_.ArrayStrideAttribute(sd, el_ty->Size(), el_ty->Align())) {
+ return false;
+ }
+ continue;
}
- count = count_val.Element<uint32_t>(0);
+ AddError("attribute is not valid for array types", attr->source);
+ return false;
}
- auto size = std::max<uint64_t>(count, 1) * stride;
+ return true;
+}
+
+sem::Array* Resolver::Array(const Source& source,
+ const sem::Type* el_ty,
+ uint32_t el_count,
+ uint32_t explicit_stride) {
+ uint32_t el_align = el_ty->Align();
+ uint32_t el_size = el_ty->Size();
+ uint64_t implicit_stride = el_size ? utils::RoundUp<uint64_t>(el_align, el_size) : 0;
+ uint64_t stride = explicit_stride ? explicit_stride : implicit_stride;
+
+ auto size = std::max<uint64_t>(el_count, 1u) * stride;
if (size > std::numeric_limits<uint32_t>::max()) {
std::stringstream msg;
- msg << "array size in bytes must not exceed 0x" << std::hex
- << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex << size;
- AddError(msg.str(), arr->source);
+ msg << "array size (0x" << std::hex << size << ") must not exceed 0xffffffff bytes";
+ AddError(msg.str(), source);
return nullptr;
}
- if (stride > std::numeric_limits<uint32_t>::max() ||
- implicit_stride > std::numeric_limits<uint32_t>::max()) {
- TINT_ICE(Resolver, diagnostics_) << "calculated array stride exceeds uint32";
- return nullptr;
- }
- auto* out = builder_->create<sem::Array>(
- elem_type, count, el_align, static_cast<uint32_t>(size), static_cast<uint32_t>(stride),
- static_cast<uint32_t>(implicit_stride));
+ auto* out = builder_->create<sem::Array>(el_ty, el_count, el_align, static_cast<uint32_t>(size),
+ static_cast<uint32_t>(stride),
+ static_cast<uint32_t>(implicit_stride));
if (!validator_.Array(out, source)) {
return nullptr;
}
- if (elem_type->Is<sem::Atomic>()) {
- atomic_composite_info_.emplace(out, arr->type->source);
- } else {
- auto found = atomic_composite_info_.find(elem_type);
- if (found != atomic_composite_info_.end()) {
- atomic_composite_info_.emplace(out, found->second);
- }
- }
-
return out;
}
@@ -2144,7 +2610,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
}
sem::StructMemberList sem_members;
- sem_members.reserve(str->members.size());
+ sem_members.reserve(str->members.Length());
// Calculate the effective size and alignment of each field, and the overall
// size of the structure.
@@ -2234,8 +2700,8 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
offset = utils::RoundUp(align, offset);
if (offset > std::numeric_limits<uint32_t>::max()) {
std::stringstream msg;
- msg << "struct member has byte offset 0x" << std::hex << offset
- << ", but must not exceed 0x" << std::hex << std::numeric_limits<uint32_t>::max();
+ msg << "struct member offset (0x" << std::hex << offset << ") must not exceed 0x"
+ << std::hex << std::numeric_limits<uint32_t>::max() << " bytes";
AddError(msg.str(), member->source);
return nullptr;
}
@@ -2256,8 +2722,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
if (struct_size > std::numeric_limits<uint32_t>::max()) {
std::stringstream msg;
- msg << "struct size in bytes must not exceed 0x" << std::hex
- << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex << struct_size;
+ msg << "struct size (0x" << std::hex << struct_size << ") must not exceed 0xffffffff bytes";
AddError(msg.str(), str->source);
return nullptr;
}
@@ -2282,6 +2747,8 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
break;
}
}
+
+ const_cast<sem::StructMember*>(sem_members[i])->SetStruct(out);
}
auto stage = current_function_ ? current_function_->Declaration()->PipelineStage()
@@ -2339,11 +2806,11 @@ sem::SwitchStatement* Resolver::SwitchStatement(const ast::SwitchStatement* stmt
auto* cond_ty = cond->Type()->UnwrapRef();
- utils::UniqueVector<const sem::Type*> types;
- types.add(cond_ty);
+ utils::Vector<const sem::Type*, 8> types;
+ types.Push(cond_ty);
- std::vector<sem::CaseStatement*> cases;
- cases.reserve(stmt->body.size());
+ utils::Vector<sem::CaseStatement*, 4> cases;
+ cases.Reserve(stmt->body.Length());
for (auto* case_stmt : stmt->body) {
Mark(case_stmt);
auto* c = CaseStatement(case_stmt);
@@ -2351,16 +2818,16 @@ sem::SwitchStatement* Resolver::SwitchStatement(const ast::SwitchStatement* stmt
return false;
}
for (auto* expr : c->Selectors()) {
- types.add(expr->Type()->UnwrapRef());
+ types.Push(expr->Type()->UnwrapRef());
}
- cases.emplace_back(c);
+ cases.Push(c);
behaviors.Add(c->Behaviors());
sem->Cases().emplace_back(c);
}
// Determine the common type across all selectors and the switch expression
// This must materialize to an integer scalar (non-abstract).
- auto* common_ty = sem::Type::Common(types.data(), types.size());
+ auto* common_ty = sem::Type::Common(types);
if (!common_ty || !common_ty->is_integer_scalar()) {
// No common type found or the common type was abstract.
// Pick i32 and let validation deal with any mismatches.
@@ -2394,8 +2861,8 @@ sem::Statement* Resolver::VariableDeclStatement(const ast::VariableDeclStatement
return StatementScope(stmt, sem, [&] {
Mark(stmt->variable);
- auto* var = Variable(stmt->variable, VariableKind::kLocal);
- if (!var) {
+ auto* variable = Variable(stmt->variable, /* is_global */ false);
+ if (!variable) {
return false;
}
@@ -2411,11 +2878,11 @@ sem::Statement* Resolver::VariableDeclStatement(const ast::VariableDeclStatement
current_block_->AddDecl(stmt->variable);
}
- if (auto* ctor = var->Constructor()) {
+ if (auto* ctor = variable->Constructor()) {
sem->Behaviors() = ctor->Behaviors();
}
- return validator_.Variable(var);
+ return validator_.LocalVariable(variable);
});
}
@@ -2568,7 +3035,7 @@ bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
str->AddUsage(sc);
for (auto* member : str->Members()) {
- if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
+ if (!ApplyStorageClassUsageToType(sc, const_cast<sem::Type*>(member->Type()), usage)) {
std::stringstream err;
err << "while analysing structure member " << sem_.TypeNameOf(str) << "."
<< builder_->Symbols().NameFor(member->Declaration()->symbol);
@@ -2626,7 +3093,9 @@ bool Resolver::Mark(const ast::Node* node) {
TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr";
return false;
}
- if (marked_.emplace(node).second) {
+ auto marked_bit_ref = marked_[node->node_id.value];
+ if (!marked_bit_ref) {
+ marked_bit_ref = true;
return true;
}
TINT_ICE(Resolver, diagnostics_) << "AST node '" << node->TypeInfo().name
diff --git a/chromium/third_party/dawn/src/tint/resolver/resolver.h b/chromium/third_party/dawn/src/tint/resolver/resolver.h
index 99996517d74..4c61c47fe0c 100644
--- a/chromium/third_party/dawn/src/tint/resolver/resolver.h
+++ b/chromium/third_party/dawn/src/tint/resolver/resolver.h
@@ -24,6 +24,7 @@
#include <vector>
#include "src/tint/program_builder.h"
+#include "src/tint/resolver/const_eval.h"
#include "src/tint/resolver/dependency_graph.h"
#include "src/tint/resolver/intrinsic_table.h"
#include "src/tint/resolver/sem_helper.h"
@@ -34,7 +35,7 @@
#include "src/tint/sem/constant.h"
#include "src/tint/sem/function.h"
#include "src/tint/sem/struct.h"
-#include "src/tint/utils/result.h"
+#include "src/tint/utils/bitset.h"
#include "src/tint/utils/unique_vector.h"
// Forward declarations
@@ -54,6 +55,7 @@ class ReturnStatement;
class SwitchStatement;
class UnaryOpExpression;
class Variable;
+class WhileStatement;
} // namespace tint::ast
namespace tint::sem {
class Array;
@@ -65,8 +67,10 @@ class ForLoopStatement;
class IfStatement;
class LoopStatement;
class Statement;
+class StructMember;
class SwitchStatement;
class TypeConstructor;
+class WhileStatement;
} // namespace tint::sem
namespace tint::resolver {
@@ -107,9 +111,6 @@ class Resolver {
const Validator* GetValidatorForTesting() const { return &validator_; }
private:
- /// Describes the context in which a variable is declared
- enum class VariableKind { kParameter, kLocal, kGlobal };
-
Validator::ValidTypeStorageLayouts valid_type_storage_layouts_;
/// Structure holding semantic information about a block (i.e. scope), such as
@@ -159,39 +160,36 @@ class Resolver {
/// ProgramBuilder.
void CreateSemanticNodes() const;
- /// Retrieves information for the requested import.
- /// @param src the source of the import
- /// @param path the import path
- /// @param name the method name to get information on
- /// @param params the parameters to the method call
- /// @param id out parameter for the external call ID. Must not be a nullptr.
- /// @returns the return type of `name` in `path` or nullptr on error.
- sem::Type* GetImportData(const Source& src,
- const std::string& path,
- const std::string& name,
- const ast::ExpressionList& params,
- uint32_t* id);
-
- //////////////////////////////////////////////////////////////////////////////
- // AST and Type traversal methods
- //////////////////////////////////////////////////////////////////////////////
+ /// Expression traverses the graph of expressions starting at `expr`, building a postordered
+ /// list (leaf-first) of all the expression nodes. Each of the expressions are then resolved by
+ /// dispatching to the appropriate expression handlers below.
+ /// @returns the resolved semantic node for the expression `expr`, or nullptr on failure.
+ sem::Expression* Expression(const ast::Expression* expr);
+ ////////////////////////////////////////////////////////////////////////////////////////////////
// Expression resolving methods
+ //
// Returns the semantic node pointer on success, nullptr on failure.
+ //
+ // These methods are invoked by Expression(), in postorder (child-first). These methods should
+ // not attempt to resolve their children. This design avoids recursion, which is a common cause
+ // of stack-overflows.
+ ////////////////////////////////////////////////////////////////////////////////////////////////
sem::Expression* IndexAccessor(const ast::IndexAccessorExpression*);
sem::Expression* Binary(const ast::BinaryExpression*);
sem::Expression* Bitcast(const ast::BitcastExpression*);
sem::Call* Call(const ast::CallExpression*);
- sem::Expression* Expression(const ast::Expression*);
sem::Function* Function(const ast::Function*);
+ template <size_t N>
sem::Call* FunctionCall(const ast::CallExpression*,
sem::Function* target,
- std::vector<const sem::Expression*> args,
+ utils::Vector<const sem::Expression*, N>& args,
sem::Behaviors arg_behaviors);
sem::Expression* Identifier(const ast::IdentifierExpression*);
+ template <size_t N>
sem::Call* BuiltinCall(const ast::CallExpression*,
sem::BuiltinType,
- std::vector<const sem::Expression*> args);
+ utils::Vector<const sem::Expression*, N>& args);
sem::Expression* Literal(const ast::LiteralExpression*);
sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
@@ -214,13 +212,36 @@ class Resolver {
/// Materializes all the arguments in `args` to the parameter types of `target`.
/// @returns true on success, false on failure.
- bool MaterializeArguments(std::vector<const sem::Expression*>& args,
+ template <size_t N>
+ bool MaterializeArguments(utils::Vector<const sem::Expression*, N>& args,
const sem::CallTarget* target);
/// @returns true if an argument of an abstract numeric type, passed to a parameter of type
/// `parameter_ty` should be materialized.
bool ShouldMaterializeArgument(const sem::Type* parameter_ty) const;
+ /// Converts `c` to `target_ty`
+ /// @returns true on success, false on failure.
+ bool Convert(const sem::Constant*& c, const sem::Type* target_ty, const Source& source);
+
+ /// Transforms `args` to a vector of constants, and converts each constant to the call target's
+ /// parameter type.
+ /// @returns the vector of constants, `utils::Failure` on failure.
+ template <size_t N>
+ utils::Result<utils::Vector<const sem::Constant*, N>> ConvertArguments(
+ const utils::Vector<const sem::Expression*, N>& args,
+ const sem::CallTarget* target);
+
+ /// @param ty the type that may hold abstract numeric types
+ /// @param target_ty the target type for the expression (variable type, parameter type, etc).
+ /// May be nullptr.
+ /// @param source the source of the expression requiring materialization
+ /// @returns the concrete (materialized) type for the given type, or nullptr if the type is
+ /// already concrete.
+ const sem::Type* ConcreteType(const sem::Type* ty,
+ const sem::Type* target_ty,
+ const Source& source);
+
// Statement resolving methods
// Each return true on success, false on failure.
sem::Statement* AssignmentStatement(const ast::AssignmentStatement*);
@@ -233,6 +254,7 @@ class Resolver {
sem::Statement* DiscardStatement(const ast::DiscardStatement*);
sem::Statement* FallthroughStatement(const ast::FallthroughStatement*);
sem::ForLoopStatement* ForLoopStatement(const ast::ForLoopStatement*);
+ sem::WhileStatement* WhileStatement(const ast::WhileStatement*);
sem::GlobalVariable* GlobalVariable(const ast::Variable*);
sem::Statement* Parameter(const ast::Variable*);
sem::IfStatement* IfStatement(const ast::IfStatement*);
@@ -240,16 +262,17 @@ class Resolver {
sem::LoopStatement* LoopStatement(const ast::LoopStatement*);
sem::Statement* ReturnStatement(const ast::ReturnStatement*);
sem::Statement* Statement(const ast::Statement*);
+ sem::Statement* StaticAssert(const ast::StaticAssert*);
sem::SwitchStatement* SwitchStatement(const ast::SwitchStatement* s);
sem::Statement* VariableDeclStatement(const ast::VariableDeclStatement*);
- bool Statements(const ast::StatementList&);
+ bool Statements(utils::VectorRef<const ast::Statement*>);
// CollectTextureSamplerPairs() collects all the texture/sampler pairs from the target function
// / builtin, and records these on the current function by calling AddTextureSamplerPair().
void CollectTextureSamplerPairs(sem::Function* func,
- const std::vector<const sem::Expression*>& args) const;
+ utils::VectorRef<const sem::Expression*> args) const;
void CollectTextureSamplerPairs(const sem::Builtin* builtin,
- const std::vector<const sem::Expression*>& args) const;
+ utils::VectorRef<const sem::Expression*> args) const;
/// Resolves the WorkgroupSize for the given function, assigning it to
/// current_function_
@@ -269,14 +292,38 @@ class Resolver {
/// @returns the resolved semantic type
sem::Type* TypeDecl(const ast::TypeDecl* named_type);
- /// Builds and returns the semantic information for the array `arr`.
- /// This method does not mark the ast::Array node, nor attach the generated
- /// semantic information to the AST node.
- /// @returns the semantic Array information, or nullptr if an error is
- /// raised.
+ /// Builds and returns the semantic information for the AST array `arr`.
+ /// This method does not mark the ast::Array node, nor attach the generated semantic information
+ /// to the AST node.
+ /// @returns the semantic Array information, or nullptr if an error is raised.
/// @param arr the Array to get semantic information for
sem::Array* Array(const ast::Array* arr);
+ /// Resolves and validates the expression used as the count parameter of an array.
+ /// @param count_expr the expression used as the second template parameter to an array<>.
+ /// @returns the number of elements in the array.
+ utils::Result<uint32_t> ArrayCount(const ast::Expression* count_expr);
+
+ /// Resolves and validates the attributes on an array.
+ /// @param attributes the attributes on the array type.
+ /// @param el_ty the element type of the array.
+ /// @param explicit_stride assigned the specified stride of the array in bytes.
+ /// @returns true on success, false on failure
+ bool ArrayAttributes(utils::VectorRef<const ast::Attribute*> attributes,
+ const sem::Type* el_ty,
+ uint32_t& explicit_stride);
+
+ /// Builds and returns the semantic information for an array.
+ /// @returns the semantic Array information, or nullptr if an error is raised.
+ /// @param source the source of the array declaration
+ /// @param el_ty the Array element type
+ /// @param el_count the number of elements in the array. Zero means runtime-sized.
+ /// @param explicit_stride the explicit byte stride of the array. Zero means implicit stride.
+ sem::Array* Array(const Source& source,
+ const sem::Type* el_ty,
+ uint32_t el_count,
+ uint32_t explicit_stride);
+
/// Builds and returns the semantic information for the alias `alias`.
/// This method does not mark the ast::Alias node, nor attach the generated
/// semantic information to the AST node.
@@ -290,14 +337,51 @@ class Resolver {
/// raised.
sem::Struct* Structure(const ast::Struct* str);
- /// @returns the semantic info for the variable `var`. If an error is
- /// raised, nullptr is returned.
- /// @note this method does not resolve the attributes as these are
- /// context-dependent (global, local, parameter)
- /// @param var the variable to create or return the `VariableInfo` for
- /// @param kind what kind of variable we are declaring
- /// @param index the index of the parameter, if this variable is a parameter
- sem::Variable* Variable(const ast::Variable* var, VariableKind kind, uint32_t index = 0);
+ /// @returns the semantic info for the variable `v`. If an error is raised, nullptr is
+ /// returned.
+ /// @note this method does not resolve the attributes as these are context-dependent (global,
+ /// local)
+ /// @param var the variable
+ /// @param is_global true if this is module scope, otherwise function scope
+ sem::Variable* Variable(const ast::Variable* var, bool is_global);
+
+ /// @returns the semantic info for the `ast::Let` `v`. If an error is raised, nullptr is
+ /// returned.
+ /// @note this method does not resolve the attributes as these are context-dependent (global,
+ /// local)
+ /// @param var the variable
+ /// @param is_global true if this is module scope, otherwise function scope
+ sem::Variable* Let(const ast::Let* var, bool is_global);
+
+ /// @returns the semantic info for the module-scope `ast::Override` `v`. If an error is raised,
+ /// nullptr is returned.
+ /// @note this method does not resolve the attributes as these are context-dependent (global,
+ /// local)
+ /// @param override the variable
+ sem::Variable* Override(const ast::Override* override);
+
+ /// @returns the semantic info for an `ast::Const` `v`. If an error is raised, nullptr is
+ /// returned.
+ /// @note this method does not resolve the attributes as these are context-dependent (global,
+ /// local)
+ /// @param const_ the variable
+ /// @param is_global true if this is module scope, otherwise function scope
+ sem::Variable* Const(const ast::Const* const_, bool is_global);
+
+ /// @returns the semantic info for the `ast::Var` `var`. If an error is raised, nullptr is
+ /// returned.
+ /// @note this method does not resolve the attributes as these are context-dependent (global,
+ /// local)
+ /// @param var the variable
+ /// @param is_global true if this is module scope, otherwise function scope
+ sem::Variable* Var(const ast::Var* var, bool is_global);
+
+ /// @returns the semantic info for the function parameter `param`. If an error is raised,
+ /// nullptr is returned.
+ /// @note the caller is expected to validate the parameter
+ /// @param param the AST parameter
+ /// @param index the index of the parameter
+ sem::Parameter* Parameter(const ast::Parameter* param, uint32_t index);
/// Records the storage class usage for the given type, and any transient
/// dependencies of the type. Validates that the type can be used for the
@@ -315,7 +399,8 @@ class Resolver {
ast::Access DefaultAccessForStorageClass(ast::StorageClass storage_class);
/// Allocate constant IDs for pipeline-overridable constants.
- void AllocateOverridableConstantIds();
+ /// @returns true on success, false on error
+ bool AllocateOverridableConstantIds();
/// Set the shadowing information on variable declarations.
/// @note this method must only be called after all semantic nodes are built.
@@ -350,36 +435,23 @@ class Resolver {
/// Adds the given note message to the diagnostics
void AddNote(const std::string& msg, const Source& source) const;
- //////////////////////////////////////////////////////////////////////////////
- /// Constant value evaluation methods
- //////////////////////////////////////////////////////////////////////////////
- /// The result type of a ConstantEvaluation method. Holds the constant value and a boolean,
- /// which is true on success, false on an error.
- using ConstantResult = utils::Result<sem::Constant>;
-
- /// Convert the `value` to `target_type`
- /// @return the converted value
- ConstantResult ConvertValue(const sem::Constant& value,
- const sem::Type* target_type,
- const Source& source);
- ConstantResult EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type);
- ConstantResult EvaluateConstantValue(const ast::LiteralExpression* literal,
- const sem::Type* type);
- ConstantResult EvaluateConstantValue(const ast::CallExpression* call, const sem::Type* type);
-
/// @returns true if the symbol is the name of a builtin function.
bool IsBuiltin(Symbol) const;
// ArrayConstructorSig represents a unique array constructor signature.
- // It is a tuple of the array type and number of arguments provided.
- using ArrayConstructorSig = utils::UnorderedKeyWrapper<std::tuple<const sem::Array*, size_t>>;
+ // It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
+ using ArrayConstructorSig =
+ utils::UnorderedKeyWrapper<std::tuple<const sem::Array*, size_t, sem::EvaluationStage>>;
// StructConstructorSig represents a unique structure constructor signature.
- // It is a tuple of the structure type and number of arguments provided.
- using StructConstructorSig = utils::UnorderedKeyWrapper<std::tuple<const sem::Struct*, size_t>>;
+ // It is a tuple of the structure type, number of arguments provided and earliest evaluation
+ // stage.
+ using StructConstructorSig =
+ utils::UnorderedKeyWrapper<std::tuple<const sem::Struct*, size_t, sem::EvaluationStage>>;
ProgramBuilder* const builder_;
diag::List& diagnostics_;
+ ConstEval const_eval_;
std::unique_ptr<IntrinsicTable> const intrinsic_table_;
DependencyGraph dependencies_;
SemHelper sem_;
@@ -387,8 +459,8 @@ class Resolver {
ast::Extensions enabled_extensions_;
std::vector<sem::Function*> entry_points_;
std::unordered_map<const sem::Type*, const Source&> atomic_composite_info_;
- std::unordered_set<const ast::Node*> marked_;
- std::unordered_map<uint32_t, const sem::Variable*> constant_ids_;
+ utils::Bitset<0> marked_;
+ std::unordered_map<OverrideId, const sem::Variable*> override_ids_;
std::unordered_map<ArrayConstructorSig, sem::CallTarget*> array_ctors_;
std::unordered_map<StructConstructorSig, sem::CallTarget*> struct_ctors_;
diff --git a/chromium/third_party/dawn/src/tint/resolver/resolver_behavior_test.cc b/chromium/third_party/dawn/src/tint/resolver/resolver_behavior_test.cc
index 3a3b14f4c63..43f0bf1660a 100644
--- a/chromium/third_party/dawn/src/tint/resolver/resolver_behavior_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/resolver_behavior_test.cc
@@ -20,6 +20,7 @@
#include "src/tint/sem/for_loop_statement.h"
#include "src/tint/sem/if_statement.h"
#include "src/tint/sem/switch_statement.h"
+#include "src/tint/sem/while_statement.h"
using namespace tint::number_suffixes; // NOLINT
@@ -32,8 +33,8 @@ class ResolverBehaviorTest : public ResolverTest {
// Create a function called 'DiscardOrNext' which returns an i32, and has
// the behavior of {Discard, Return}, which when called, will have the
// behavior {Discard, Next}.
- Func("DiscardOrNext", {}, ty.i32(),
- {
+ Func("DiscardOrNext", utils::Empty, ty.i32(),
+ utils::Vector{
If(true, Block(Discard())),
Return(1_i),
});
@@ -71,8 +72,8 @@ TEST_F(ResolverBehaviorTest, ExprBitcastOp) {
}
TEST_F(ResolverBehaviorTest, ExprIndex_Arr) {
- Func("ArrayDiscardOrNext", {}, ty.array<i32, 4>(),
- {
+ Func("ArrayDiscardOrNext", utils::Empty, ty.array<i32, 4>(),
+ utils::Vector{
If(true, Block(Discard())),
Return(Construct(ty.array<i32, 4>())),
});
@@ -164,7 +165,7 @@ TEST_F(ResolverBehaviorTest, StmtBlockSingleStmt) {
}
TEST_F(ResolverBehaviorTest, StmtCallReturn) {
- Func("f", {}, ty.void_(), {Return()});
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Return()});
auto* stmt = CallStmt(Call("f"));
WrapInFunction(stmt);
@@ -175,7 +176,7 @@ TEST_F(ResolverBehaviorTest, StmtCallReturn) {
}
TEST_F(ResolverBehaviorTest, StmtCallFuncDiscard) {
- Func("f", {}, ty.void_(), {Discard()});
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Discard()});
auto* stmt = CallStmt(Call("f"));
WrapInFunction(stmt);
@@ -314,6 +315,56 @@ TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_CondCallFuncMayDiscard) {
EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
}
+TEST_F(ResolverBehaviorTest, StmtWhileBreak) {
+ auto* stmt = While(Expr(true), Block(Break()));
+ WrapInFunction(stmt);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(stmt);
+ EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+}
+
+TEST_F(ResolverBehaviorTest, StmtWhileDiscard) {
+ auto* stmt = While(Expr(true), Block(Discard()));
+ WrapInFunction(stmt);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(stmt);
+ EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+}
+
+TEST_F(ResolverBehaviorTest, StmtWhileReturn) {
+ auto* stmt = While(Expr(true), Block(Return()));
+ WrapInFunction(stmt);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(stmt);
+ EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kReturn, sem::Behavior::kNext));
+}
+
+TEST_F(ResolverBehaviorTest, StmtWhileEmpty_CondTrue) {
+ auto* stmt = While(Expr(true), Block());
+ WrapInFunction(stmt);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(stmt);
+ EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
+}
+
+TEST_F(ResolverBehaviorTest, StmtWhileEmpty_CondCallFuncMayDiscard) {
+ auto* stmt = While(Equal(Call("DiscardOrNext"), 1_i), Block());
+ WrapInFunction(stmt);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(stmt);
+ EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+}
+
TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenEmptyBlock) {
auto* stmt = If(true, Block());
WrapInFunction(stmt);
@@ -471,7 +522,7 @@ TEST_F(ResolverBehaviorTest, StmtReturn) {
TEST_F(ResolverBehaviorTest, StmtReturn_DiscardOrNext) {
auto* stmt = Return(Call("DiscardOrNext"));
- Func("F", {}, ty.i32(), {stmt});
+ Func("F", utils::Empty, ty.i32(), utils::Vector{stmt});
ASSERT_TRUE(r()->Resolve()) << r()->error();
diff --git a/chromium/third_party/dawn/src/tint/resolver/resolver_constants.cc b/chromium/third_party/dawn/src/tint/resolver/resolver_constants.cc
deleted file mode 100644
index b281f918eae..00000000000
--- a/chromium/third_party/dawn/src/tint/resolver/resolver_constants.cc
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/resolver/resolver.h"
-
-#include <cmath>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <optional> // NOLINT(build/include_order))
-
-#include "src/tint/sem/abstract_float.h"
-#include "src/tint/sem/abstract_int.h"
-#include "src/tint/sem/constant.h"
-#include "src/tint/sem/type_constructor.h"
-#include "src/tint/utils/compiler_macros.h"
-#include "src/tint/utils/map.h"
-#include "src/tint/utils/transform.h"
-
-using namespace tint::number_suffixes; // NOLINT
-
-namespace tint::resolver {
-
-namespace {
-
-/// Converts and returns all the element values of `in` to the type `T`, using the converter
-/// function `CONVERTER`.
-/// @param elements_in the vector of elements to be converted
-/// @param converter a function-like with the signature `void(TO&, FROM)`
-/// @returns the elements converted to type T.
-template <typename T, typename ELEMENTS_IN, typename CONVERTER>
-sem::Constant::Elements Transform(const ELEMENTS_IN& elements_in, CONVERTER&& converter) {
- TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
-
- return utils::Transform(elements_in, [&](auto value_in) {
- if constexpr (std::is_same_v<UnwrapNumber<T>, bool>) {
- return AInt(value_in != 0);
- } else {
- T converted{};
- converter(converted, value_in);
- if constexpr (IsFloatingPoint<UnwrapNumber<T>>) {
- return AFloat(converted);
- } else {
- return AInt(converted);
- }
- }
- });
-
- TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
-}
-
-/// Converts and returns all the element values of `in` to the semantic type `el_ty`, using the
-/// converter function `CONVERTER`.
-/// @param in the constant to convert
-/// @param el_ty the target element type
-/// @param converter a function-like with the signature `void(TO&, FROM)`
-/// @returns the elements converted to `el_ty`
-template <typename CONVERTER>
-sem::Constant::Elements Transform(const sem::Constant::Elements& in,
- const sem::Type* el_ty,
- CONVERTER&& converter) {
- return std::visit(
- [&](auto&& v) {
- return Switch(
- el_ty, //
- [&](const sem::AbstractInt*) { return Transform<AInt>(v, converter); },
- [&](const sem::AbstractFloat*) { return Transform<AFloat>(v, converter); },
- [&](const sem::I32*) { return Transform<i32>(v, converter); },
- [&](const sem::U32*) { return Transform<u32>(v, converter); },
- [&](const sem::F32*) { return Transform<f32>(v, converter); },
- [&](const sem::F16*) { return Transform<f16>(v, converter); },
- [&](const sem::Bool*) { return Transform<bool>(v, converter); },
- [&](Default) -> sem::Constant::Elements {
- diag::List diags;
- TINT_UNREACHABLE(Semantic, diags)
- << "invalid element type " << el_ty->TypeInfo().name;
- return {};
- });
- },
- in);
-}
-
-/// Converts and returns all the elements in `in` to the type `el_ty`.
-/// If the value does not fit in the target type, and:
-/// * the target type is an integer type, then the resulting value will be clamped to the integer's
-/// highest or lowest value.
-/// * the target type is an float type, then the resulting value will be either positive or
-/// negative infinity, based on the sign of the input value.
-/// @param in the input elements
-/// @param el_ty the target element type
-/// @returns the elements converted to `el_ty`
-sem::Constant::Elements ConvertElements(const sem::Constant::Elements& in, const sem::Type* el_ty) {
- return Transform(in, el_ty, [](auto& el_out, auto el_in) {
- using OUT = std::decay_t<decltype(el_out)>;
- if (auto conv = CheckedConvert<OUT>(el_in)) {
- el_out = conv.Get();
- } else {
- constexpr auto kInf = std::numeric_limits<double>::infinity();
- switch (conv.Failure()) {
- case ConversionFailure::kExceedsNegativeLimit:
- el_out = IsFloatingPoint<UnwrapNumber<OUT>> ? OUT(-kInf) : OUT::kLowest;
- break;
- case ConversionFailure::kExceedsPositiveLimit:
- el_out = IsFloatingPoint<UnwrapNumber<OUT>> ? OUT(kInf) : OUT::kHighest;
- break;
- }
- }
- });
-}
-
-/// Converts and returns all the elements in `in` to the type `el_ty`, by performing a
-/// `CheckedConvert` on each element value. A single error diagnostic will be raised if an element
-/// value cannot be represented by the target type.
-/// @param in the input elements
-/// @param el_ty the target element type
-/// @returns the elements converted to `el_ty`, or a Failure if some elements could not be
-/// represented by the target type.
-utils::Result<sem::Constant::Elements> MaterializeElements(const sem::Constant::Elements& in,
- const sem::Type* el_ty,
- ProgramBuilder& builder,
- Source source) {
- std::optional<std::string> failure;
-
- auto out = Transform(in, el_ty, [&](auto& el_out, auto el_in) {
- using OUT = std::decay_t<decltype(el_out)>;
- if (auto conv = CheckedConvert<OUT>(el_in)) {
- el_out = conv.Get();
- } else if (!failure.has_value()) {
- std::stringstream ss;
- ss << "value " << el_in << " cannot be represented as ";
- ss << "'" << builder.FriendlyName(el_ty) << "'";
- failure = ss.str();
- }
- });
-
- if (failure.has_value()) {
- builder.Diagnostics().add_error(diag::System::Resolver, std::move(failure.value()), source);
- return utils::Failure;
- }
-
- return out;
-}
-
-} // namespace
-
-utils::Result<sem::Constant> Resolver::EvaluateConstantValue(const ast::Expression* expr,
- const sem::Type* type) {
- if (auto* e = expr->As<ast::LiteralExpression>()) {
- return EvaluateConstantValue(e, type);
- }
- if (auto* e = expr->As<ast::CallExpression>()) {
- return EvaluateConstantValue(e, type);
- }
- return sem::Constant{};
-}
-
-utils::Result<sem::Constant> Resolver::EvaluateConstantValue(const ast::LiteralExpression* literal,
- const sem::Type* type) {
- return Switch(
- literal,
- [&](const ast::BoolLiteralExpression* lit) {
- return sem::Constant{type, {AInt(lit->value ? 1 : 0)}};
- },
- [&](const ast::IntLiteralExpression* lit) {
- return sem::Constant{type, {AInt(lit->value)}};
- },
- [&](const ast::FloatLiteralExpression* lit) {
- return sem::Constant{type, {AFloat(lit->value)}};
- });
-}
-
-utils::Result<sem::Constant> Resolver::EvaluateConstantValue(const ast::CallExpression* call,
- const sem::Type* ty) {
- uint32_t result_size = 0;
- auto* el_ty = sem::Type::ElementOf(ty, &result_size);
- if (!el_ty) {
- return sem::Constant{};
- }
-
- // ElementOf() will also return the element type of array, which we do not support.
- if (ty->Is<sem::Array>()) {
- return sem::Constant{};
- }
-
- // For zero value init, return 0s
- if (call->args.empty()) {
- return Switch(
- el_ty,
- [&](const sem::AbstractInt*) {
- return sem::Constant(ty, std::vector(result_size, AInt(0)));
- },
- [&](const sem::AbstractFloat*) {
- return sem::Constant(ty, std::vector(result_size, AFloat(0)));
- },
- [&](const sem::I32*) { return sem::Constant(ty, std::vector(result_size, AInt(0))); },
- [&](const sem::U32*) { return sem::Constant(ty, std::vector(result_size, AInt(0))); },
- [&](const sem::F32*) { return sem::Constant(ty, std::vector(result_size, AFloat(0))); },
- [&](const sem::F16*) { return sem::Constant(ty, std::vector(result_size, AFloat(0))); },
- [&](const sem::Bool*) { return sem::Constant(ty, std::vector(result_size, AInt(0))); });
- }
-
- // Build value for type_ctor from each child value by converting to type_ctor's type.
- std::optional<sem::Constant::Elements> elements;
- for (auto* expr : call->args) {
- auto* arg = builder_->Sem().Get(expr);
- if (!arg) {
- return sem::Constant{};
- }
- auto value = arg->ConstantValue();
- if (!value) {
- return sem::Constant{};
- }
-
- // Convert the elements to the desired type.
- auto converted = ConvertElements(value.GetElements(), el_ty);
-
- if (elements.has_value()) {
- // Append the converted vector to elements
- std::visit(
- [&](auto&& dst) {
- using VEC_TY = std::decay_t<decltype(dst)>;
- const auto& src = std::get<VEC_TY>(converted);
- dst.insert(dst.end(), src.begin(), src.end());
- },
- elements.value());
- } else {
- elements = std::move(converted);
- }
- }
-
- // Splat single-value initializers
- std::visit(
- [&](auto&& v) {
- if (v.size() == 1) {
- for (uint32_t i = 0; i < result_size - 1; ++i) {
- v.emplace_back(v[0]);
- }
- }
- },
- elements.value());
-
- return sem::Constant(ty, std::move(elements.value()));
-}
-
-utils::Result<sem::Constant> Resolver::ConvertValue(const sem::Constant& value,
- const sem::Type* ty,
- const Source& source) {
- if (value.Type() == ty) {
- return value;
- }
-
- auto* el_ty = sem::Type::ElementOf(ty);
- if (el_ty == nullptr) {
- return sem::Constant{};
- }
- if (value.ElementType() == el_ty) {
- return sem::Constant(ty, value.GetElements());
- }
-
- if (auto res = MaterializeElements(value.GetElements(), el_ty, *builder_, source)) {
- return sem::Constant(ty, std::move(res.Get()));
- }
- return utils::Failure;
-}
-
-} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/resolver_constants_test.cc b/chromium/third_party/dawn/src/tint/resolver/resolver_constants_test.cc
deleted file mode 100644
index bbdbfeafd4f..00000000000
--- a/chromium/third_party/dawn/src/tint/resolver/resolver_constants_test.cc
+++ /dev/null
@@ -1,515 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/resolver/resolver.h"
-
-#include "gtest/gtest.h"
-#include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/expression.h"
-
-using namespace tint::number_suffixes; // NOLINT
-
-namespace tint::resolver {
-namespace {
-
-using ResolverConstantsTest = ResolverTest;
-
-TEST_F(ResolverConstantsTest, Scalar_i32) {
- auto* expr = Expr(99_i);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- EXPECT_TRUE(sem->Type()->Is<sem::I32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
-}
-
-TEST_F(ResolverConstantsTest, Scalar_u32) {
- auto* expr = Expr(99_u);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- EXPECT_TRUE(sem->Type()->Is<sem::U32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
-}
-
-TEST_F(ResolverConstantsTest, Scalar_f32) {
- auto* expr = Expr(9.9_f);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- EXPECT_TRUE(sem->Type()->Is<sem::F32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.9f);
-}
-
-TEST_F(ResolverConstantsTest, Scalar_bool) {
- auto* expr = Expr(true);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- EXPECT_TRUE(sem->Type()->Is<sem::Bool>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_ZeroInit_i32) {
- auto* expr = vec3<i32>();
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_ZeroInit_u32) {
- auto* expr = vec3<u32>();
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0u);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_ZeroInit_f32) {
- auto* expr = vec3<f32>();
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 0.0);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 0.0);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 0.0);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_ZeroInit_bool) {
- auto* expr = vec3<bool>();
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), false);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Splat_i32) {
- auto* expr = vec3<i32>(99_i);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Splat_u32) {
- auto* expr = vec3<u32>(99_u);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99u);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Splat_f32) {
- auto* expr = vec3<f32>(9.9_f);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.9f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 9.9f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 9.9f);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Splat_bool) {
- auto* expr = vec3<bool>(true);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_FullConstruct_i32) {
- auto* expr = vec3<i32>(1_i, 2_i, 3_i);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_FullConstruct_u32) {
- auto* expr = vec3<u32>(1_u, 2_u, 3_u);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_FullConstruct_f32) {
- auto* expr = vec3<f32>(1_f, 2_f, 3_f);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1.f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2.f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3.f);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_FullConstruct_bool) {
- auto* expr = vec3<bool>(true, false, true);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_MixConstruct_i32) {
- auto* expr = vec3<i32>(1_i, vec2<i32>(2_i, 3_i));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_MixConstruct_u32) {
- auto* expr = vec3<u32>(vec2<u32>(1_u, 2_u), 3_u);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32) {
- auto* expr = vec3<f32>(1_f, vec2<f32>(2_f, 3_f));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1.f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2.f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3.f);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_MixConstruct_bool) {
- auto* expr = vec3<bool>(vec2<bool>(true, false), true);
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Convert_f32_to_i32) {
- auto* expr = vec3<i32>(vec3<f32>(1.1_f, 2.2_f, 3.3_f));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Convert_u32_to_f32) {
- auto* expr = vec3<f32>(vec3<u32>(10_u, 20_u, 30_u));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 10.f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 20.f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 30.f);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Convert_Large_f32_to_i32) {
- auto* expr = vec3<i32>(vec3<f32>(1e10_f, -1e20_f, 1e30_f));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, i32::kHighest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, i32::kLowest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, i32::kHighest);
-}
-
-TEST_F(ResolverConstantsTest, Vec3_Convert_Large_f32_to_u32) {
- auto* expr = vec3<u32>(vec3<f32>(1e10_f, -1e20_f, 1e30_f));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, u32::kHighest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, u32::kLowest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, u32::kHighest);
-}
-
-// TODO(crbug.com/tint/1502): Enable when f16 overloads are implemented
-TEST_F(ResolverConstantsTest, DISABLED_Vec3_Convert_Large_f32_to_f16) {
- Enable(ast::Extension::kF16);
-
- auto* expr = vec3<f16>(vec3<f32>(0.00001_f, -0.00002_f, 0.00003_f));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- constexpr auto kInf = std::numeric_limits<double>::infinity();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F16>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, kInf);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, -kInf);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, kInf);
-}
-
-// TODO(crbug.com/tint/1502): Enable when f16 overloads are implemented
-TEST_F(ResolverConstantsTest, DISABLED_Vec3_Convert_Small_f32_to_f16) {
- Enable(ast::Extension::kF16);
-
- auto* expr = vec3<f16>(vec3<f32>(1e-10_f, -1e20_f, 1e30_f));
- WrapInFunction(expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-
- auto* sem = Sem().Get(expr);
- EXPECT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
- EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F16>());
- EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 0.0);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, -0.0);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 0.0);
-}
-
-} // namespace
-} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/resolver_test.cc b/chromium/third_party/dawn/src/tint/resolver/resolver_test.cc
index 16725ba88a4..35ebcf5baea 100644
--- a/chromium/third_party/dawn/src/tint/resolver/resolver_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/resolver_test.cc
@@ -233,7 +233,7 @@ TEST_F(ResolverTest, Stmt_Return) {
auto* cond = Expr(2_i);
auto* ret = Return(cond);
- Func("test", {}, ty.i32(), {ret}, {});
+ Func("test", utils::Empty, ty.i32(), utils::Vector{ret}, utils::Empty);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -270,8 +270,10 @@ TEST_F(ResolverTest, Stmt_Switch) {
}
TEST_F(ResolverTest, Stmt_Call) {
- ast::VariableList params;
- Func("my_func", params, ty.void_(), {Return()}, ast::AttributeList{});
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(),
+ });
auto* expr = Call("my_func");
@@ -314,7 +316,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_Alias) {
TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScope) {
auto* init = Expr(2_i);
- Global("my_var", ty.i32(), ast::StorageClass::kPrivate, init);
+ GlobalVar("my_var", ty.i32(), ast::StorageClass::kPrivate, init);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -333,8 +335,6 @@ TEST_F(ResolverTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
// var bar : f32 = foo;
// }
- ast::VariableList params;
-
// Declare i32 "foo" inside a block
auto* foo_i32 = Var("foo", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
auto* foo_i32_init = foo_i32->constructor;
@@ -357,7 +357,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
auto* bar_f32_init = bar_f32->constructor;
auto* bar_f32_decl = Decl(bar_f32);
- Func("func", params, ty.void_(), {inner, foo_f32_decl, bar_f32_decl}, ast::AttributeList{});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{inner, foo_f32_decl, bar_f32_decl});
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(foo_i32_init), nullptr);
@@ -372,8 +372,8 @@ TEST_F(ResolverTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
EXPECT_EQ(StmtOf(bar_i32_init), bar_i32_decl);
EXPECT_EQ(StmtOf(foo_f32_init), foo_f32_decl);
EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl);
- EXPECT_TRUE(CheckVarUsers(foo_i32, {bar_i32->constructor}));
- EXPECT_TRUE(CheckVarUsers(foo_f32, {bar_f32->constructor}));
+ EXPECT_TRUE(CheckVarUsers(foo_i32, utils::Vector{bar_i32->constructor}));
+ EXPECT_TRUE(CheckVarUsers(foo_f32, utils::Vector{bar_f32->constructor}));
ASSERT_NE(VarOf(bar_i32->constructor), nullptr);
EXPECT_EQ(VarOf(bar_i32->constructor)->Declaration(), foo_i32);
ASSERT_NE(VarOf(bar_f32->constructor), nullptr);
@@ -389,13 +389,11 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
// var bar : f32 = foo;
// }
- ast::VariableList params;
-
// Declare i32 "foo" inside a function
auto* fn_i32 = Var("foo", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
auto* fn_i32_init = fn_i32->constructor;
auto* fn_i32_decl = Decl(fn_i32);
- Func("func_i32", params, ty.void_(), {fn_i32_decl}, ast::AttributeList{});
+ Func("func_i32", utils::Empty, ty.void_(), utils::Vector{fn_i32_decl});
// Declare f32 "foo" at module scope
auto* mod_f32 = Var("foo", ty.f32(), ast::StorageClass::kPrivate, Expr(2_f));
@@ -406,7 +404,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
auto* fn_f32 = Var("bar", ty.f32(), ast::StorageClass::kNone, Expr("foo"));
auto* fn_f32_init = fn_f32->constructor;
auto* fn_f32_decl = Decl(fn_f32);
- Func("func_f32", params, ty.void_(), {fn_f32_decl}, ast::AttributeList{});
+ Func("func_f32", utils::Empty, ty.void_(), utils::Vector{fn_f32_decl});
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(mod_init), nullptr);
@@ -418,15 +416,15 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
EXPECT_EQ(StmtOf(fn_i32_init), fn_i32_decl);
EXPECT_EQ(StmtOf(mod_init), nullptr);
EXPECT_EQ(StmtOf(fn_f32_init), fn_f32_decl);
- EXPECT_TRUE(CheckVarUsers(fn_i32, {}));
- EXPECT_TRUE(CheckVarUsers(mod_f32, {fn_f32->constructor}));
+ EXPECT_TRUE(CheckVarUsers(fn_i32, utils::Empty));
+ EXPECT_TRUE(CheckVarUsers(mod_f32, utils::Vector{fn_f32->constructor}));
ASSERT_NE(VarOf(fn_f32->constructor), nullptr);
EXPECT_EQ(VarOf(fn_f32->constructor)->Declaration(), mod_f32);
}
TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
// var<private> a : array<f32, 10u>;
- auto* a = Global("a", ty.array(ty.f32(), Expr(10_u)), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_u)), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -439,7 +437,7 @@ TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
TEST_F(ResolverTest, ArraySize_SignedLiteral) {
// var<private> a : array<f32, 10i>;
- auto* a = Global("a", ty.array(ty.f32(), Expr(10_i)), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_i)), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -450,11 +448,11 @@ TEST_F(ResolverTest, ArraySize_SignedLiteral) {
EXPECT_EQ(ary->Count(), 10u);
}
-TEST_F(ResolverTest, ArraySize_UnsignedConstant) {
- // let size = 0u;
+TEST_F(ResolverTest, ArraySize_UnsignedConst) {
+ // const size = 10u;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(10_u));
- auto* a = Global("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -465,11 +463,11 @@ TEST_F(ResolverTest, ArraySize_UnsignedConstant) {
EXPECT_EQ(ary->Count(), 10u);
}
-TEST_F(ResolverTest, ArraySize_SignedConstant) {
- // let size = 0;
+TEST_F(ResolverTest, ArraySize_SignedConst) {
+ // const size = 0;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(10_i));
- auto* a = Global("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -481,7 +479,7 @@ TEST_F(ResolverTest, ArraySize_SignedConstant) {
}
TEST_F(ResolverTest, Expr_Bitcast) {
- Global("name", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("name", ty.f32(), ast::StorageClass::kPrivate);
auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr("name"));
WrapInFunction(bitcast);
@@ -493,8 +491,7 @@ TEST_F(ResolverTest, Expr_Bitcast) {
}
TEST_F(ResolverTest, Expr_Call) {
- ast::VariableList params;
- Func("my_func", params, ty.f32(), {Return(0_f)}, ast::AttributeList{});
+ Func("my_func", utils::Empty, ty.f32(), utils::Vector{Return(0_f)});
auto* call = Call("my_func");
WrapInFunction(call);
@@ -506,8 +503,7 @@ TEST_F(ResolverTest, Expr_Call) {
}
TEST_F(ResolverTest, Expr_Call_InBinaryOp) {
- ast::VariableList params;
- Func("func", params, ty.f32(), {Return(0_f)}, ast::AttributeList{});
+ Func("func", utils::Empty, ty.f32(), utils::Vector{Return(0_f)});
auto* expr = Add(Call("func"), Call("func"));
WrapInFunction(expr);
@@ -519,8 +515,8 @@ TEST_F(ResolverTest, Expr_Call_InBinaryOp) {
}
TEST_F(ResolverTest, Expr_Call_WithParams) {
- Func("my_func", {Param(Sym(), ty.f32())}, ty.f32(),
- {
+ Func("my_func", utils::Vector{Param(Sym(), ty.f32())}, ty.f32(),
+ utils::Vector{
Return(1.2_f),
});
@@ -546,7 +542,7 @@ TEST_F(ResolverTest, Expr_Call_Builtin) {
}
TEST_F(ResolverTest, Expr_Cast) {
- Global("name", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("name", ty.f32(), ast::StorageClass::kPrivate);
auto* cast = Construct(ty.f32(), "name");
WrapInFunction(cast);
@@ -604,7 +600,7 @@ TEST_F(ResolverTest, Expr_Constructor_Type_Vec4) {
}
TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
- auto* my_var = Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
+ auto* my_var = GlobalVar("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* ident = Expr("my_var");
WrapInFunction(ident);
@@ -614,12 +610,12 @@ TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
ASSERT_NE(TypeOf(ident), nullptr);
ASSERT_TRUE(TypeOf(ident)->Is<sem::Reference>());
EXPECT_TRUE(TypeOf(ident)->UnwrapRef()->Is<sem::F32>());
- EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
+ EXPECT_TRUE(CheckVarUsers(my_var, utils::Vector{ident}));
ASSERT_NE(VarOf(ident), nullptr);
EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
}
-TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
+TEST_F(ResolverTest, Expr_Identifier_GlobalConst) {
auto* my_var = GlobalConst("my_var", ty.f32(), Construct(ty.f32()));
auto* ident = Expr("my_var");
@@ -629,7 +625,7 @@ TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
ASSERT_NE(TypeOf(ident), nullptr);
EXPECT_TRUE(TypeOf(ident)->Is<sem::F32>());
- EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
+ EXPECT_TRUE(CheckVarUsers(my_var, utils::Vector{ident}));
ASSERT_NE(VarOf(ident), nullptr);
EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
}
@@ -639,19 +635,18 @@ TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) {
auto* var = Let("my_var", ty.f32(), Construct(ty.f32()));
auto* decl = Decl(Var("b", ty.f32(), ast::StorageClass::kNone, my_var_a));
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
decl,
- },
- ast::AttributeList{});
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(my_var_a), nullptr);
EXPECT_TRUE(TypeOf(my_var_a)->Is<sem::F32>());
EXPECT_EQ(StmtOf(my_var_a), decl);
- EXPECT_TRUE(CheckVarUsers(var, {my_var_a}));
+ EXPECT_TRUE(CheckVarUsers(var, utils::Vector{my_var_a}));
ASSERT_NE(VarOf(my_var_a), nullptr);
EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
}
@@ -663,13 +658,12 @@ TEST_F(ResolverTest, IndexAccessor_Dynamic_Ref_F32) {
auto* a = Var("a", ty.array<bool, 10>(), array<bool, 10>());
auto* idx = Var("idx", ty.f32(), Construct(ty.f32()));
auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(a),
Decl(idx),
Decl(f),
- },
- ast::AttributeList{});
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
@@ -682,12 +676,11 @@ TEST_F(ResolverTest, Expr_Identifier_FunctionVariable) {
auto* var = Var("my_var", ty.f32());
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
assign,
- },
- ast::AttributeList{});
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -699,7 +692,7 @@ TEST_F(ResolverTest, Expr_Identifier_FunctionVariable) {
ASSERT_TRUE(TypeOf(my_var_b)->Is<sem::Reference>());
EXPECT_TRUE(TypeOf(my_var_b)->UnwrapRef()->Is<sem::F32>());
EXPECT_EQ(StmtOf(my_var_b), assign);
- EXPECT_TRUE(CheckVarUsers(var, {my_var_a, my_var_b}));
+ EXPECT_TRUE(CheckVarUsers(var, utils::Vector{my_var_a, my_var_b}));
ASSERT_NE(VarOf(my_var_a), nullptr);
EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
ASSERT_NE(VarOf(my_var_b), nullptr);
@@ -712,13 +705,12 @@ TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {
auto* v_decl = Decl(Var("v", ty.f32()));
auto* p_decl = Decl(Let("p", ty.pointer<f32>(ast::StorageClass::kFunction), AddressOf(v)));
auto* assign = Assign(Deref(p), 1.23_f);
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
v_decl,
p_decl,
assign,
- },
- ast::AttributeList{});
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -733,7 +725,10 @@ TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {
}
TEST_F(ResolverTest, Expr_Call_Function) {
- Func("my_func", ast::VariableList{}, ty.f32(), {Return(0_f)}, ast::AttributeList{});
+ Func("my_func", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(0_f),
+ });
auto* call = Call("my_func");
WrapInFunction(call);
@@ -757,18 +752,18 @@ TEST_F(ResolverTest, Function_Parameters) {
auto* param_c = Param("c", ty.u32());
auto* func = Func("my_func",
- ast::VariableList{
+ utils::Vector{
param_a,
param_b,
param_c,
},
- ty.void_(), {});
+ ty.void_(), utils::Empty);
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* func_sem = Sem().Get(func);
ASSERT_NE(func_sem, nullptr);
- EXPECT_EQ(func_sem->Parameters().size(), 3u);
+ EXPECT_EQ(func_sem->Parameters().Length(), 3u);
EXPECT_TRUE(func_sem->Parameters()[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(func_sem->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(func_sem->Parameters()[2]->Type()->Is<sem::U32>());
@@ -779,18 +774,19 @@ TEST_F(ResolverTest, Function_Parameters) {
}
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
- auto* s = Structure("S", {Member("m", ty.u32())});
-
- auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
- auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
- auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
-
- auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
+
+ auto* sb_var =
+ GlobalVar("sb_var", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+ auto* wg_var = GlobalVar("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
+ auto* priv_var = GlobalVar("priv_var", ty.f32(), ast::StorageClass::kPrivate);
+
+ auto* func = Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign("wg_var", "wg_var"),
Assign("sb_var", "sb_var"),
Assign("priv_var", "priv_var"),
@@ -800,54 +796,54 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
auto* func_sem = Sem().Get(func);
ASSERT_NE(func_sem, nullptr);
- EXPECT_EQ(func_sem->Parameters().size(), 0u);
+ EXPECT_EQ(func_sem->Parameters().Length(), 0u);
EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
const auto& vars = func_sem->TransitivelyReferencedGlobals();
- ASSERT_EQ(vars.size(), 3u);
+ ASSERT_EQ(vars.Length(), 3u);
EXPECT_EQ(vars[0]->Declaration(), wg_var);
EXPECT_EQ(vars[1]->Declaration(), sb_var);
EXPECT_EQ(vars[2]->Declaration(), priv_var);
}
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
- auto* s = Structure("S", {Member("m", ty.u32())});
-
- auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
- auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
- auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
-
- Func("my_func", ast::VariableList{}, ty.f32(),
- {Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"), Assign("priv_var", "priv_var"),
- Return(0_f)},
- ast::AttributeList{});
-
- auto* func2 = Func("func", ast::VariableList{}, ty.void_(),
- {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
+
+ auto* sb_var =
+ GlobalVar("sb_var", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+ auto* wg_var = GlobalVar("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
+ auto* priv_var = GlobalVar("priv_var", ty.f32(), ast::StorageClass::kPrivate);
+
+ Func("my_func", utils::Empty, ty.f32(),
+ utils::Vector{Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"),
+ Assign("priv_var", "priv_var"), Return(0_f)});
+
+ auto* func2 = Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
WrapInStatement(Call("my_func")),
},
- ast::AttributeList{});
+ utils::Empty);
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* func2_sem = Sem().Get(func2);
ASSERT_NE(func2_sem, nullptr);
- EXPECT_EQ(func2_sem->Parameters().size(), 0u);
+ EXPECT_EQ(func2_sem->Parameters().Length(), 0u);
const auto& vars = func2_sem->TransitivelyReferencedGlobals();
- ASSERT_EQ(vars.size(), 3u);
+ ASSERT_EQ(vars.Length(), 3u);
EXPECT_EQ(vars[0]->Declaration(), wg_var);
EXPECT_EQ(vars[1]->Declaration(), sb_var);
EXPECT_EQ(vars[2]->Declaration(), priv_var);
}
TEST_F(ResolverTest, Function_NotRegisterFunctionVariable) {
- auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ auto* func = Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("var", ty.f32())),
Assign("var", 1_f),
});
@@ -857,13 +853,13 @@ TEST_F(ResolverTest, Function_NotRegisterFunctionVariable) {
auto* func_sem = Sem().Get(func);
ASSERT_NE(func_sem, nullptr);
- EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
+ EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().Length(), 0u);
EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
}
TEST_F(ResolverTest, Function_NotRegisterFunctionConstant) {
- auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ auto* func = Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("var", ty.f32(), Construct(ty.f32()))),
});
@@ -872,28 +868,28 @@ TEST_F(ResolverTest, Function_NotRegisterFunctionConstant) {
auto* func_sem = Sem().Get(func);
ASSERT_NE(func_sem, nullptr);
- EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
+ EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().Length(), 0u);
EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
}
TEST_F(ResolverTest, Function_NotRegisterFunctionParams) {
- auto* func = Func("my_func", {Let("var", ty.f32(), Construct(ty.f32()))}, ty.void_(), {});
+ auto* func = Func("my_func", utils::Vector{Param("var", ty.f32())}, ty.void_(), utils::Empty);
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* func_sem = Sem().Get(func);
ASSERT_NE(func_sem, nullptr);
- EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
+ EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().Length(), 0u);
EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
}
TEST_F(ResolverTest, Function_CallSites) {
- auto* foo = Func("foo", ast::VariableList{}, ty.void_(), {});
+ auto* foo = Func("foo", utils::Empty, ty.void_(), utils::Empty);
auto* call_1 = Call("foo");
auto* call_2 = Call("foo");
- auto* bar = Func("bar", ast::VariableList{}, ty.void_(),
- {
+ auto* bar = Func("bar", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(call_1),
CallStmt(call_2),
});
@@ -914,7 +910,7 @@ TEST_F(ResolverTest, Function_CallSites) {
TEST_F(ResolverTest, Function_WorkgroupSize_NotSet) {
// @compute @workgroup_size(1)
// fn main() {}
- auto* func = Func("main", ast::VariableList{}, ty.void_(), {}, {});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -932,8 +928,11 @@ TEST_F(ResolverTest, Function_WorkgroupSize_NotSet) {
TEST_F(ResolverTest, Function_WorkgroupSize_Literals) {
// @compute @workgroup_size(8, 2, 3)
// fn main() {}
- auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8_i, 2_i, 3_i)});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(8_i, 2_i, 3_i),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -948,18 +947,20 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Literals) {
EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
}
-TEST_F(ResolverTest, Function_WorkgroupSize_Consts) {
- // let width = 16i;
- // let height = 8i;
- // let depth = 2i;
+TEST_F(ResolverTest, Function_WorkgroupSize_ViaConst) {
+ // const width = 16i;
+ // const height = 8i;
+ // const depth = 2i;
// @compute @workgroup_size(width, height, depth)
// fn main() {}
GlobalConst("width", ty.i32(), Expr(16_i));
GlobalConst("height", ty.i32(), Expr(8_i));
GlobalConst("depth", ty.i32(), Expr(2_i));
- auto* func =
- Func("main", ast::VariableList{}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height", "depth")});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize("width", "height", "depth"),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -974,17 +975,20 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Consts) {
EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
}
-TEST_F(ResolverTest, Function_WorkgroupSize_Consts_NestedInitializer) {
- // let width = i32(i32(i32(8i)));
- // let height = i32(i32(i32(4i)));
+TEST_F(ResolverTest, Function_WorkgroupSize_ViaConst_NestedInitializer) {
+ // const width = i32(i32(i32(8i)));
+ // const height = i32(i32(i32(4i)));
// @compute @workgroup_size(width, height)
// fn main() {}
GlobalConst("width", ty.i32(),
Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 8_i))));
GlobalConst("height", ty.i32(),
Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 4_i))));
- auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height")});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize("width", "height"),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1005,12 +1009,14 @@ TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts) {
// @id(2) override depth = 2i;
// @compute @workgroup_size(width, height, depth)
// fn main() {}
- auto* width = Override("width", ty.i32(), Expr(16_i), {Id(0)});
- auto* height = Override("height", ty.i32(), Expr(8_i), {Id(1)});
- auto* depth = Override("depth", ty.i32(), Expr(2_i), {Id(2)});
- auto* func =
- Func("main", ast::VariableList{}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height", "depth")});
+ auto* width = Override("width", ty.i32(), Expr(16_i), utils::Vector{Id(0)});
+ auto* height = Override("height", ty.i32(), Expr(8_i), utils::Vector{Id(1)});
+ auto* depth = Override("depth", ty.i32(), Expr(2_i), utils::Vector{Id(2)});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize("width", "height", "depth"),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1031,12 +1037,14 @@ TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts_NoInit) {
// @id(2) override depth : i32;
// @compute @workgroup_size(width, height, depth)
// fn main() {}
- auto* width = Override("width", ty.i32(), nullptr, {Id(0)});
- auto* height = Override("height", ty.i32(), nullptr, {Id(1)});
- auto* depth = Override("depth", ty.i32(), nullptr, {Id(2)});
- auto* func =
- Func("main", ast::VariableList{}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height", "depth")});
+ auto* width = Override("width", ty.i32(), nullptr, utils::Vector{Id(0)});
+ auto* height = Override("height", ty.i32(), nullptr, utils::Vector{Id(1)});
+ auto* depth = Override("depth", ty.i32(), nullptr, utils::Vector{Id(2)});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize("width", "height", "depth"),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1053,13 +1061,16 @@ TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts_NoInit) {
TEST_F(ResolverTest, Function_WorkgroupSize_Mixed) {
// @id(1) override height = 2i;
- // let depth = 3i;
+ // const depth = 3i;
// @compute @workgroup_size(8, height, depth)
// fn main() {}
- auto* height = Override("height", ty.i32(), Expr(2_i), {Id(0)});
+ auto* height = Override("height", ty.i32(), Expr(2_i), utils::Vector{Id(0)});
GlobalConst("depth", ty.i32(), Expr(3_i));
- auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8_i, "height", "depth")});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(8_i, "height", "depth"),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1075,9 +1086,9 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Mixed) {
}
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
- auto* st =
- Structure("S", {Member("first_member", ty.i32()), Member("second_member", ty.f32())});
- Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
+ auto* st = Structure(
+ "S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
+ GlobalVar("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_struct", "second_member");
WrapInFunction(mem);
@@ -1092,15 +1103,16 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
ASSERT_NE(sma, nullptr);
EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
+ EXPECT_EQ(sma->Object()->Declaration(), mem->structure);
EXPECT_EQ(sma->Member()->Index(), 1u);
EXPECT_EQ(sma->Member()->Declaration()->symbol, Symbols().Get("second_member"));
}
TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
- auto* st =
- Structure("S", {Member("first_member", ty.i32()), Member("second_member", ty.f32())});
+ auto* st = Structure(
+ "S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
auto* alias = Alias("alias", ty.Of(st));
- Global("my_struct", ty.Of(alias), ast::StorageClass::kPrivate);
+ GlobalVar("my_struct", ty.Of(alias), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_struct", "second_member");
WrapInFunction(mem);
@@ -1114,12 +1126,13 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
ASSERT_NE(sma, nullptr);
+ EXPECT_EQ(sma->Object()->Declaration(), mem->structure);
EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
EXPECT_EQ(sma->Member()->Index(), 1u);
}
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
- Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_vec", "xzyw");
WrapInFunction(mem);
@@ -1130,12 +1143,14 @@ TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
ASSERT_TRUE(TypeOf(mem)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(mem)->As<sem::Vector>()->type()->Is<sem::F32>());
EXPECT_EQ(TypeOf(mem)->As<sem::Vector>()->Width(), 4u);
- ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
- EXPECT_THAT(Sem().Get(mem)->As<sem::Swizzle>()->Indices(), ElementsAre(0, 2, 1, 3));
+ auto* sma = Sem().Get(mem)->As<sem::Swizzle>();
+ ASSERT_NE(sma, nullptr);
+ EXPECT_EQ(sma->Object()->Declaration(), mem->structure);
+ EXPECT_THAT(sma->As<sem::Swizzle>()->Indices(), ElementsAre(0, 2, 1, 3));
}
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) {
- Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_vec", "b");
WrapInFunction(mem);
@@ -1147,7 +1162,9 @@ TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) {
auto* ref = TypeOf(mem)->As<sem::Reference>();
ASSERT_TRUE(ref->StoreType()->Is<sem::F32>());
- ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
+ auto* sma = Sem().Get(mem)->As<sem::Swizzle>();
+ ASSERT_NE(sma, nullptr);
+ EXPECT_EQ(sma->Object()->Declaration(), mem->structure);
EXPECT_THAT(Sem().Get(mem)->As<sem::Swizzle>()->Indices(), ElementsAre(2));
}
@@ -1167,9 +1184,9 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
// }
//
- auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())});
- auto* stA = Structure("A", {Member("mem", ty.array(ty.Of(stB), 3_i))});
- Global("c", ty.Of(stA), ast::StorageClass::kPrivate);
+ auto* stB = Structure("B", utils::Vector{Member("foo", ty.vec4<f32>())});
+ auto* stA = Structure("A", utils::Vector{Member("mem", ty.array(ty.Of(stB), 3_i))});
+ GlobalVar("c", ty.Of(stA), ast::StorageClass::kPrivate);
auto* mem =
MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0_i), "foo"), "yx");
@@ -1185,9 +1202,9 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
}
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
- auto* st =
- Structure("S", {Member("first_member", ty.f32()), Member("second_member", ty.f32())});
- Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
+ auto* st = Structure(
+ "S", utils::Vector{Member("first_member", ty.f32()), Member("second_member", ty.f32())});
+ GlobalVar("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
auto* expr = Add(MemberAccessor("my_struct", "first_member"),
MemberAccessor("my_struct", "second_member"));
@@ -1490,8 +1507,8 @@ TEST_P(Expr_Binary_Test_Valid, All) {
ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str());
- Global("lhs", lhs_type, ast::StorageClass::kPrivate);
- Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
@@ -1525,8 +1542,8 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
<< FriendlyName(rhs_type);
SCOPED_TRACE(ss.str());
- Global("lhs", lhs_type, ast::StorageClass::kPrivate);
- Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
@@ -1571,8 +1588,8 @@ TEST_P(Expr_Binary_Test_Invalid, All) {
ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str());
- Global("lhs", lhs_type, ast::StorageClass::kPrivate);
- Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
@@ -1611,8 +1628,8 @@ TEST_P(Expr_Binary_Test_Invalid_VectorMatrixMultiply, All) {
is_valid_expr = vec_size == mat_cols;
}
- Global("lhs", lhs_type, ast::StorageClass::kPrivate);
- Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
@@ -1648,8 +1665,8 @@ TEST_P(Expr_Binary_Test_Invalid_MatrixMatrixMultiply, All) {
auto* col = create<sem::Vector>(f32, lhs_mat_rows);
auto* result_type = create<sem::Matrix>(col, rhs_mat_cols);
- Global("lhs", lhs_type, ast::StorageClass::kPrivate);
- Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
+ GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
@@ -1677,11 +1694,11 @@ TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
auto op = GetParam();
if (op == ast::UnaryOp::kNot) {
- Global("ident", ty.vec4<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("ident", ty.vec4<bool>(), ast::StorageClass::kPrivate);
} else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
- Global("ident", ty.vec4<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("ident", ty.vec4<i32>(), ast::StorageClass::kPrivate);
} else {
- Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
}
auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
WrapInFunction(der);
@@ -1709,7 +1726,7 @@ TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
auto* var = Var("var", ty.i32());
auto* stmt = Decl(var);
- Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{stmt});
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1718,11 +1735,11 @@ TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
TEST_F(ResolverTest, StorageClass_SetForSampler) {
auto* t = ty.sampler(ast::SamplerKind::kSampler);
- auto* var = Global("var", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* var = GlobalVar("var", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1731,11 +1748,11 @@ TEST_F(ResolverTest, StorageClass_SetForSampler) {
TEST_F(ResolverTest, StorageClass_SetForTexture) {
auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
- auto* var = Global("var", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* var = GlobalVar("var", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1745,7 +1762,7 @@ TEST_F(ResolverTest, StorageClass_SetForTexture) {
TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
auto* var = Let("var", ty.i32(), Construct(ty.i32()));
auto* stmt = Decl(var);
- Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{stmt});
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1755,12 +1772,12 @@ TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
TEST_F(ResolverTest, Access_SetForStorageBuffer) {
// struct S { x : i32 };
// var<storage> g : S;
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
- auto* var = Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
+ auto* var = GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1770,12 +1787,12 @@ TEST_F(ResolverTest, Access_SetForStorageBuffer) {
TEST_F(ResolverTest, BindingPoint_SetForResources) {
// @group(1) @binding(2) var s1 : sampler;
// @group(3) @binding(4) var s2 : sampler;
- auto* s1 = Global(
+ auto* s1 = GlobalVar(
Sym(), ty.sampler(ast::SamplerKind::kSampler),
- ast::AttributeList{create<ast::GroupAttribute>(1), create<ast::BindingAttribute>(2)});
- auto* s2 = Global(
+ utils::Vector{create<ast::GroupAttribute>(1u), create<ast::BindingAttribute>(2u)});
+ auto* s2 = GlobalVar(
Sym(), ty.sampler(ast::SamplerKind::kSampler),
- ast::AttributeList{create<ast::GroupAttribute>(3), create<ast::BindingAttribute>(4)});
+ utils::Vector{create<ast::GroupAttribute>(3u), create<ast::BindingAttribute>(4u)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1796,32 +1813,46 @@ TEST_F(ResolverTest, Function_EntryPoints_StageAttribute) {
// ep_1 -> {}
// ep_2 -> {}
- Global("first", ty.f32(), ast::StorageClass::kPrivate);
- Global("second", ty.f32(), ast::StorageClass::kPrivate);
- Global("call_a", ty.f32(), ast::StorageClass::kPrivate);
- Global("call_b", ty.f32(), ast::StorageClass::kPrivate);
- Global("call_c", ty.f32(), ast::StorageClass::kPrivate);
-
- ast::VariableList params;
- auto* func_b = Func("b", params, ty.f32(), {Return(0_f)}, ast::AttributeList{});
- auto* func_c = Func("c", params, ty.f32(), {Assign("second", Call("b")), Return(0_f)},
- ast::AttributeList{});
-
- auto* func_a = Func("a", params, ty.f32(), {Assign("first", Call("c")), Return(0_f)},
- ast::AttributeList{});
-
- auto* ep_1 = Func("ep_1", params, ty.void_(),
- {
+ GlobalVar("first", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("second", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("call_a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("call_b", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("call_c", ty.f32(), ast::StorageClass::kPrivate);
+
+ auto* func_b = Func("b", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(0_f),
+ });
+ auto* func_c = Func("c", utils::Empty, ty.f32(),
+ utils::Vector{
+ Assign("second", Call("b")),
+ Return(0_f),
+ });
+
+ auto* func_a = Func("a", utils::Empty, ty.f32(),
+ utils::Vector{
+ Assign("first", Call("c")),
+ Return(0_f),
+ });
+
+ auto* ep_1 = Func("ep_1", utils::Empty, ty.void_(),
+ utils::Vector{
Assign("call_a", Call("a")),
Assign("call_b", Call("b")),
},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
- auto* ep_2 = Func("ep_2", params, ty.void_(),
- {
+ auto* ep_2 = Func("ep_2", utils::Empty, ty.void_(),
+ utils::Vector{
Assign("call_c", Call("c")),
},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1836,9 +1867,9 @@ TEST_F(ResolverTest, Function_EntryPoints_StageAttribute) {
ASSERT_NE(ep_1_sem, nullptr);
ASSERT_NE(ep_2_sem, nullptr);
- EXPECT_EQ(func_b_sem->Parameters().size(), 0u);
- EXPECT_EQ(func_a_sem->Parameters().size(), 0u);
- EXPECT_EQ(func_c_sem->Parameters().size(), 0u);
+ EXPECT_EQ(func_b_sem->Parameters().Length(), 0u);
+ EXPECT_EQ(func_a_sem->Parameters().Length(), 0u);
+ EXPECT_EQ(func_c_sem->Parameters().Length(), 0u);
const auto& b_eps = func_b_sem->AncestorEntryPoints();
ASSERT_EQ(2u, b_eps.size());
@@ -1875,38 +1906,38 @@ TEST_F(ResolverTest, Function_EntryPoints_LinearTime) {
auto fn_a = [](int level) { return "l" + std::to_string(level + 1) + "a"; };
auto fn_b = [](int level) { return "l" + std::to_string(level + 1) + "b"; };
- Func(fn_a(levels), {}, ty.void_(), {}, {});
- Func(fn_b(levels), {}, ty.void_(), {}, {});
+ Func(fn_a(levels), utils::Empty, ty.void_(), utils::Empty);
+ Func(fn_b(levels), utils::Empty, ty.void_(), utils::Empty);
for (int i = levels - 1; i >= 0; i--) {
- Func(fn_a(i), {}, ty.void_(),
- {
+ Func(fn_a(i), utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call(fn_a(i + 1))),
CallStmt(Call(fn_b(i + 1))),
},
- {});
- Func(fn_b(i), {}, ty.void_(),
- {
+ utils::Empty);
+ Func(fn_b(i), utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call(fn_a(i + 1))),
CallStmt(Call(fn_b(i + 1))),
},
- {});
+ utils::Empty);
}
- Func("main", {}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call(fn_a(0))),
CallStmt(Call(fn_b(0))),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
// Test for crbug.com/tint/728
TEST_F(ResolverTest, ASTNodesAreReached) {
- Structure("A", {Member("x", ty.array<f32, 4>(4))});
- Structure("B", {Member("x", ty.array<f32, 4>(4))});
+ Structure("A", utils::Vector{Member("x", ty.array<f32, 4>(4))});
+ Structure("B", utils::Vector{Member("x", ty.array<f32, 4>(4))});
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -1926,8 +1957,8 @@ TEST_F(ResolverTest, ASTNodeReachedTwice) {
{
ProgramBuilder b;
auto* expr = b.Expr(1_i);
- b.Global("a", b.ty.i32(), ast::StorageClass::kPrivate, expr);
- b.Global("b", b.ty.i32(), ast::StorageClass::kPrivate, expr);
+ b.GlobalVar("a", b.ty.i32(), ast::StorageClass::kPrivate, expr);
+ b.GlobalVar("b", b.ty.i32(), ast::StorageClass::kPrivate, expr);
Resolver(&b).Resolve();
},
"internal compiler error: AST node 'tint::ast::IntLiteralExpression' was encountered twice "
@@ -1935,7 +1966,7 @@ TEST_F(ResolverTest, ASTNodeReachedTwice) {
}
TEST_F(ResolverTest, UnaryOp_Not) {
- Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(Source{{12, 34}}, "ident"));
WrapInFunction(der);
@@ -1944,7 +1975,7 @@ TEST_F(ResolverTest, UnaryOp_Not) {
}
TEST_F(ResolverTest, UnaryOp_Complement) {
- Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* der =
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr(Source{{12, 34}}, "ident"));
WrapInFunction(der);
@@ -1954,7 +1985,7 @@ TEST_F(ResolverTest, UnaryOp_Complement) {
}
TEST_F(ResolverTest, UnaryOp_Negation) {
- Global("ident", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("ident", ty.u32(), ast::StorageClass::kPrivate);
auto* der =
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(Source{{12, 34}}, "ident"));
WrapInFunction(der);
@@ -1964,106 +1995,114 @@ TEST_F(ResolverTest, UnaryOp_Negation) {
}
TEST_F(ResolverTest, TextureSampler_TextureSample) {
- Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
- Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
+ GlobalVar("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
+ GlobalVar("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
auto* call = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
- const ast::Function* f =
- Func("test_function", {}, ty.void_(), {call}, {Stage(ast::PipelineStage::kFragment)});
+ const ast::Function* f = Func("test_function", utils::Empty, ty.void_(), utils::Vector{call},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
const sem::Function* sf = Sem().Get(f);
auto pairs = sf->TextureSamplerPairs();
- ASSERT_EQ(pairs.size(), 1u);
+ ASSERT_EQ(pairs.Length(), 1u);
EXPECT_TRUE(pairs[0].first != nullptr);
EXPECT_TRUE(pairs[0].second != nullptr);
}
TEST_F(ResolverTest, TextureSampler_TextureSampleInFunction) {
- Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
- Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
+ GlobalVar("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
+ GlobalVar("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
auto* inner_call = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
- const ast::Function* inner_func = Func("inner_func", {}, ty.void_(), {inner_call});
+ const ast::Function* inner_func =
+ Func("inner_func", utils::Empty, ty.void_(), utils::Vector{inner_call});
auto* outer_call = CallStmt(Call("inner_func"));
const ast::Function* outer_func =
- Func("outer_func", {}, ty.void_(), {outer_call}, {Stage(ast::PipelineStage::kFragment)});
+ Func("outer_func", utils::Empty, ty.void_(), utils::Vector{outer_call},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto inner_pairs = Sem().Get(inner_func)->TextureSamplerPairs();
- ASSERT_EQ(inner_pairs.size(), 1u);
+ ASSERT_EQ(inner_pairs.Length(), 1u);
EXPECT_TRUE(inner_pairs[0].first != nullptr);
EXPECT_TRUE(inner_pairs[0].second != nullptr);
auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
- ASSERT_EQ(outer_pairs.size(), 1u);
+ ASSERT_EQ(outer_pairs.Length(), 1u);
EXPECT_TRUE(outer_pairs[0].first != nullptr);
EXPECT_TRUE(outer_pairs[0].second != nullptr);
}
TEST_F(ResolverTest, TextureSampler_TextureSampleFunctionDiamondSameVariables) {
- Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
- Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
+ GlobalVar("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
+ GlobalVar("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
auto* inner_call_1 = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
- const ast::Function* inner_func_1 = Func("inner_func_1", {}, ty.void_(), {inner_call_1});
+ const ast::Function* inner_func_1 =
+ Func("inner_func_1", utils::Empty, ty.void_(), utils::Vector{inner_call_1});
auto* inner_call_2 = CallStmt(Call("textureSample", "t", "s", vec2<f32>(3_f, 4_f)));
- const ast::Function* inner_func_2 = Func("inner_func_2", {}, ty.void_(), {inner_call_2});
+ const ast::Function* inner_func_2 =
+ Func("inner_func_2", utils::Empty, ty.void_(), utils::Vector{inner_call_2});
auto* outer_call_1 = CallStmt(Call("inner_func_1"));
auto* outer_call_2 = CallStmt(Call("inner_func_2"));
const ast::Function* outer_func =
- Func("outer_func", {}, ty.void_(), {outer_call_1, outer_call_2},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("outer_func", utils::Empty, ty.void_(), utils::Vector{outer_call_1, outer_call_2},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto inner_pairs_1 = Sem().Get(inner_func_1)->TextureSamplerPairs();
- ASSERT_EQ(inner_pairs_1.size(), 1u);
+ ASSERT_EQ(inner_pairs_1.Length(), 1u);
EXPECT_TRUE(inner_pairs_1[0].first != nullptr);
EXPECT_TRUE(inner_pairs_1[0].second != nullptr);
auto inner_pairs_2 = Sem().Get(inner_func_2)->TextureSamplerPairs();
- ASSERT_EQ(inner_pairs_1.size(), 1u);
+ ASSERT_EQ(inner_pairs_1.Length(), 1u);
EXPECT_TRUE(inner_pairs_2[0].first != nullptr);
EXPECT_TRUE(inner_pairs_2[0].second != nullptr);
auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
- ASSERT_EQ(outer_pairs.size(), 1u);
+ ASSERT_EQ(outer_pairs.Length(), 1u);
EXPECT_TRUE(outer_pairs[0].first != nullptr);
EXPECT_TRUE(outer_pairs[0].second != nullptr);
}
TEST_F(ResolverTest, TextureSampler_TextureSampleFunctionDiamondDifferentVariables) {
- Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
- Global("t2", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 2));
- Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 3));
+ GlobalVar("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ GroupAndBinding(1, 1));
+ GlobalVar("t2", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ GroupAndBinding(1, 2));
+ GlobalVar("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 3));
auto* inner_call_1 = CallStmt(Call("textureSample", "t1", "s", vec2<f32>(1_f, 2_f)));
- const ast::Function* inner_func_1 = Func("inner_func_1", {}, ty.void_(), {inner_call_1});
+ const ast::Function* inner_func_1 =
+ Func("inner_func_1", utils::Empty, ty.void_(), utils::Vector{inner_call_1});
auto* inner_call_2 = CallStmt(Call("textureSample", "t2", "s", vec2<f32>(3_f, 4_f)));
- const ast::Function* inner_func_2 = Func("inner_func_2", {}, ty.void_(), {inner_call_2});
+ const ast::Function* inner_func_2 =
+ Func("inner_func_2", utils::Empty, ty.void_(), utils::Vector{inner_call_2});
auto* outer_call_1 = CallStmt(Call("inner_func_1"));
auto* outer_call_2 = CallStmt(Call("inner_func_2"));
const ast::Function* outer_func =
- Func("outer_func", {}, ty.void_(), {outer_call_1, outer_call_2},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("outer_func", utils::Empty, ty.void_(), utils::Vector{outer_call_1, outer_call_2},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto inner_pairs_1 = Sem().Get(inner_func_1)->TextureSamplerPairs();
- ASSERT_EQ(inner_pairs_1.size(), 1u);
+ ASSERT_EQ(inner_pairs_1.Length(), 1u);
EXPECT_TRUE(inner_pairs_1[0].first != nullptr);
EXPECT_TRUE(inner_pairs_1[0].second != nullptr);
auto inner_pairs_2 = Sem().Get(inner_func_2)->TextureSamplerPairs();
- ASSERT_EQ(inner_pairs_2.size(), 1u);
+ ASSERT_EQ(inner_pairs_2.Length(), 1u);
EXPECT_TRUE(inner_pairs_2[0].first != nullptr);
EXPECT_TRUE(inner_pairs_2[0].second != nullptr);
auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
- ASSERT_EQ(outer_pairs.size(), 2u);
+ ASSERT_EQ(outer_pairs.Length(), 2u);
EXPECT_TRUE(outer_pairs[0].first == inner_pairs_1[0].first);
EXPECT_TRUE(outer_pairs[0].second == inner_pairs_1[0].second);
EXPECT_TRUE(outer_pairs[1].first == inner_pairs_2[0].first);
@@ -2071,7 +2110,7 @@ TEST_F(ResolverTest, TextureSampler_TextureSampleFunctionDiamondDifferentVariabl
}
TEST_F(ResolverTest, TextureSampler_TextureDimensions) {
- Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 2));
+ GlobalVar("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 2));
auto* call = Call("textureDimensions", "t");
const ast::Function* f = WrapInFunction(call);
@@ -2080,24 +2119,24 @@ TEST_F(ResolverTest, TextureSampler_TextureDimensions) {
const sem::Function* sf = Sem().Get(f);
auto pairs = sf->TextureSamplerPairs();
- ASSERT_EQ(pairs.size(), 1u);
+ ASSERT_EQ(pairs.Length(), 1u);
EXPECT_TRUE(pairs[0].first != nullptr);
EXPECT_TRUE(pairs[0].second == nullptr);
}
TEST_F(ResolverTest, ModuleDependencyOrderedDeclarations) {
- auto* f0 = Func("f0", {}, ty.void_(), {});
- auto* v0 = Global("v0", ty.i32(), ast::StorageClass::kPrivate);
+ auto* f0 = Func("f0", utils::Empty, ty.void_(), utils::Empty);
+ auto* v0 = GlobalVar("v0", ty.i32(), ast::StorageClass::kPrivate);
auto* a0 = Alias("a0", ty.i32());
- auto* s0 = Structure("s0", {Member("m", ty.i32())});
- auto* f1 = Func("f1", {}, ty.void_(), {});
- auto* v1 = Global("v1", ty.i32(), ast::StorageClass::kPrivate);
+ auto* s0 = Structure("s0", utils::Vector{Member("m", ty.i32())});
+ auto* f1 = Func("f1", utils::Empty, ty.void_(), utils::Empty);
+ auto* v1 = GlobalVar("v1", ty.i32(), ast::StorageClass::kPrivate);
auto* a1 = Alias("a1", ty.i32());
- auto* s1 = Structure("s1", {Member("m", ty.i32())});
- auto* f2 = Func("f2", {}, ty.void_(), {});
- auto* v2 = Global("v2", ty.i32(), ast::StorageClass::kPrivate);
+ auto* s1 = Structure("s1", utils::Vector{Member("m", ty.i32())});
+ auto* f2 = Func("f2", utils::Empty, ty.void_(), utils::Empty);
+ auto* v2 = GlobalVar("v2", ty.i32(), ast::StorageClass::kPrivate);
auto* a2 = Alias("a2", ty.i32());
- auto* s2 = Structure("s2", {Member("m", ty.i32())});
+ auto* s2 = Structure("s2", utils::Vector{Member("m", ty.i32())});
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -2134,5 +2173,22 @@ TEST_F(ResolverTest, MaxExpressionDepth_Fail) {
std::to_string(kMaxExpressionDepth)));
}
+TEST_F(ResolverTest, Literal_F16WithoutExtension) {
+ // fn test() {_ = 1.23h;}
+ WrapInFunction(Ignore(Expr(f16(1.23f))));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(r()->error(), HasSubstr("error: f16 literal used without 'f16' extension enabled"));
+}
+
+TEST_F(ResolverTest, Literal_F16WithExtension) {
+ // enable f16;
+ // fn test() {_ = 1.23h;}
+ Enable(ast::Extension::kF16);
+ WrapInFunction(Ignore(Expr(f16(1.23f))));
+
+ EXPECT_TRUE(r()->Resolve());
+}
+
} // namespace
} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/resolver_test_helper.h b/chromium/third_party/dawn/src/tint/resolver/resolver_test_helper.h
index a0d71e55fe1..bab1d843aad 100644
--- a/chromium/third_party/dawn/src/tint/resolver/resolver_test_helper.h
+++ b/chromium/third_party/dawn/src/tint/resolver/resolver_test_helper.h
@@ -18,7 +18,6 @@
#include <functional>
#include <memory>
#include <string>
-#include <vector>
#include "gtest/gtest.h"
#include "src/tint/program_builder.h"
@@ -28,6 +27,7 @@
#include "src/tint/sem/expression.h"
#include "src/tint/sem/statement.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/utils/vector.h"
namespace tint::resolver {
@@ -88,9 +88,9 @@ class TestHelper : public ProgramBuilder {
/// @param expected_users the expected users of the variable
/// @return true if all users are as expected
bool CheckVarUsers(const ast::Variable* var,
- std::vector<const ast::Expression*>&& expected_users) {
+ utils::VectorRef<const ast::Expression*> expected_users) {
auto& var_users = Sem().Get(var)->Users();
- if (var_users.size() != expected_users.size()) {
+ if (var_users.size() != expected_users.Length()) {
return false;
}
for (size_t i = 0; i < var_users.size(); i++) {
@@ -389,10 +389,10 @@ struct DataType<vec<N, T>> {
/// @param b the ProgramBuilder
/// @param elem_value the value each element will be initialized with
/// @return the list of expressions that are used to construct the vector
- static inline ast::ExpressionList ExprArgs(ProgramBuilder& b, double elem_value) {
- ast::ExpressionList args;
+ static inline auto ExprArgs(ProgramBuilder& b, double elem_value) {
+ utils::Vector<const ast::Expression*, N> args;
for (uint32_t i = 0; i < N; i++) {
- args.emplace_back(DataType<T>::Expr(b, elem_value));
+ args.Push(DataType<T>::Expr(b, elem_value));
}
return args;
}
@@ -433,10 +433,10 @@ struct DataType<mat<N, M, T>> {
/// @param b the ProgramBuilder
/// @param elem_value the value each element will be initialized with
/// @return the list of expressions that are used to construct the matrix
- static inline ast::ExpressionList ExprArgs(ProgramBuilder& b, double elem_value) {
- ast::ExpressionList args;
+ static inline auto ExprArgs(ProgramBuilder& b, double elem_value) {
+ utils::Vector<const ast::Expression*, N> args;
for (uint32_t i = 0; i < N; i++) {
- args.emplace_back(DataType<vec<M, T>>::Expr(b, elem_value));
+ args.Push(DataType<vec<M, T>>::Expr(b, elem_value));
}
return args;
}
@@ -519,7 +519,7 @@ struct DataType<ptr<T>> {
/// @return a new AST expression of the alias type
static inline const ast::Expression* Expr(ProgramBuilder& b, double /*unused*/) {
auto sym = b.Symbols().New("global_for_ptr");
- b.Global(sym, DataType<T>::AST(b), ast::StorageClass::kPrivate);
+ b.GlobalVar(sym, DataType<T>::AST(b), ast::StorageClass::kPrivate);
return b.AddressOf(sym);
}
/// @returns the WGSL name for the type
@@ -538,7 +538,10 @@ struct DataType<array<N, T>> {
/// @param b the ProgramBuilder
/// @return a new AST array type
static inline const ast::Type* AST(ProgramBuilder& b) {
- return b.ty.array(DataType<T>::AST(b), u32(N));
+ if (auto* ast = DataType<T>::AST(b)) {
+ return b.ty.array(ast, u32(N));
+ }
+ return b.ty.array(nullptr, nullptr);
}
/// @param b the ProgramBuilder
/// @return the semantic array type
@@ -548,7 +551,7 @@ struct DataType<array<N, T>> {
/* element */ el,
/* count */ N,
/* align */ el->Align(),
- /* size */ el->Size(),
+ /* size */ N * el->Size(),
/* stride */ el->Align(),
/* implicit_stride */ el->Align());
}
@@ -563,10 +566,10 @@ struct DataType<array<N, T>> {
/// @param b the ProgramBuilder
/// @param elem_value the value each element will be initialized with
/// @return the list of expressions that are used to construct the array
- static inline ast::ExpressionList ExprArgs(ProgramBuilder& b, double elem_value) {
- ast::ExpressionList args;
+ static inline auto ExprArgs(ProgramBuilder& b, double elem_value) {
+ utils::Vector<const ast::Expression*, N> args;
for (uint32_t i = 0; i < N; i++) {
- args.emplace_back(DataType<T>::Expr(b, elem_value));
+ args.Push(DataType<T>::Expr(b, elem_value));
}
return args;
}
diff --git a/chromium/third_party/dawn/src/tint/resolver/side_effects_test.cc b/chromium/third_party/dawn/src/tint/resolver/side_effects_test.cc
index a50d9045f4e..d0cb32ca680 100644
--- a/chromium/third_party/dawn/src/tint/resolver/side_effects_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/side_effects_test.cc
@@ -17,7 +17,9 @@
#include "gtest/gtest.h"
#include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/sem/expression.h"
+#include "src/tint/sem/index_accessor_expression.h"
#include "src/tint/sem/member_accessor_expression.h"
+#include "src/tint/utils/vector.h"
using namespace tint::number_suffixes; // NOLINT
@@ -28,10 +30,10 @@ struct SideEffectsTest : ResolverTest {
template <typename T>
void MakeSideEffectFunc(const char* name) {
auto global = Sym();
- Global(global, ty.Of<T>(), ast::StorageClass::kPrivate);
+ GlobalVar(global, ty.Of<T>(), ast::StorageClass::kPrivate);
auto local = Sym();
- Func(name, {}, ty.Of<T>(),
- {
+ Func(name, utils::Empty, ty.Of<T>(),
+ utils::Vector{
Decl(Var(local, ty.Of<T>())),
Assign(global, local),
Return(global),
@@ -41,10 +43,10 @@ struct SideEffectsTest : ResolverTest {
template <typename MAKE_TYPE_FUNC>
void MakeSideEffectFunc(const char* name, MAKE_TYPE_FUNC make_type) {
auto global = Sym();
- Global(global, make_type(), ast::StorageClass::kPrivate);
+ GlobalVar(global, make_type(), ast::StorageClass::kPrivate);
auto local = Sym();
- Func(name, {}, make_type(),
- {
+ Func(name, utils::Empty, make_type(),
+ utils::Vector{
Decl(Var(local, make_type())),
Assign(global, local),
Return(global),
@@ -86,10 +88,10 @@ TEST_F(SideEffectsTest, VariableUser) {
}
TEST_F(SideEffectsTest, Call_Builtin_NoSE) {
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call("dpdx", "a");
- Func("f", {}, ty.void_(), {Ignore(expr)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
+ utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(expr);
@@ -101,8 +103,8 @@ TEST_F(SideEffectsTest, Call_Builtin_NoSE) {
TEST_F(SideEffectsTest, Call_Builtin_NoSE_WithSEArg) {
MakeSideEffectFunc<f32>("se");
auto* expr = Call("dpdx", Call("se"));
- Func("f", {}, ty.void_(), {Ignore(expr)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
+ utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(expr);
@@ -112,7 +114,7 @@ TEST_F(SideEffectsTest, Call_Builtin_NoSE_WithSEArg) {
}
TEST_F(SideEffectsTest, Call_Builtin_SE) {
- Global("a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
auto* expr = Call("atomicAdd", AddressOf("a"), 1_i);
WrapInFunction(expr);
@@ -123,8 +125,230 @@ TEST_F(SideEffectsTest, Call_Builtin_SE) {
EXPECT_TRUE(sem->HasSideEffects());
}
+namespace builtin {
+struct Case {
+ const char* name;
+ utils::Vector<const char*, 3> args;
+ bool has_side_effects;
+ ast::PipelineStage pipeline_stage;
+};
+static Case C(const char* name,
+ utils::VectorRef<const char*> args,
+ bool has_side_effects,
+ ast::PipelineStage stage = ast::PipelineStage::kFragment) {
+ Case c;
+ c.name = name;
+ c.args = std::move(args);
+ c.has_side_effects = has_side_effects;
+ c.pipeline_stage = stage;
+ return c;
+}
+static std::ostream& operator<<(std::ostream& o, const Case& c) {
+ o << c.name << "(";
+ for (size_t i = 0; i < c.args.Length(); ++i) {
+ o << c.args[i];
+ if (i + 1 != c.args.Length()) {
+ o << ", ";
+ }
+ }
+ o << "), ";
+ o << "has_side_effects = " << c.has_side_effects;
+ return o;
+}
+
+using SideEffectsBuiltinTest = resolver::ResolverTestWithParam<Case>;
+
+TEST_P(SideEffectsBuiltinTest, Test) {
+ Enable(ast::Extension::kChromiumExperimentalDp4A);
+ auto& c = GetParam();
+
+ uint32_t next_binding = 0;
+ GlobalVar("f", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("i", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("u", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("vf", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("vf2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("vi2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("vf4", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("vb", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("m", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("arr", ty.array<f32, 10>(), ast::StorageClass::kPrivate);
+ GlobalVar("storage_arr", ty.array<f32>(), ast::StorageClass::kStorage,
+ GroupAndBinding(0, next_binding++));
+ GlobalVar("a", ty.atomic(ty.i32()), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ GroupAndBinding(0, next_binding++));
+ if (c.pipeline_stage != ast::PipelineStage::kCompute) {
+ GlobalVar("t2d", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ GroupAndBinding(0, next_binding++));
+ GlobalVar("tdepth2d", ty.depth_texture(ast::TextureDimension::k2d),
+ GroupAndBinding(0, next_binding++));
+ GlobalVar("t2d_arr", ty.sampled_texture(ast::TextureDimension::k2dArray, ty.f32()),
+ GroupAndBinding(0, next_binding++));
+ GlobalVar("t2d_multi", ty.multisampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ GroupAndBinding(0, next_binding++));
+ GlobalVar("tstorage2d",
+ ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+ ast::Access::kWrite),
+ GroupAndBinding(0, next_binding++));
+ GlobalVar("s2d", ty.sampler(ast::SamplerKind::kSampler),
+ GroupAndBinding(0, next_binding++));
+ GlobalVar("scomp", ty.sampler(ast::SamplerKind::kComparisonSampler),
+ GroupAndBinding(0, next_binding++));
+ }
+
+ utils::Vector<const ast::Statement*, 4> stmts;
+ stmts.Push(Decl(Let("pstorage_arr", nullptr, AddressOf("storage_arr"))));
+ stmts.Push(Decl(Let("pa", nullptr, AddressOf("a"))));
+
+ utils::Vector<const ast::Expression*, 5> args;
+ for (auto& a : c.args) {
+ args.Push(Expr(a));
+ }
+ auto* expr = Call(c.name, args);
+
+ utils::Vector<const ast::Attribute*, 2> attrs;
+ attrs.Push(create<ast::StageAttribute>(c.pipeline_stage));
+ if (c.pipeline_stage == ast::PipelineStage::kCompute) {
+ attrs.Push(WorkgroupSize(Expr(1_u)));
+ }
+
+ stmts.Push(create<ast::CallStatement>(expr));
+
+ Func("func", utils::Empty, ty.void_(), stmts, attrs);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ EXPECT_TRUE(sem->Is<sem::Call>());
+ EXPECT_EQ(c.has_side_effects, sem->HasSideEffects());
+}
+INSTANTIATE_TEST_SUITE_P(
+ SideEffectsTest_Builtins,
+ SideEffectsBuiltinTest,
+ testing::ValuesIn(std::vector<Case>{
+ // No side-effect builts
+ C("abs", utils::Vector{"f"}, false), //
+ C("acos", utils::Vector{"f"}, false), //
+ C("acosh", utils::Vector{"f"}, false), //
+ C("all", utils::Vector{"vb"}, false), //
+ C("any", utils::Vector{"vb"}, false), //
+ C("arrayLength", utils::Vector{"pstorage_arr"}, false), //
+ C("asin", utils::Vector{"f"}, false), //
+ C("asinh", utils::Vector{"f"}, false), //
+ C("atan", utils::Vector{"f"}, false), //
+ C("atan2", utils::Vector{"f", "f"}, false), //
+ C("atanh", utils::Vector{"f"}, false), //
+ C("atomicLoad", utils::Vector{"pa"}, false), //
+ C("ceil", utils::Vector{"f"}, false), //
+ C("clamp", utils::Vector{"f", "f", "f"}, false), //
+ C("cos", utils::Vector{"f"}, false), //
+ C("cosh", utils::Vector{"f"}, false), //
+ C("countLeadingZeros", utils::Vector{"i"}, false), //
+ C("countOneBits", utils::Vector{"i"}, false), //
+ C("countTrailingZeros", utils::Vector{"i"}, false), //
+ C("cross", utils::Vector{"vf", "vf"}, false), //
+ C("degrees", utils::Vector{"f"}, false), //
+ C("determinant", utils::Vector{"m"}, false), //
+ C("distance", utils::Vector{"f", "f"}, false), //
+ C("dot", utils::Vector{"vf", "vf"}, false), //
+ C("dot4I8Packed", utils::Vector{"u", "u"}, false), //
+ C("dot4U8Packed", utils::Vector{"u", "u"}, false), //
+ C("exp", utils::Vector{"f"}, false), //
+ C("exp2", utils::Vector{"f"}, false), //
+ C("extractBits", utils::Vector{"i", "u", "u"}, false), //
+ C("faceForward", utils::Vector{"vf", "vf", "vf"}, false), //
+ C("firstLeadingBit", utils::Vector{"u"}, false), //
+ C("firstTrailingBit", utils::Vector{"u"}, false), //
+ C("floor", utils::Vector{"f"}, false), //
+ C("fma", utils::Vector{"f", "f", "f"}, false), //
+ C("fract", utils::Vector{"vf"}, false), //
+ C("frexp", utils::Vector{"f"}, false), //
+ C("insertBits", utils::Vector{"i", "i", "u", "u"}, false), //
+ C("inverseSqrt", utils::Vector{"f"}, false), //
+ C("ldexp", utils::Vector{"f", "i"}, false), //
+ C("length", utils::Vector{"vf"}, false), //
+ C("log", utils::Vector{"f"}, false), //
+ C("log2", utils::Vector{"f"}, false), //
+ C("max", utils::Vector{"f", "f"}, false), //
+ C("min", utils::Vector{"f", "f"}, false), //
+ C("mix", utils::Vector{"f", "f", "f"}, false), //
+ C("modf", utils::Vector{"f"}, false), //
+ C("normalize", utils::Vector{"vf"}, false), //
+ C("pack2x16float", utils::Vector{"vf2"}, false), //
+ C("pack2x16snorm", utils::Vector{"vf2"}, false), //
+ C("pack2x16unorm", utils::Vector{"vf2"}, false), //
+ C("pack4x8snorm", utils::Vector{"vf4"}, false), //
+ C("pack4x8unorm", utils::Vector{"vf4"}, false), //
+ C("pow", utils::Vector{"f", "f"}, false), //
+ C("radians", utils::Vector{"f"}, false), //
+ C("reflect", utils::Vector{"vf", "vf"}, false), //
+ C("refract", utils::Vector{"vf", "vf", "f"}, false), //
+ C("reverseBits", utils::Vector{"u"}, false), //
+ C("round", utils::Vector{"f"}, false), //
+ C("select", utils::Vector{"f", "f", "b"}, false), //
+ C("sign", utils::Vector{"f"}, false), //
+ C("sin", utils::Vector{"f"}, false), //
+ C("sinh", utils::Vector{"f"}, false), //
+ C("smoothstep", utils::Vector{"f", "f", "f"}, false), //
+ C("sqrt", utils::Vector{"f"}, false), //
+ C("step", utils::Vector{"f", "f"}, false), //
+ C("tan", utils::Vector{"f"}, false), //
+ C("tanh", utils::Vector{"f"}, false), //
+ C("textureDimensions", utils::Vector{"t2d"}, false), //
+ C("textureGather", utils::Vector{"tdepth2d", "s2d", "vf2"}, false), //
+ C("textureGatherCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false), //
+ C("textureLoad", utils::Vector{"t2d", "vi2", "i"}, false), //
+ C("textureNumLayers", utils::Vector{"t2d_arr"}, false), //
+ C("textureNumLevels", utils::Vector{"t2d"}, false), //
+ C("textureNumSamples", utils::Vector{"t2d_multi"}, false), //
+ C("textureSampleCompareLevel", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false), //
+ C("textureSampleGrad", utils::Vector{"t2d", "s2d", "vf2", "vf2", "vf2"}, false), //
+ C("textureSampleLevel", utils::Vector{"t2d", "s2d", "vf2", "f"}, false), //
+ C("transpose", utils::Vector{"m"}, false), //
+ C("trunc", utils::Vector{"f"}, false), //
+ C("unpack2x16float", utils::Vector{"u"}, false), //
+ C("unpack2x16snorm", utils::Vector{"u"}, false), //
+ C("unpack2x16unorm", utils::Vector{"u"}, false), //
+ C("unpack4x8snorm", utils::Vector{"u"}, false), //
+ C("unpack4x8unorm", utils::Vector{"u"}, false), //
+ C("storageBarrier", utils::Empty, false, ast::PipelineStage::kCompute), //
+ C("workgroupBarrier", utils::Empty, false, ast::PipelineStage::kCompute), //
+ C("textureSample", utils::Vector{"t2d", "s2d", "vf2"}, false), //
+ C("textureSampleBias", utils::Vector{"t2d", "s2d", "vf2", "f"}, false), //
+ C("textureSampleCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false), //
+ C("dpdx", utils::Vector{"f"}, false), //
+ C("dpdxCoarse", utils::Vector{"f"}, false), //
+ C("dpdxFine", utils::Vector{"f"}, false), //
+ C("dpdy", utils::Vector{"f"}, false), //
+ C("dpdyCoarse", utils::Vector{"f"}, false), //
+ C("dpdyFine", utils::Vector{"f"}, false), //
+ C("fwidth", utils::Vector{"f"}, false), //
+ C("fwidthCoarse", utils::Vector{"f"}, false), //
+ C("fwidthFine", utils::Vector{"f"}, false), //
+
+ // Side-effect builtins
+ C("atomicAdd", utils::Vector{"pa", "i"}, true), //
+ C("atomicAnd", utils::Vector{"pa", "i"}, true), //
+ C("atomicCompareExchangeWeak", utils::Vector{"pa", "i", "i"}, true), //
+ C("atomicExchange", utils::Vector{"pa", "i"}, true), //
+ C("atomicMax", utils::Vector{"pa", "i"}, true), //
+ C("atomicMin", utils::Vector{"pa", "i"}, true), //
+ C("atomicOr", utils::Vector{"pa", "i"}, true), //
+ C("atomicStore", utils::Vector{"pa", "i"}, true), //
+ C("atomicSub", utils::Vector{"pa", "i"}, true), //
+ C("atomicXor", utils::Vector{"pa", "i"}, true), //
+ C("textureStore", utils::Vector{"tstorage2d", "vi2", "vf4"}, true), //
+
+ // Unimplemented builtins
+ // C("quantizeToF16", utils::Vector{"f"}, false), //
+ // C("saturate", utils::Vector{"f"}, false), //
+ }));
+
+} // namespace builtin
+
TEST_F(SideEffectsTest, Call_Function) {
- Func("f", {}, ty.i32(), {Return(1_i)});
+ Func("f", utils::Empty, ty.i32(), utils::Vector{Return(1_i)});
auto* expr = Call("f");
WrapInFunction(expr);
@@ -184,7 +408,7 @@ TEST_F(SideEffectsTest, Call_TypeConstructor_SE) {
}
TEST_F(SideEffectsTest, MemberAccessor_Struct_NoSE) {
- auto* s = Structure("S", {Member("m", ty.i32())});
+ auto* s = Structure("S", utils::Vector{Member("m", ty.i32())});
auto* var = Decl(Var("a", ty.Of(s)));
auto* expr = MemberAccessor("a", "m");
WrapInFunction(var, expr);
@@ -196,7 +420,7 @@ TEST_F(SideEffectsTest, MemberAccessor_Struct_NoSE) {
}
TEST_F(SideEffectsTest, MemberAccessor_Struct_SE) {
- auto* s = Structure("S", {Member("m", ty.i32())});
+ auto* s = Structure("S", utils::Vector{Member("m", ty.i32())});
MakeSideEffectFunc("se", [&] { return ty.Of(s); });
auto* expr = MemberAccessor(Call("se"), "m");
WrapInFunction(expr);
diff --git a/chromium/third_party/dawn/src/tint/resolver/source_variable_test.cc b/chromium/third_party/dawn/src/tint/resolver/source_variable_test.cc
index cd943f3635f..f80c980f7f2 100644
--- a/chromium/third_party/dawn/src/tint/resolver/source_variable_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/source_variable_test.cc
@@ -15,6 +15,7 @@
#include "src/tint/resolver/resolver.h"
#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/index_accessor_expression.h"
#include "src/tint/sem/member_accessor_expression.h"
using namespace tint::number_suffixes; // NOLINT
@@ -25,7 +26,7 @@ namespace {
class ResolverSourceVariableTest : public ResolverTest {};
TEST_F(ResolverSourceVariableTest, GlobalPrivateVar) {
- auto* a = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Expr(a);
WrapInFunction(expr);
@@ -36,7 +37,7 @@ TEST_F(ResolverSourceVariableTest, GlobalPrivateVar) {
}
TEST_F(ResolverSourceVariableTest, GlobalWorkgroupVar) {
- auto* a = Global("a", ty.f32(), ast::StorageClass::kWorkgroup);
+ auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kWorkgroup);
auto* expr = Expr(a);
WrapInFunction(expr);
@@ -47,7 +48,7 @@ TEST_F(ResolverSourceVariableTest, GlobalWorkgroupVar) {
}
TEST_F(ResolverSourceVariableTest, GlobalStorageVar) {
- auto* a = Global("a", ty.f32(), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
+ auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
auto* expr = Expr(a);
WrapInFunction(expr);
@@ -58,7 +59,7 @@ TEST_F(ResolverSourceVariableTest, GlobalStorageVar) {
}
TEST_F(ResolverSourceVariableTest, GlobalUniformVar) {
- auto* a = Global("a", ty.f32(), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+ auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
auto* expr = Expr(a);
WrapInFunction(expr);
@@ -69,8 +70,8 @@ TEST_F(ResolverSourceVariableTest, GlobalUniformVar) {
}
TEST_F(ResolverSourceVariableTest, GlobalTextureVar) {
- auto* a = Global("a", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
- ast::StorageClass::kNone, GroupAndBinding(0, 0));
+ auto* a = GlobalVar("a", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ ast::StorageClass::kNone, GroupAndBinding(0, 0));
auto* expr = Expr(a);
WrapInFunction(Call("textureDimensions", expr));
@@ -127,7 +128,7 @@ TEST_F(ResolverSourceVariableTest, FunctionLet) {
TEST_F(ResolverSourceVariableTest, Parameter) {
auto* a = Param("a", ty.f32());
auto* expr = Expr(a);
- Func("foo", {a}, ty.void_(), {WrapInStatement(expr)});
+ Func("foo", utils::Vector{a}, ty.void_(), utils::Vector{WrapInStatement(expr)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -144,7 +145,8 @@ TEST_F(ResolverSourceVariableTest, PointerParameter) {
auto* expr_param = Expr(param);
auto* let = Let("b", nullptr, expr_param);
auto* expr_let = Expr("b");
- Func("foo", {param}, ty.void_(), {WrapInStatement(let), WrapInStatement(expr_let)});
+ Func("foo", utils::Vector{param}, ty.void_(),
+ utils::Vector{WrapInStatement(let), WrapInStatement(expr_let)});
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -196,7 +198,7 @@ TEST_F(ResolverSourceVariableTest, ThroughIndexAccessor) {
// {
// a[2i]
// }
- auto* a = Global("a", ty.array(ty.f32(), 4_u), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.array(ty.f32(), 4_u), ast::StorageClass::kPrivate);
auto* expr = IndexAccessor(a, 2_i);
WrapInFunction(expr);
@@ -212,8 +214,8 @@ TEST_F(ResolverSourceVariableTest, ThroughMemberAccessor) {
// {
// a.f
// }
- auto* S = Structure("S", {Member("f", ty.f32())});
- auto* a = Global("a", ty.Of(S), ast::StorageClass::kPrivate);
+ auto* S = Structure("S", utils::Vector{Member("f", ty.f32())});
+ auto* a = GlobalVar("a", ty.Of(S), ast::StorageClass::kPrivate);
auto* expr = MemberAccessor(a, "f");
WrapInFunction(expr);
@@ -229,7 +231,7 @@ TEST_F(ResolverSourceVariableTest, ThroughPointers) {
// let a_ptr1 = &*&a;
// let a_ptr2 = &*a_ptr1;
// }
- auto* a = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
auto* address_of_1 = AddressOf(a);
auto* deref_1 = Deref(address_of_1);
auto* address_of_2 = AddressOf(deref_1);
diff --git a/chromium/third_party/dawn/src/tint/resolver/static_assert_test.cc b/chromium/third_party/dawn/src/tint/resolver/static_assert_test.cc
new file mode 100644
index 00000000000..3cb67c9ebd0
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/resolver/static_assert_test.cc
@@ -0,0 +1,110 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/resolver/resolver.h"
+
+#include "gmock/gmock.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+using ResolverStaticAssertTest = ResolverTest;
+
+TEST_F(ResolverStaticAssertTest, Global_True_Pass) {
+ GlobalStaticAssert(true);
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStaticAssertTest, Global_False_Fail) {
+ GlobalStaticAssert(Source{{12, 34}}, false);
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: static assertion failed");
+}
+
+TEST_F(ResolverStaticAssertTest, Global_Const_Pass) {
+ GlobalConst("C", ty.bool_(), Expr(true));
+ GlobalStaticAssert("C");
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStaticAssertTest, Global_Const_Fail) {
+ GlobalConst("C", ty.bool_(), Expr(false));
+ GlobalStaticAssert(Source{{12, 34}}, "C");
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: static assertion failed");
+}
+
+// TODO(crbug.com/tint/1581): Enable once the '<' operator is implemented for constant evaluation.
+TEST_F(ResolverStaticAssertTest, DISABLED_Global_LessThan_Pass) {
+ GlobalStaticAssert(LessThan(2_i, 3_i));
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+// TODO(crbug.com/tint/1581): Enable once the '<' operator is implemented for constant evaluation.
+TEST_F(ResolverStaticAssertTest, DISABLED_Global_LessThan_Fail) {
+ GlobalStaticAssert(Source{{12, 34}}, LessThan(4_i, 3_i));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: static assertion failed");
+}
+
+TEST_F(ResolverStaticAssertTest, Local_True_Pass) {
+ WrapInFunction(StaticAssert(true));
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStaticAssertTest, Local_False_Fail) {
+ WrapInFunction(StaticAssert(Source{{12, 34}}, false));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: static assertion failed");
+}
+
+TEST_F(ResolverStaticAssertTest, Local_Const_Pass) {
+ GlobalConst("C", ty.bool_(), Expr(true));
+ WrapInFunction(StaticAssert("C"));
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStaticAssertTest, Local_Const_Fail) {
+ GlobalConst("C", ty.bool_(), Expr(false));
+ WrapInFunction(StaticAssert(Source{{12, 34}}, "C"));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: static assertion failed");
+}
+
+TEST_F(ResolverStaticAssertTest, Local_NonConst) {
+ GlobalVar("V", ty.bool_(), Expr(true), ast::StorageClass::kPrivate);
+ WrapInFunction(StaticAssert(Expr(Source{{12, 34}}, "V")));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: static assertion condition must be a constant expression");
+}
+
+// TODO(crbug.com/tint/1581): Enable once the '<' operator is implemented for constant evaluation.
+TEST_F(ResolverStaticAssertTest, DISABLED_Local_LessThan_Pass) {
+ WrapInFunction(StaticAssert(LessThan(2_i, 3_i)));
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+// TODO(crbug.com/tint/1581): Enable once the '<' operator is implemented for constant evaluation.
+TEST_F(ResolverStaticAssertTest, DISABLED_Local_LessThan_Fail) {
+ WrapInFunction(StaticAssert(Source{{12, 34}}, LessThan(4_i, 3_i)));
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: static assertion failed");
+}
+
+} // namespace
+} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/storage_class_layout_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/storage_class_layout_validation_test.cc
index db379a062bf..c55aece2862 100644
--- a/chromium/third_party/dawn/src/tint/resolver/storage_class_layout_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/storage_class_layout_validation_test.cc
@@ -34,11 +34,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember)
// var<storage> a : S;
Structure(Source{{12, 34}}, "S",
- {Member("a", ty.f32(), {MemberSize(5)}),
- Member(Source{{34, 56}}, "b", ty.f32(), {MemberAlign(1)})});
+ utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberSize(5)}),
+ Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1)}),
+ });
- Global(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -62,11 +64,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember_S
// var<storage> a : S;
Structure(Source{{12, 34}}, "S",
- {Member("a", ty.f32(), {MemberSize(5)}),
- Member(Source{{34, 56}}, "b", ty.f32(), {MemberAlign(4)})});
+ utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberSize(5)}),
+ Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4)}),
+ });
- Global(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
+ GroupAndBinding(0, 0));
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -85,16 +89,19 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_S
// @group(0) @binding(0)
// var<uniform> a : Outer;
- Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
+ Structure(Source{{12, 34}}, "Inner",
+ utils::Vector{
+ Member("scalar", ty.i32()),
+ });
Structure(Source{{34, 56}}, "Outer",
- {
+ utils::Vector{
Member("scalar", ty.f32()),
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -126,16 +133,20 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// @group(0) @binding(0)
// var<uniform> a : Outer;
- Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
+ Structure(Source{{12, 34}}, "Inner",
+ utils::Vector{
+ Member("scalar", ty.i32()),
+ });
Structure(Source{{34, 56}}, "Outer",
- {
+ utils::Vector{
Member("scalar", ty.f32()),
- Member(Source{{56, 78}}, "inner", ty.type_name("Inner"), {MemberAlign(16)}),
+ Member(Source{{56, 78}}, "inner", ty.type_name("Inner"),
+ utils::Vector{MemberAlign(16)}),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -154,13 +165,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_A
Alias("Inner", ty.array(ty.f32(), 10_u, 16));
Structure(Source{{12, 34}}, "Outer",
- {
+ utils::Vector{
Member("scalar", ty.f32()),
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -187,13 +198,14 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_A
Alias("Inner", ty.array(ty.f32(), 10_u, 16));
Structure(Source{{12, 34}}, "Outer",
- {
+ utils::Vector{
Member("scalar", ty.f32()),
- Member(Source{{34, 56}}, "inner", ty.type_name("Inner"), {MemberAlign(16)}),
+ Member(Source{{34, 56}}, "inner", ty.type_name("Inner"),
+ utils::Vector{MemberAlign(16)}),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -214,16 +226,18 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_MembersOffsetNotM
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner",
- {Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)})});
+ utils::Vector{
+ Member("scalar", ty.i32(), utils::Vector{MemberAlign(1), MemberSize(5)}),
+ });
Structure(Source{{34, 56}}, "Outer",
- {
+ utils::Vector{
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
Member(Source{{78, 90}}, "scalar", ty.i32()),
});
- Global(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -261,21 +275,21 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner",
- {
+ utils::Vector{
Member("a", ty.i32()),
Member("b", ty.i32()),
Member("c", ty.i32()),
- Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)}),
+ Member("scalar", ty.i32(), utils::Vector{MemberAlign(1), MemberSize(5)}),
});
Structure(Source{{34, 56}}, "Outer",
- {
+ utils::Vector{
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
Member(Source{{78, 90}}, "scalar", ty.i32()),
});
- Global(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -312,16 +326,18 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner",
- {Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)})});
+ utils::Vector{
+ Member("scalar", ty.i32(), utils::Vector{MemberAlign(1), MemberSize(5)}),
+ });
Structure(Source{{34, 56}}, "Outer",
- {
+ utils::Vector{
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
- Member(Source{{78, 90}}, "scalar", ty.i32(), {MemberAlign(16)}),
+ Member(Source{{78, 90}}, "scalar", ty.i32(), utils::Vector{MemberAlign(16)}),
});
- Global(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -336,13 +352,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_Vec3MemberOffset_
// @group(0) @binding(0)
// var<uniform> a : ScalarPackedAtEndOfVec3;
- Structure("ScalarPackedAtEndOfVec3", {
+ Structure("ScalarPackedAtEndOfVec3", utils::Vector{
Member("v", ty.vec3(ty.f32())),
Member("s", ty.f32()),
});
- Global(Source{{78, 90}}, "a", ty.type_name("ScalarPackedAtEndOfVec3"),
- ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("ScalarPackedAtEndOfVec3"),
+ ast::StorageClass::kUniform, GroupAndBinding(0, 0));
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -362,13 +378,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
Alias("Inner", ty.array(ty.f32(), 10_u));
Structure(Source{{12, 34}}, "Outer",
- {
+ utils::Vector{
Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
Member("scalar", ty.i32()),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -396,13 +412,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
Alias("Inner", ty.array(ty.vec2<f32>(), 10_u));
Structure(Source{{12, 34}}, "Outer",
- {
+ utils::Vector{
Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
Member("scalar", ty.i32()),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -432,20 +448,20 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
// @group(0) @binding(0)
// var<uniform> a : Outer;
- auto* array_elem = Structure("ArrayElem", {
+ auto* array_elem = Structure("ArrayElem", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.i32()),
});
Alias("Inner", ty.array(ty.Of(array_elem), 10_u));
Structure(Source{{12, 34}}, "Outer",
- {
+ utils::Vector{
Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
Member("scalar", ty.i32()),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -462,8 +478,8 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_TopLevelArray) {
// @group(0) @binding(0)
// var<uniform> a : array<f32, 4u>;
- Global(Source{{78, 90}}, "a", ty.array(Source{{34, 56}}, ty.f32(), 4_u),
- ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.array(Source{{34, 56}}, ty.f32(), 4_u),
+ ast::StorageClass::kUniform, GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -480,12 +496,12 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
// var<uniform> a : array<Outer, 4u>;
Structure(Source{{12, 34}}, "Outer",
- {
+ utils::Vector{
Member("inner", ty.array(Source{{34, 56}}, ty.array(ty.f32(), 4_u), 4_u)),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
@@ -512,13 +528,56 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
Alias("Inner", ty.array(ty.f32(), 10_u, 16));
Structure(Source{{12, 34}}, "Outer",
- {
+ utils::Vector{
Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
Member("scalar", ty.i32()),
});
- Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
- GroupAndBinding(0, 0));
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+ GroupAndBinding(0, 0));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+// Detect unaligned member for push constants buffers
+TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_UnalignedMember) {
+ // enable chromium_experimental_push_constant;
+ // struct S {
+ // @size(5) a : f32;
+ // @align(1) b : f32;
+ // };
+ // var<push_constant> a : S;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ Structure(
+ Source{{12, 34}}, "S",
+ utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5)}),
+ Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1)})});
+ GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kPushConstant);
+
+ ASSERT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(34:56 error: the offset of a struct member of type 'f32' in storage class 'push_constant' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
+12:34 note: see layout of struct:
+/* align(4) size(12) */ struct S {
+/* offset(0) align(4) size( 5) */ a : f32;
+/* offset(5) align(1) size( 4) */ b : f32;
+/* offset(9) align(1) size( 3) */ // -- implicit struct size padding --;
+/* */ };
+78:90 note: see declaration of variable)");
+}
+
+TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_Aligned) {
+ // enable chromium_experimental_push_constant;
+ // struct S {
+ // @size(5) a : f32;
+ // @align(4) b : f32;
+ // };
+ // var<push_constant> a : S;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(4)})});
+ GlobalVar("a", ty.type_name("S"), ast::StorageClass::kPushConstant);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
diff --git a/chromium/third_party/dawn/src/tint/resolver/storage_class_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/storage_class_validation_test.cc
index 2d75167ea83..e1b3dab4269 100644
--- a/chromium/third_party/dawn/src/tint/resolver/storage_class_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/storage_class_validation_test.cc
@@ -23,188 +23,329 @@ using namespace tint::number_suffixes; // NOLINT
namespace tint::resolver {
namespace {
+using ::testing::HasSubstr;
+
using ResolverStorageClassValidationTest = ResolverTest;
TEST_F(ResolverStorageClassValidationTest, GlobalVariableNoStorageClass_Fail) {
// var g : f32;
- Global(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kNone);
+ GlobalVar(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kNone);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: global variables must have a storage class");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: module-scope 'var' declaration must have a storage class");
}
TEST_F(ResolverStorageClassValidationTest, GlobalVariableFunctionStorageClass_Fail) {
// var<function> g : f32;
- Global(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kFunction);
+ GlobalVar(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kFunction);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: variables declared at module scope must not be in "
- "the function storage class");
+ "12:34 error: module-scope 'var' must not use storage class 'function'");
}
TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArray) {
- Global(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kPrivate);
+ GlobalVar(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
-12:34 note: while instantiating variable v)");
+12:34 note: while instantiating 'var' v)");
}
TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArrayInStruct) {
- auto* s = Structure("S", {Member("m", ty.array(ty.i32()))});
- Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kPrivate);
+ auto* s = Structure("S", utils::Vector{Member("m", ty.array(ty.i32()))});
+ GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
note: while analysing structure member S.m
-12:34 note: while instantiating variable v)");
+12:34 note: while instantiating 'var' v)");
}
TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArray) {
- Global(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kWorkgroup);
+ GlobalVar(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kWorkgroup);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
-12:34 note: while instantiating variable v)");
+12:34 note: while instantiating 'var' v)");
}
TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArrayInStruct) {
- auto* s = Structure("S", {Member("m", ty.array(ty.i32()))});
- Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kWorkgroup);
+ auto* s = Structure("S", utils::Vector{Member("m", ty.array(ty.i32()))});
+ GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kWorkgroup);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
note: while analysing structure member S.m
-12:34 note: while instantiating variable v)");
+12:34 note: while instantiating 'var' v)");
}
TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
// var<storage> g : bool;
- Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(
+ r()->error(),
+ R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
+56:78 note: while instantiating 'var' g)");
+}
+
+TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
+ // type a = bool;
+ // var<storage, read> g : a;
+ auto* a = Alias("a", ty.bool_());
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
+}
+
+// F16 types in storage and uniform buffer is not implemented yet.
+// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
+TEST_F(ResolverStorageClassValidationTest, StorageBufferF16_TemporallyBan) {
+ // var<storage> g : f16;
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ "56:78 error: using f16 types in 'storage' storage class is not "
+ "implemented yet");
+}
+
+TEST_F(ResolverStorageClassValidationTest, StorageBufferF16Alias_TemporallyBan) {
+ // type a = f16;
+ // var<storage, read> g : a;
+ Enable(ast::Extension::kF16);
+
+ auto* a = Alias("a", ty.f16());
+ GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ "56:78 error: using f16 types in 'storage' storage class is not "
+ "implemented yet");
+}
+
+TEST_F(ResolverStorageClassValidationTest, StorageBufferVectorF16_TemporallyBan) {
+ // var<storage> g : vec4<f16>;
+ Enable(ast::Extension::kF16);
+ GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ "56:78 error: using f16 types in 'storage' storage class is not "
+ "implemented yet");
+}
+
+TEST_F(ResolverStorageClassValidationTest, StorageBufferArrayF16_TemporallyBan) {
+ // struct S { a : f16 };
+ // var<storage, read> g : array<S, 3u>;
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f16(Source{{56, 78}}))});
+ auto* a = ty.array(ty.Of(s), 3_u);
+ GlobalVar("g", a, ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'storage' storage "
+ "class is not implemented yet"));
+}
+
+TEST_F(ResolverStorageClassValidationTest, StorageBufferStructF16_TemporallyBan) {
+ // struct S { x : f16 };
+ // var<storage, read> g : S;
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'storage' storage "
+ "class is not implemented yet"));
+}
+
+TEST_F(ResolverStorageClassValidationTest, StorageBufferNoErrorStructF16Aliases_TemporallyBan) {
+ // struct S { x : f16 };
+ // type a1 = S;
+ // var<storage, read> g : a1;
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
+ auto* a1 = Alias("a1", ty.Of(s));
+ auto* a2 = Alias("a2", ty.Of(a1));
+ GlobalVar("g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'storage' storage "
+ "class is not implemented yet"));
}
TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
// var<storage> g : ptr<private, f32>;
- Global(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
- ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
+ ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'storage' as it is non-host-shareable
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
}
TEST_F(ResolverStorageClassValidationTest, StorageBufferIntScalar) {
// var<storage> g : i32;
- Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverStorageClassValidationTest, StorageBufferVector) {
+TEST_F(ResolverStorageClassValidationTest, StorageBufferVectorF32) {
// var<storage> g : vec4<f32>;
- Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
+TEST_F(ResolverStorageClassValidationTest, StorageBufferArrayF32) {
// var<storage, read> g : array<S, 3u>;
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
auto* a = ty.array(ty.Of(s), 3_u);
- Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
- // type a = bool;
- // var<storage, read> g : a;
- auto* a = Alias("a", ty.bool_());
- Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+TEST_F(ResolverStorageClassValidationTest, NotStorage_AccessMode) {
+ // var<private, read> g : a;
+ GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate, ast::Access::kRead);
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
- R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
-56:78 note: while instantiating variable g)");
+ R"(56:78 error: only variables in <storage> storage class may declare an access mode)");
}
-TEST_F(ResolverStorageClassValidationTest, NotStorage_AccessMode) {
- // var<private, read> g : a;
- Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate, ast::Access::kRead);
+TEST_F(ResolverStorageClassValidationTest, Storage_ReadAccessMode) {
+ // @group(0) @binding(0) var<storage, read> a : i32;
+ GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStorageClassValidationTest, Storage_ReadWriteAccessMode) {
+ // @group(0) @binding(0) var<storage, read_write> a : i32;
+ GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ GroupAndBinding(0, 0));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStorageClassValidationTest, Storage_WriteAccessMode) {
+ // @group(0) @binding(0) var<storage, read_write> a : i32;
+ GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kWrite,
+ GroupAndBinding(0, 0));
ASSERT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- R"(56:78 error: only variables in <storage> storage class may declare an access mode)");
+ EXPECT_EQ(r()->error(),
+ R"(56:78 error: access mode 'write' is not valid for the 'storage' address space)");
}
-TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
+TEST_F(ResolverStorageClassValidationTest, StorageBufferStructI32) {
// struct S { x : i32 };
// var<storage, read> g : S;
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
- Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve());
}
-TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
+TEST_F(ResolverStorageClassValidationTest, StorageBufferNoErrorStructI32Aliases) {
// struct S { x : i32 };
// type a1 = S;
// var<storage, read> g : a1;
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
auto* a1 = Alias("a1", ty.Of(s));
auto* a2 = Alias("a2", ty.Of(a1));
- Global(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve());
}
@@ -213,137 +354,334 @@ TEST_F(ResolverStorageClassValidationTest, UniformBuffer_Struct_Runtime) {
// struct S { m: array<f32>; };
// @group(0) @binding(0) var<uniform, > svar : S;
- auto* s = Structure(Source{{12, 34}}, "S", {Member("m", ty.array<i32>())});
+ auto* s = Structure(Source{{12, 34}}, "S", utils::Vector{Member("m", ty.array<i32>())});
- Global(Source{{56, 78}}, "svar", ty.Of(s), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "svar", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
note: while analysing structure member S.m
-56:78 note: while instantiating variable svar)");
+56:78 note: while instantiating 'var' svar)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
// var<uniform> g : bool;
- Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(
+ r()->error(),
+ R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
+56:78 note: while instantiating 'var' g)");
+}
+
+TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
+ // type a = bool;
+ // var<uniform> g : a;
+ auto* a = Alias("a", ty.bool_());
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
+}
+
+// F16 types in storage and uniform buffer is not implemented yet.
+// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
+TEST_F(ResolverStorageClassValidationTest, UniformBufferF16_TemporallyBan) {
+ // var<uniform> g : f16;
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ "56:78 error: using f16 types in 'uniform' storage class is not "
+ "implemented yet");
+}
+
+TEST_F(ResolverStorageClassValidationTest, UniformBufferF16Alias_TemporallyBan) {
+ // type a = f16;
+ // var<uniform> g : a;
+ Enable(ast::Extension::kF16);
+
+ auto* a = Alias("a", ty.f16());
+ GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ "56:78 error: using f16 types in 'uniform' storage class is not "
+ "implemented yet");
+}
+
+TEST_F(ResolverStorageClassValidationTest, UniformBufferVectorF16_TemporallyBan) {
+ // var<uniform> g : vec4<f16>;
+ Enable(ast::Extension::kF16);
+ GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'uniform' storage "
+ "class is not implemented yet"));
+}
+
+TEST_F(ResolverStorageClassValidationTest, UniformBufferArrayF16_TemporallyBan) {
+ // struct S {
+ // @size(16) f : f16;
+ // }
+ // var<uniform> g : array<S, 3u>;
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure(
+ "S", utils::Vector{Member("a", ty.f16(Source{{56, 78}}), utils::Vector{MemberSize(16)})});
+ auto* a = ty.array(ty.Of(s), 3_u);
+ GlobalVar("g", a, ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'uniform' storage "
+ "class is not implemented yet"));
+}
+
+TEST_F(ResolverStorageClassValidationTest, UniformBufferStructF16_TemporallyBan) {
+ // struct S { x : f16 };
+ // var<uniform> g : S;
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'uniform' storage "
+ "class is not implemented yet"));
+}
+
+TEST_F(ResolverStorageClassValidationTest, UniformBufferStructF16Aliases_TemporallyBan) {
+ // struct S { x : f16 };
+ // type a1 = S;
+ // var<uniform> g : a1;
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
+ auto* a1 = Alias("a1", ty.Of(s));
+ GlobalVar("g", ty.Of(a1), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'uniform' storage "
+ "class is not implemented yet"));
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
// var<uniform> g : ptr<private, f32>;
- Global(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
- ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
+ ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'uniform' as it is non-host-shareable
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferIntScalar) {
// var<uniform> g : i32;
- Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverStorageClassValidationTest, UniformBufferVector) {
+TEST_F(ResolverStorageClassValidationTest, UniformBufferVectorF32) {
// var<uniform> g : vec4<f32>;
- Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
+TEST_F(ResolverStorageClassValidationTest, UniformBufferArrayF32) {
// struct S {
// @size(16) f : f32;
// }
// var<uniform> g : array<S, 3u>;
- auto* s = Structure("S", {Member("a", ty.f32(), {MemberSize(16)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(16)})});
auto* a = ty.array(ty.Of(s), 3_u);
- Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
- // type a = bool;
- // var<uniform> g : a;
- auto* a = Alias("a", ty.bool_());
- Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+TEST_F(ResolverStorageClassValidationTest, UniformBufferStructI32) {
+ // struct S { x : i32 };
+ // var<uniform> g : S;
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStorageClassValidationTest, UniformBufferStructI32Aliases) {
+ // struct S { x : i32 };
+ // type a1 = S;
+ // var<uniform> g : a1;
+ auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
+ auto* a1 = Alias("a1", ty.Of(s));
+ GlobalVar(Source{{56, 78}}, "g", ty.Of(a1), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStorageClassValidationTest, PushConstantBool) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> g : bool;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kPushConstant);
+
+ ASSERT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(56:78 error: Type 'bool' cannot be used in storage class 'push_constant' as it is non-host-shareable
+56:78 note: while instantiating 'var' g)");
+}
+
+TEST_F(ResolverStorageClassValidationTest, PushConstantF16) {
+ // enable chromium_experimental_push_constant;
+ // enable f16;
+ // var<push_constant> g : f16;
+ Enable(ast::Extension::kF16);
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kPushConstant);
ASSERT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "56:78 error: using f16 types in 'push_constant' storage class is not "
+ "implemented yet");
+}
+TEST_F(ResolverStorageClassValidationTest, PushConstantPointer) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> g : ptr<private, f32>;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
+ ast::StorageClass::kPushConstant);
+
+ ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
- R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
-56:78 note: while instantiating variable g)");
+ R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'push_constant' as it is non-host-shareable
+56:78 note: while instantiating 'var' g)");
}
-TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
- // struct S { x : i32 };
- // var<uniform> g : S;
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
- Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+TEST_F(ResolverStorageClassValidationTest, PushConstantIntScalar) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> g : i32;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar("g", ty.i32(), ast::StorageClass::kPushConstant);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
- // struct S { x : i32 };
- // type a1 = S;
- // var<uniform> g : a1;
- auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
- auto* a1 = Alias("a1", ty.Of(s));
- Global(Source{{56, 78}}, "g", ty.Of(a1), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+TEST_F(ResolverStorageClassValidationTest, PushConstantVectorF32) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> g : vec4<f32>;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPushConstant);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
+TEST_F(ResolverStorageClassValidationTest, PushConstantArrayF32) {
+ // enable chromium_experimental_push_constant;
+ // struct S { a : f32}
+ // var<push_constant> g : array<S, 3u>;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
+ auto* a = ty.array(ty.Of(s), 3_u);
+ GlobalVar("g", a, ast::StorageClass::kPushConstant);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverStorageClassValidationTest, PushConstantWithInitializer) {
+ // enable chromium_experimental_push_constant;
+ // var<push_constant> a : u32 = 0u;
+ Enable(ast::Extension::kChromiumExperimentalPushConstant);
+ GlobalVar(Source{{1u, 2u}}, "a", ty.u32(), ast::StorageClass::kPushConstant,
+ Expr(Source{{3u, 4u}}, u32(0)));
+
+ ASSERT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(1:2 error: var of storage class 'push_constant' cannot have an initializer. var initializers are only supported for the storage classes 'private' and 'function')");
+}
+
} // namespace
} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/struct_layout_test.cc b/chromium/third_party/dawn/src/tint/resolver/struct_layout_test.cc
index 854e87ae3ea..59faf8d2920 100644
--- a/chromium/third_party/dawn/src/tint/resolver/struct_layout_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/struct_layout_test.cc
@@ -26,7 +26,7 @@ namespace {
using ResolverStructLayoutTest = ResolverTest;
TEST_F(ResolverStructLayoutTest, Scalars) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.u32()),
Member("c", ty.i32()),
@@ -49,13 +49,67 @@ TEST_F(ResolverStructLayoutTest, Scalars) {
EXPECT_EQ(sem->Members()[2]->Offset(), 8u);
EXPECT_EQ(sem->Members()[2]->Align(), 4u);
EXPECT_EQ(sem->Members()[2]->Size(), 4u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
+}
+
+TEST_F(ResolverStructLayoutTest, ScalarsWithF16) {
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.f32()),
+ Member("b", ty.f16()),
+ Member("c", ty.u32()),
+ Member("d", ty.f16()),
+ Member("e", ty.f16()),
+ Member("f", ty.i32()),
+ Member("g", ty.f16()),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = TypeOf(s)->As<sem::Struct>();
+ ASSERT_NE(sem, nullptr);
+ EXPECT_EQ(sem->Size(), 24u);
+ EXPECT_EQ(sem->SizeNoPadding(), 22u);
+ EXPECT_EQ(sem->Align(), 4u);
+ ASSERT_EQ(sem->Members().size(), 7u);
+ // f32
+ EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+ EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+ // f16
+ EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
+ EXPECT_EQ(sem->Members()[1]->Align(), 2u);
+ EXPECT_EQ(sem->Members()[1]->Size(), 2u);
+ // u32
+ EXPECT_EQ(sem->Members()[2]->Offset(), 8u);
+ EXPECT_EQ(sem->Members()[2]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[2]->Size(), 4u);
+ // f16
+ EXPECT_EQ(sem->Members()[3]->Offset(), 12u);
+ EXPECT_EQ(sem->Members()[3]->Align(), 2u);
+ EXPECT_EQ(sem->Members()[3]->Size(), 2u);
+ // f16
+ EXPECT_EQ(sem->Members()[4]->Offset(), 14u);
+ EXPECT_EQ(sem->Members()[4]->Align(), 2u);
+ EXPECT_EQ(sem->Members()[4]->Size(), 2u);
+ // i32
+ EXPECT_EQ(sem->Members()[5]->Offset(), 16u);
+ EXPECT_EQ(sem->Members()[5]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[5]->Size(), 4u);
+ // f16
+ EXPECT_EQ(sem->Members()[6]->Offset(), 20u);
+ EXPECT_EQ(sem->Members()[6]->Align(), 2u);
+ EXPECT_EQ(sem->Members()[6]->Size(), 2u);
}
TEST_F(ResolverStructLayoutTest, Alias) {
auto* alias_a = Alias("a", ty.f32());
auto* alias_b = Alias("b", ty.f32());
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.Of(alias_a)),
Member("b", ty.Of(alias_b)),
});
@@ -74,62 +128,93 @@ TEST_F(ResolverStructLayoutTest, Alias) {
EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
EXPECT_EQ(sem->Members()[1]->Align(), 4u);
EXPECT_EQ(sem->Members()[1]->Size(), 4u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
- auto* s = Structure("S", {
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.array<i32, 3>()),
Member("b", ty.array<f32, 5>()),
- Member("c", ty.array<f32, 1>()),
+ Member("c", ty.array<f16, 7>()),
+ Member("d", ty.array<f32, 1>()),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr);
- EXPECT_EQ(sem->Size(), 36u);
- EXPECT_EQ(sem->SizeNoPadding(), 36u);
+ EXPECT_EQ(sem->Size(), 52u);
+ EXPECT_EQ(sem->SizeNoPadding(), 52u);
EXPECT_EQ(sem->Align(), 4u);
- ASSERT_EQ(sem->Members().size(), 3u);
+ ASSERT_EQ(sem->Members().size(), 4u);
+ // array<i32, 3>
EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 12u);
+ // array<f32, 5>
EXPECT_EQ(sem->Members()[1]->Offset(), 12u);
EXPECT_EQ(sem->Members()[1]->Align(), 4u);
EXPECT_EQ(sem->Members()[1]->Size(), 20u);
+ // array<f16, 7>
EXPECT_EQ(sem->Members()[2]->Offset(), 32u);
- EXPECT_EQ(sem->Members()[2]->Align(), 4u);
- EXPECT_EQ(sem->Members()[2]->Size(), 4u);
+ EXPECT_EQ(sem->Members()[2]->Align(), 2u);
+ EXPECT_EQ(sem->Members()[2]->Size(), 14u);
+ // array<f32, 1>
+ EXPECT_EQ(sem->Members()[3]->Offset(), 48u);
+ EXPECT_EQ(sem->Members()[3]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[3]->Size(), 4u);
+
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
- auto* s = Structure("S", {
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.array<i32, 3>(/*stride*/ 8)),
Member("b", ty.array<f32, 5>(/*stride*/ 16)),
- Member("c", ty.array<f32, 1>(/*stride*/ 32)),
+ Member("c", ty.array<f16, 7>(/*stride*/ 4)),
+ Member("d", ty.array<f32, 1>(/*stride*/ 32)),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr);
- EXPECT_EQ(sem->Size(), 136u);
- EXPECT_EQ(sem->SizeNoPadding(), 136u);
+ EXPECT_EQ(sem->Size(), 164u);
+ EXPECT_EQ(sem->SizeNoPadding(), 164u);
EXPECT_EQ(sem->Align(), 4u);
- ASSERT_EQ(sem->Members().size(), 3u);
+ ASSERT_EQ(sem->Members().size(), 4u);
+ // array<i32, 3>, stride = 8
EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 24u);
+ // array<f32, 5>, stride = 16
EXPECT_EQ(sem->Members()[1]->Offset(), 24u);
EXPECT_EQ(sem->Members()[1]->Align(), 4u);
EXPECT_EQ(sem->Members()[1]->Size(), 80u);
+ // array<f16, 7>, stride = 4
EXPECT_EQ(sem->Members()[2]->Offset(), 104u);
- EXPECT_EQ(sem->Members()[2]->Align(), 4u);
- EXPECT_EQ(sem->Members()[2]->Size(), 32u);
+ EXPECT_EQ(sem->Members()[2]->Align(), 2u);
+ EXPECT_EQ(sem->Members()[2]->Size(), 28u);
+ // array<f32, 1>, stride = 32
+ EXPECT_EQ(sem->Members()[3]->Offset(), 132u);
+ EXPECT_EQ(sem->Members()[3]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[3]->Size(), 32u);
+
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("c", ty.array<f32>()),
});
@@ -144,10 +229,13 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("c", ty.array<f32>(/*stride*/ 32)),
});
@@ -162,12 +250,15 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 32u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
auto* inner = ty.array<i32, 2>(/*stride*/ 16); // size: 32
auto* outer = ty.array(inner, 12_u); // size: 12 * 32
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("c", outer),
});
@@ -182,16 +273,19 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 384u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec2<i32>()),
Member("b", ty.vec3<i32>()),
Member("c", ty.vec4<i32>()),
}); // size: 48
auto* outer = ty.array(ty.Of(inner), 12_u); // size: 12 * 48
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("c", outer),
});
@@ -206,10 +300,13 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 16u);
EXPECT_EQ(sem->Members()[0]->Size(), 576u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, Vector) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.vec2<i32>()),
Member("b", ty.vec3<i32>()),
Member("c", ty.vec4<i32>()),
@@ -232,63 +329,108 @@ TEST_F(ResolverStructLayoutTest, Vector) {
EXPECT_EQ(sem->Members()[2]->Offset(), 32u); // vec4
EXPECT_EQ(sem->Members()[2]->Align(), 16u);
EXPECT_EQ(sem->Members()[2]->Size(), 16u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, Matrix) {
- auto* s = Structure("S", {
- Member("a", ty.mat2x2<f32>()),
- Member("b", ty.mat2x3<f32>()),
- Member("c", ty.mat2x4<f32>()),
- Member("d", ty.mat3x2<f32>()),
- Member("e", ty.mat3x3<f32>()),
- Member("f", ty.mat3x4<f32>()),
- Member("g", ty.mat4x2<f32>()),
- Member("h", ty.mat4x3<f32>()),
- Member("i", ty.mat4x4<f32>()),
+ Enable(ast::Extension::kF16);
+
+ auto* s = Structure("S", utils::Vector{
+ Member("a_1", ty.mat2x2<f32>()),
+ Member("a_2", ty.mat2x2<f16>()),
+ Member("b_1", ty.mat2x3<f32>()),
+ Member("b_2", ty.mat2x3<f16>()),
+ Member("c_1", ty.mat2x4<f32>()),
+ Member("c_2", ty.mat2x4<f16>()),
+ Member("d_1", ty.mat3x2<f32>()),
+ Member("d_2", ty.mat3x2<f16>()),
+ Member("e_1", ty.mat3x3<f32>()),
+ Member("e_2", ty.mat3x3<f16>()),
+ Member("f_1", ty.mat3x4<f32>()),
+ Member("f_2", ty.mat3x4<f16>()),
+ Member("g_1", ty.mat4x2<f32>()),
+ Member("g_2", ty.mat4x2<f16>()),
+ Member("h_1", ty.mat4x3<f32>()),
+ Member("h_2", ty.mat4x3<f16>()),
+ Member("i_1", ty.mat4x4<f32>()),
+ Member("i_2", ty.mat4x4<f16>()),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr);
- EXPECT_EQ(sem->Size(), 368u);
- EXPECT_EQ(sem->SizeNoPadding(), 368u);
+ EXPECT_EQ(sem->Size(), 576u);
+ EXPECT_EQ(sem->SizeNoPadding(), 576u);
EXPECT_EQ(sem->Align(), 16u);
- ASSERT_EQ(sem->Members().size(), 9u);
- EXPECT_EQ(sem->Members()[0]->Offset(), 0u); // mat2x2
+ ASSERT_EQ(sem->Members().size(), 18u);
+ EXPECT_EQ(sem->Members()[0]->Offset(), 0u); // mat2x2<f32>
EXPECT_EQ(sem->Members()[0]->Align(), 8u);
EXPECT_EQ(sem->Members()[0]->Size(), 16u);
- EXPECT_EQ(sem->Members()[1]->Offset(), 16u); // mat2x3
- EXPECT_EQ(sem->Members()[1]->Align(), 16u);
- EXPECT_EQ(sem->Members()[1]->Size(), 32u);
- EXPECT_EQ(sem->Members()[2]->Offset(), 48u); // mat2x4
+ EXPECT_EQ(sem->Members()[1]->Offset(), 16u); // mat2x2<f16>
+ EXPECT_EQ(sem->Members()[1]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[1]->Size(), 8u);
+ EXPECT_EQ(sem->Members()[2]->Offset(), 32u); // mat2x3<f32>
EXPECT_EQ(sem->Members()[2]->Align(), 16u);
EXPECT_EQ(sem->Members()[2]->Size(), 32u);
- EXPECT_EQ(sem->Members()[3]->Offset(), 80u); // mat3x2
+ EXPECT_EQ(sem->Members()[3]->Offset(), 64u); // mat2x3<f16>
EXPECT_EQ(sem->Members()[3]->Align(), 8u);
- EXPECT_EQ(sem->Members()[3]->Size(), 24u);
- EXPECT_EQ(sem->Members()[4]->Offset(), 112u); // mat3x3
+ EXPECT_EQ(sem->Members()[3]->Size(), 16u);
+ EXPECT_EQ(sem->Members()[4]->Offset(), 80u); // mat2x4<f32>
EXPECT_EQ(sem->Members()[4]->Align(), 16u);
- EXPECT_EQ(sem->Members()[4]->Size(), 48u);
- EXPECT_EQ(sem->Members()[5]->Offset(), 160u); // mat3x4
- EXPECT_EQ(sem->Members()[5]->Align(), 16u);
- EXPECT_EQ(sem->Members()[5]->Size(), 48u);
- EXPECT_EQ(sem->Members()[6]->Offset(), 208u); // mat4x2
+ EXPECT_EQ(sem->Members()[4]->Size(), 32u);
+ EXPECT_EQ(sem->Members()[5]->Offset(), 112u); // mat2x4<f16>
+ EXPECT_EQ(sem->Members()[5]->Align(), 8u);
+ EXPECT_EQ(sem->Members()[5]->Size(), 16u);
+ EXPECT_EQ(sem->Members()[6]->Offset(), 128u); // mat3x2<f32>
EXPECT_EQ(sem->Members()[6]->Align(), 8u);
- EXPECT_EQ(sem->Members()[6]->Size(), 32u);
- EXPECT_EQ(sem->Members()[7]->Offset(), 240u); // mat4x3
- EXPECT_EQ(sem->Members()[7]->Align(), 16u);
- EXPECT_EQ(sem->Members()[7]->Size(), 64u);
- EXPECT_EQ(sem->Members()[8]->Offset(), 304u); // mat4x4
+ EXPECT_EQ(sem->Members()[6]->Size(), 24u);
+ EXPECT_EQ(sem->Members()[7]->Offset(), 152u); // mat3x2<f16>
+ EXPECT_EQ(sem->Members()[7]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[7]->Size(), 12u);
+ EXPECT_EQ(sem->Members()[8]->Offset(), 176u); // mat3x3<f32>
EXPECT_EQ(sem->Members()[8]->Align(), 16u);
- EXPECT_EQ(sem->Members()[8]->Size(), 64u);
+ EXPECT_EQ(sem->Members()[8]->Size(), 48u);
+ EXPECT_EQ(sem->Members()[9]->Offset(), 224u); // mat3x3<f16>
+ EXPECT_EQ(sem->Members()[9]->Align(), 8u);
+ EXPECT_EQ(sem->Members()[9]->Size(), 24u);
+ EXPECT_EQ(sem->Members()[10]->Offset(), 256u); // mat3x4<f32>
+ EXPECT_EQ(sem->Members()[10]->Align(), 16u);
+ EXPECT_EQ(sem->Members()[10]->Size(), 48u);
+ EXPECT_EQ(sem->Members()[11]->Offset(), 304u); // mat3x4<f16>
+ EXPECT_EQ(sem->Members()[11]->Align(), 8u);
+ EXPECT_EQ(sem->Members()[11]->Size(), 24u);
+ EXPECT_EQ(sem->Members()[12]->Offset(), 328u); // mat4x2<f32>
+ EXPECT_EQ(sem->Members()[12]->Align(), 8u);
+ EXPECT_EQ(sem->Members()[12]->Size(), 32u);
+ EXPECT_EQ(sem->Members()[13]->Offset(), 360u); // mat4x2<f16>
+ EXPECT_EQ(sem->Members()[13]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[13]->Size(), 16u);
+ EXPECT_EQ(sem->Members()[14]->Offset(), 384u); // mat4x3<f32>
+ EXPECT_EQ(sem->Members()[14]->Align(), 16u);
+ EXPECT_EQ(sem->Members()[14]->Size(), 64u);
+ EXPECT_EQ(sem->Members()[15]->Offset(), 448u); // mat4x3<f16>
+ EXPECT_EQ(sem->Members()[15]->Align(), 8u);
+ EXPECT_EQ(sem->Members()[15]->Size(), 32u);
+ EXPECT_EQ(sem->Members()[16]->Offset(), 480u); // mat4x4<f32>
+ EXPECT_EQ(sem->Members()[16]->Align(), 16u);
+ EXPECT_EQ(sem->Members()[16]->Size(), 64u);
+ EXPECT_EQ(sem->Members()[17]->Offset(), 544u); // mat4x4<f16>
+ EXPECT_EQ(sem->Members()[17]->Align(), 8u);
+ EXPECT_EQ(sem->Members()[17]->Size(), 32u);
+
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, NestedStruct) {
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.mat3x3<f32>()),
});
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.Of(inner)),
Member("c", ty.i32()),
@@ -311,19 +453,22 @@ TEST_F(ResolverStructLayoutTest, NestedStruct) {
EXPECT_EQ(sem->Members()[2]->Offset(), 64u);
EXPECT_EQ(sem->Members()[2]->Align(), 4u);
EXPECT_EQ(sem->Members()[2]->Size(), 4u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, SizeAttributes) {
- auto* inner = Structure("Inner", {
- Member("a", ty.f32(), {MemberSize(8)}),
- Member("b", ty.f32(), {MemberSize(16)}),
- Member("c", ty.f32(), {MemberSize(8)}),
+ auto* inner = Structure("Inner", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberSize(8)}),
+ Member("b", ty.f32(), utils::Vector{MemberSize(16)}),
+ Member("c", ty.f32(), utils::Vector{MemberSize(8)}),
});
- auto* s = Structure("S", {
- Member("a", ty.f32(), {MemberSize(4)}),
- Member("b", ty.u32(), {MemberSize(8)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberSize(4)}),
+ Member("b", ty.u32(), utils::Vector{MemberSize(8)}),
Member("c", ty.Of(inner)),
- Member("d", ty.i32(), {MemberSize(32)}),
+ Member("d", ty.i32(), utils::Vector{MemberSize(32)}),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -346,19 +491,22 @@ TEST_F(ResolverStructLayoutTest, SizeAttributes) {
EXPECT_EQ(sem->Members()[3]->Offset(), 44u);
EXPECT_EQ(sem->Members()[3]->Align(), 4u);
EXPECT_EQ(sem->Members()[3]->Size(), 32u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, AlignAttributes) {
- auto* inner = Structure("Inner", {
- Member("a", ty.f32(), {MemberAlign(8)}),
- Member("b", ty.f32(), {MemberAlign(16)}),
- Member("c", ty.f32(), {MemberAlign(4)}),
+ auto* inner = Structure("Inner", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberAlign(8)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(16)}),
+ Member("c", ty.f32(), utils::Vector{MemberAlign(4)}),
});
- auto* s = Structure("S", {
- Member("a", ty.f32(), {MemberAlign(4)}),
- Member("b", ty.u32(), {MemberAlign(8)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberAlign(4)}),
+ Member("b", ty.u32(), utils::Vector{MemberAlign(8)}),
Member("c", ty.Of(inner)),
- Member("d", ty.i32(), {MemberAlign(32)}),
+ Member("d", ty.i32(), utils::Vector{MemberAlign(32)}),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -381,11 +529,14 @@ TEST_F(ResolverStructLayoutTest, AlignAttributes) {
EXPECT_EQ(sem->Members()[3]->Offset(), 64u);
EXPECT_EQ(sem->Members()[3]->Align(), 32u);
EXPECT_EQ(sem->Members()[3]->Size(), 4u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
- auto* s = Structure("S", {
- Member("a", ty.i32(), {MemberAlign(1024)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberAlign(1024)}),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -399,6 +550,9 @@ TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 1024u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/resolver/struct_pipeline_stage_use_test.cc b/chromium/third_party/dawn/src/tint/resolver/struct_pipeline_stage_use_test.cc
index 1ca80dffecd..acf30f6bf58 100644
--- a/chromium/third_party/dawn/src/tint/resolver/struct_pipeline_stage_use_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/struct_pipeline_stage_use_test.cc
@@ -29,7 +29,7 @@ namespace {
using ResolverPipelineStageUseTest = ResolverTest;
TEST_F(ResolverPipelineStageUseTest, UnusedStruct) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -39,9 +39,9 @@ TEST_F(ResolverPipelineStageUseTest, UnusedStruct) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointParam) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
- Func("foo", {Param("param", ty.Of(s))}, ty.void_(), {}, {});
+ Func("foo", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty, utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -51,9 +51,10 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointParam) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
- Func("foo", {}, ty.Of(s), {Return(Construct(ty.Of(s), Expr(0_f)))}, {});
+ Func("foo", utils::Empty, ty.Of(s), utils::Vector{Return(Construct(ty.Of(s), Expr(0_f)))},
+ utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -63,10 +64,12 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
- Func("main", {Param("param", ty.Of(s))}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
- {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
+ Func("main", utils::Vector{Param("param", ty.Of(s))}, ty.vec4<f32>(),
+ utils::Vector{Return(Construct(ty.vec4<f32>()))},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)},
+ utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -77,9 +80,12 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
- auto* s = Structure("S", {Member("a", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+ auto* s =
+ Structure("S", utils::Vector{Member("a", ty.vec4<f32>(),
+ utils::Vector{Builtin(ast::BuiltinValue::kPosition)})});
- Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))}, {Stage(ast::PipelineStage::kVertex)});
+ Func("main", utils::Empty, ty.Of(s), utils::Vector{Return(Construct(ty.Of(s)))},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -90,10 +96,10 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderParam) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
- Func("main", {Param("param", ty.Of(s))}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -104,10 +110,10 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderParam) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderReturnType) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
- Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s), Expr(0_f)))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.Of(s), utils::Vector{Return(Construct(ty.Of(s), Expr(0_f)))},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -118,11 +124,12 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderReturnType) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
- auto* s =
- Structure("S", {Member("a", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)})});
+ auto* s = Structure(
+ "S", utils::Vector{Member(
+ "a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kLocalInvocationIndex)})});
- Func("main", {Param("param", ty.Of(s))}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ Func("main", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -133,13 +140,15 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
- auto* s = Structure("S", {Member("a", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+ auto* s =
+ Structure("S", utils::Vector{Member("a", ty.vec4<f32>(),
+ utils::Vector{Builtin(ast::BuiltinValue::kPosition)})});
- Func("vert_main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
- {Stage(ast::PipelineStage::kVertex)});
+ Func("vert_main", utils::Empty, ty.Of(s), utils::Vector{Return(Construct(ty.Of(s)))},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
- Func("frag_main", {Param("param", ty.Of(s))}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("frag_main", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -151,11 +160,11 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
auto* s_alias = Alias("S_alias", ty.Of(s));
- Func("main", {Param("param", ty.Of(s_alias))}, ty.void_(), {},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Vector{Param("param", ty.Of(s_alias))}, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -166,11 +175,12 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
- auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0)})});
auto* s_alias = Alias("S_alias", ty.Of(s));
- Func("main", {}, ty.Of(s_alias), {Return(Construct(ty.Of(s_alias), Expr(0_f)))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.Of(s_alias),
+ utils::Vector{Return(Construct(ty.Of(s_alias), Expr(0_f)))},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
diff --git a/chromium/third_party/dawn/src/tint/resolver/struct_storage_class_use_test.cc b/chromium/third_party/dawn/src/tint/resolver/struct_storage_class_use_test.cc
index 72ed546fccf..d58c9063775 100644
--- a/chromium/third_party/dawn/src/tint/resolver/struct_storage_class_use_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/struct_storage_class_use_test.cc
@@ -28,7 +28,7 @@ namespace {
using ResolverStorageClassUseTest = ResolverTest;
TEST_F(ResolverStorageClassUseTest, UnreachableStruct) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -38,9 +38,9 @@ TEST_F(ResolverStorageClassUseTest, UnreachableStruct) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
- Func("f", {Param("param", ty.Of(s))}, ty.void_(), {}, {});
+ Func("f", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty, utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -50,9 +50,9 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
- Func("f", {}, ty.Of(s), {Return(Construct(ty.Of(s)))}, {});
+ Func("f", utils::Empty, ty.Of(s), utils::Vector{Return(Construct(ty.Of(s)))}, utils::Empty);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -62,9 +62,9 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -74,9 +74,9 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
auto* a = Alias("A", ty.Of(s));
- Global("g", ty.Of(a), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(a), ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -86,9 +86,9 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
- auto* s = Structure("S", {Member("a", ty.f32())});
- auto* o = Structure("O", {Member("a", ty.Of(s))});
- Global("g", ty.Of(o), ast::StorageClass::kPrivate);
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
+ auto* o = Structure("O", utils::Vector{Member("a", ty.Of(s))});
+ GlobalVar("g", ty.Of(o), ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -98,9 +98,9 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
auto* a = ty.array(ty.Of(s), 3_u);
- Global("g", a, ast::StorageClass::kPrivate);
+ GlobalVar("g", a, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -110,7 +110,7 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
WrapInFunction(Var("g", ty.Of(s)));
@@ -122,7 +122,7 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
auto* a = Alias("A", ty.Of(s));
WrapInFunction(Var("g", ty.Of(a)));
@@ -134,8 +134,8 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
- auto* s = Structure("S", {Member("a", ty.f32())});
- auto* o = Structure("O", {Member("a", ty.Of(s))});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
+ auto* o = Structure("O", utils::Vector{Member("a", ty.Of(s))});
WrapInFunction(Var("g", ty.Of(o)));
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -146,7 +146,7 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
- auto* s = Structure("S", {Member("a", ty.f32())});
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
auto* a = ty.array(ty.Of(s), 3_u);
WrapInFunction(Var("g", a));
@@ -158,17 +158,17 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
}
TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
- auto* s = Structure("S", {Member("a", ty.f32())});
- Global("x", ty.Of(s), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
- Global("y", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
+ GlobalVar("x", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+ GlobalVar("y", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
WrapInFunction(Var("g", ty.Of(s)));
ASSERT_TRUE(r()->Resolve()) << r()->error();
diff --git a/chromium/third_party/dawn/src/tint/resolver/type_constructor_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/type_constructor_validation_test.cc
index 3277ee854d3..33c15f3d434 100644
--- a/chromium/third_party/dawn/src/tint/resolver/type_constructor_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/type_constructor_validation_test.cc
@@ -83,6 +83,8 @@ TEST_P(InferTypeTest_FromConstructorExpression, All) {
// }
auto& params = GetParam();
+ Enable(ast::Extension::kF16);
+
auto* constructor_expr = params.create_rhs_ast_value(*this, 0);
auto* a = Var("a", nullptr, ast::StorageClass::kNone, constructor_expr);
@@ -104,18 +106,24 @@ static constexpr Params from_constructor_expression_cases[] = {
ParamsFor<i32>(),
ParamsFor<u32>(),
ParamsFor<f32>(),
+ ParamsFor<f16>(),
ParamsFor<vec3<i32>>(),
ParamsFor<vec3<u32>>(),
ParamsFor<vec3<f32>>(),
+ ParamsFor<vec3<f16>>(),
ParamsFor<mat3x3<f32>>(),
+ ParamsFor<mat3x3<f16>>(),
ParamsFor<alias<bool>>(),
ParamsFor<alias<i32>>(),
ParamsFor<alias<u32>>(),
ParamsFor<alias<f32>>(),
+ ParamsFor<alias<f16>>(),
ParamsFor<alias<vec3<i32>>>(),
ParamsFor<alias<vec3<u32>>>(),
ParamsFor<alias<vec3<f32>>>(),
+ ParamsFor<alias<vec3<f16>>>(),
ParamsFor<alias<mat3x3<f32>>>(),
+ ParamsFor<alias<mat3x3<f16>>>(),
};
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
InferTypeTest_FromConstructorExpression,
@@ -176,8 +184,10 @@ TEST_P(InferTypeTest_FromCallExpression, All) {
// }
auto& params = GetParam();
- Func("foo", {}, params.create_rhs_ast_type(*this),
- {Return(Construct(params.create_rhs_ast_type(*this)))}, {});
+ Enable(ast::Extension::kF16);
+
+ Func("foo", utils::Empty, params.create_rhs_ast_type(*this),
+ utils::Vector{Return(Construct(params.create_rhs_ast_type(*this)))}, {});
auto* a = Var("a", nullptr, Call("foo"));
// Self-assign 'a' to force the expression to be resolved so we can test its
@@ -197,18 +207,24 @@ static constexpr Params from_call_expression_cases[] = {
ParamsFor<i32>(),
ParamsFor<u32>(),
ParamsFor<f32>(),
+ ParamsFor<f16>(),
ParamsFor<vec3<i32>>(),
ParamsFor<vec3<u32>>(),
ParamsFor<vec3<f32>>(),
+ ParamsFor<vec3<f16>>(),
ParamsFor<mat3x3<f32>>(),
+ ParamsFor<mat3x3<f16>>(),
ParamsFor<alias<bool>>(),
ParamsFor<alias<i32>>(),
ParamsFor<alias<u32>>(),
ParamsFor<alias<f32>>(),
+ ParamsFor<alias<f16>>(),
ParamsFor<alias<vec3<i32>>>(),
ParamsFor<alias<vec3<u32>>>(),
ParamsFor<alias<vec3<f32>>>(),
+ ParamsFor<alias<vec3<f16>>>(),
ParamsFor<alias<mat3x3<f32>>>(),
+ ParamsFor<alias<mat3x3<f16>>>(),
};
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
InferTypeTest_FromCallExpression,
@@ -240,62 +256,92 @@ static constexpr Params valid_cases[] = {
ParamsFor<i32, i32>(Kind::Construct), //
ParamsFor<u32, u32>(Kind::Construct), //
ParamsFor<f32, f32>(Kind::Construct), //
+ ParamsFor<f16, f16>(Kind::Construct), //
ParamsFor<vec3<bool>, vec3<bool>>(Kind::Construct), //
ParamsFor<vec3<i32>, vec3<i32>>(Kind::Construct), //
ParamsFor<vec3<u32>, vec3<u32>>(Kind::Construct), //
ParamsFor<vec3<f32>, vec3<f32>>(Kind::Construct), //
+ ParamsFor<vec3<f16>, vec3<f16>>(Kind::Construct), //
ParamsFor<mat3x3<f32>, mat3x3<f32>>(Kind::Construct), //
ParamsFor<mat2x3<f32>, mat2x3<f32>>(Kind::Construct), //
ParamsFor<mat3x2<f32>, mat3x2<f32>>(Kind::Construct), //
+ ParamsFor<mat3x3<f16>, mat3x3<f16>>(Kind::Construct), //
+ ParamsFor<mat2x3<f16>, mat2x3<f16>>(Kind::Construct), //
+ ParamsFor<mat3x2<f16>, mat3x2<f16>>(Kind::Construct), //
// Splat
ParamsFor<vec3<bool>, bool>(Kind::Construct), //
ParamsFor<vec3<i32>, i32>(Kind::Construct), //
ParamsFor<vec3<u32>, u32>(Kind::Construct), //
ParamsFor<vec3<f32>, f32>(Kind::Construct), //
-
- ParamsFor<mat3x3<f32>, f32>(Kind::Construct), //
- ParamsFor<mat2x3<f32>, f32>(Kind::Construct), //
- ParamsFor<mat3x2<f32>, f32>(Kind::Construct), //
+ ParamsFor<vec3<f16>, f16>(Kind::Construct), //
// Conversion
ParamsFor<bool, u32>(Kind::Conversion), //
ParamsFor<bool, i32>(Kind::Conversion), //
ParamsFor<bool, f32>(Kind::Conversion), //
+ ParamsFor<bool, f16>(Kind::Conversion), //
ParamsFor<i32, bool>(Kind::Conversion), //
ParamsFor<i32, u32>(Kind::Conversion), //
ParamsFor<i32, f32>(Kind::Conversion), //
+ ParamsFor<i32, f16>(Kind::Conversion), //
ParamsFor<u32, bool>(Kind::Conversion), //
ParamsFor<u32, i32>(Kind::Conversion), //
ParamsFor<u32, f32>(Kind::Conversion), //
+ ParamsFor<u32, f16>(Kind::Conversion), //
ParamsFor<f32, bool>(Kind::Conversion), //
ParamsFor<f32, u32>(Kind::Conversion), //
ParamsFor<f32, i32>(Kind::Conversion), //
+ ParamsFor<f32, f16>(Kind::Conversion), //
+
+ ParamsFor<f16, bool>(Kind::Conversion), //
+ ParamsFor<f16, u32>(Kind::Conversion), //
+ ParamsFor<f16, i32>(Kind::Conversion), //
+ ParamsFor<f16, f32>(Kind::Conversion), //
ParamsFor<vec3<bool>, vec3<u32>>(Kind::Conversion), //
ParamsFor<vec3<bool>, vec3<i32>>(Kind::Conversion), //
ParamsFor<vec3<bool>, vec3<f32>>(Kind::Conversion), //
+ ParamsFor<vec3<bool>, vec3<f16>>(Kind::Conversion), //
ParamsFor<vec3<i32>, vec3<bool>>(Kind::Conversion), //
ParamsFor<vec3<i32>, vec3<u32>>(Kind::Conversion), //
ParamsFor<vec3<i32>, vec3<f32>>(Kind::Conversion), //
+ ParamsFor<vec3<i32>, vec3<f16>>(Kind::Conversion), //
ParamsFor<vec3<u32>, vec3<bool>>(Kind::Conversion), //
ParamsFor<vec3<u32>, vec3<i32>>(Kind::Conversion), //
ParamsFor<vec3<u32>, vec3<f32>>(Kind::Conversion), //
+ ParamsFor<vec3<u32>, vec3<f16>>(Kind::Conversion), //
ParamsFor<vec3<f32>, vec3<bool>>(Kind::Conversion), //
ParamsFor<vec3<f32>, vec3<u32>>(Kind::Conversion), //
ParamsFor<vec3<f32>, vec3<i32>>(Kind::Conversion), //
+ ParamsFor<vec3<f32>, vec3<f16>>(Kind::Conversion), //
+
+ ParamsFor<vec3<f16>, vec3<bool>>(Kind::Conversion), //
+ ParamsFor<vec3<f16>, vec3<u32>>(Kind::Conversion), //
+ ParamsFor<vec3<f16>, vec3<i32>>(Kind::Conversion), //
+ ParamsFor<vec3<f16>, vec3<f32>>(Kind::Conversion), //
+
+ ParamsFor<mat3x3<f16>, mat3x3<f32>>(Kind::Conversion), //
+ ParamsFor<mat2x3<f16>, mat2x3<f32>>(Kind::Conversion), //
+ ParamsFor<mat3x2<f16>, mat3x2<f32>>(Kind::Conversion), //
+
+ ParamsFor<mat3x3<f32>, mat3x3<f16>>(Kind::Conversion), //
+ ParamsFor<mat2x3<f32>, mat2x3<f16>>(Kind::Conversion), //
+ ParamsFor<mat3x2<f32>, mat3x2<f16>>(Kind::Conversion), //
};
using ConversionConstructorValidTest = ResolverTestWithParam<Params>;
TEST_P(ConversionConstructorValidTest, All) {
auto& params = GetParam();
+ Enable(ast::Extension::kF16);
+
// var a : <lhs_type1> = <lhs_type2>(<rhs_type>(<rhs_value_expr>));
auto* lhs_type1 = params.lhs_type(*this);
auto* lhs_type2 = params.lhs_type(*this);
@@ -325,7 +371,7 @@ TEST_P(ConversionConstructorValidTest, All) {
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_EQ(ctor->Parameters()[0]->Type(), TypeOf(arg));
break;
}
@@ -333,7 +379,7 @@ TEST_P(ConversionConstructorValidTest, All) {
auto* conv = call->Target()->As<sem::TypeConversion>();
ASSERT_NE(conv, nullptr);
EXPECT_EQ(call->Type(), conv->ReturnType());
- ASSERT_EQ(conv->Parameters().size(), 1u);
+ ASSERT_EQ(conv->Parameters().Length(), 1u);
EXPECT_EQ(conv->Parameters()[0]->Type(), TypeOf(arg));
break;
}
@@ -348,19 +394,24 @@ constexpr CreatePtrs all_types[] = {
CreatePtrsFor<u32>(), //
CreatePtrsFor<i32>(), //
CreatePtrsFor<f32>(), //
+ CreatePtrsFor<f16>(), //
CreatePtrsFor<vec3<bool>>(), //
CreatePtrsFor<vec3<i32>>(), //
CreatePtrsFor<vec3<u32>>(), //
CreatePtrsFor<vec3<f32>>(), //
+ CreatePtrsFor<vec3<f16>>(), //
CreatePtrsFor<mat3x3<i32>>(), //
CreatePtrsFor<mat3x3<u32>>(), //
CreatePtrsFor<mat3x3<f32>>(), //
+ CreatePtrsFor<mat3x3<f16>>(), //
CreatePtrsFor<mat2x3<i32>>(), //
CreatePtrsFor<mat2x3<u32>>(), //
CreatePtrsFor<mat2x3<f32>>(), //
+ CreatePtrsFor<mat2x3<f16>>(), //
CreatePtrsFor<mat3x2<i32>>(), //
CreatePtrsFor<mat3x2<u32>>(), //
- CreatePtrsFor<mat3x2<f32>>() //
+ CreatePtrsFor<mat3x2<f32>>(), //
+ CreatePtrsFor<mat3x2<f16>>(), //
};
using ConversionConstructorInvalidTest = ResolverTestWithParam<std::tuple<CreatePtrs, // lhs
@@ -395,6 +446,8 @@ TEST_P(ConversionConstructorInvalidTest, All) {
<< FriendlyName(rhs_type) << "(<rhs value expr>))";
SCOPED_TRACE(ss.str());
+ Enable(ast::Extension::kF16);
+
auto* a = Var("a", lhs_type1, ast::StorageClass::kNone,
Construct(lhs_type2, Construct(rhs_type, rhs_value_expr)));
@@ -433,7 +486,7 @@ TEST_F(ResolverTypeConstructorValidationTest, ConversionConstructorInvalid_Inval
namespace ArrayConstructor {
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_ZeroValue_Pass) {
+TEST_F(ResolverTypeConstructorValidationTest, Array_ZeroValue_Pass) {
// array<u32, 10u>();
auto* tc = array<u32, 10>();
WrapInFunction(tc);
@@ -446,12 +499,31 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_ZeroValue_P
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 0u);
+ ASSERT_EQ(ctor->Parameters().Length(), 0u);
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Array_U32U32U32) {
+ // array<u32, 3u>(0u, 10u, 20u);
+ auto* tc = array<u32, 3>(0_u, 10_u, 20_u);
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ EXPECT_TRUE(call->Type()->Is<sem::Array>());
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_type_match) {
- // array<u32, 3u>(0u, 10u. 20u);
- auto* tc = array<u32, 3>(Expr(0_u), Expr(10_u), Expr(20_u));
+TEST_F(ResolverTypeConstructorValidationTest, InferredArray_U32U32U32) {
+ // array(0u, 10u, 20u);
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, 0_u, 10_u, 20_u);
WrapInFunction(tc);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -462,118 +534,317 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_type_match)
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_type_Mismatch_U32F32) {
+TEST_F(ResolverTypeConstructorValidationTest, Array_U32AIU32) {
+ // array<u32, 3u>(0u, 10, 20u);
+ auto* tc = array<u32, 3>(0_u, 10_a, 20_u);
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ EXPECT_TRUE(call->Type()->Is<sem::Array>());
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArray_U32AIU32) {
+ // array(0u, 10u, 20u);
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, 0_u, 10_a, 20_u);
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ EXPECT_TRUE(call->Type()->Is<sem::Array>());
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, ArrayU32_AIAIAI) {
+ // array<u32, 3u>(0, 10, 20);
+ auto* tc = array<u32, 3>(0_a, 10_a, 20_a);
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ EXPECT_TRUE(call->Type()->Is<sem::Array>());
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
+ EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArray_AIAIAI) {
+ // const c = array(0, 10, 20);
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, 0_a, 10_a, 20_a);
+ WrapInFunction(Decl(Const("C", nullptr, tc)));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ EXPECT_TRUE(call->Type()->Is<sem::Array>());
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::AbstractInt>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::AbstractInt>());
+ EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::AbstractInt>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayU32_VecI32_VecAI) {
+ // array(vec2(10i), vec2(20));
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, //
+ Construct(ty.vec(nullptr, 2), 20_i), //
+ Construct(ty.vec(nullptr, 2), 20_a));
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ EXPECT_TRUE(call->Type()->Is<sem::Array>());
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
+ ASSERT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+ ASSERT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayU32_VecAI_VecF32) {
+ // array(vec2(20), vec2(10f));
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, //
+ Construct(ty.vec(nullptr, 2), 20_a), //
+ Construct(ty.vec(nullptr, 2), 20_f));
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ EXPECT_TRUE(call->Type()->Is<sem::Array>());
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
+ ASSERT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+ ASSERT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Vector>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, ArrayArgumentTypeMismatch_U32F32) {
// array<u32, 3u>(0u, 1.0f, 20u);
- auto* tc = array<u32, 3>(Expr(0_u), Expr(Source{{12, 34}}, 1_f), Expr(20_u));
+ auto* tc = array<u32, 3>(0_u, Expr(Source{{12, 34}}, 1_f), 20_u);
+ WrapInFunction(tc);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'f32' cannot be used to construct an array of 'u32')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayArgumentTypeMismatch_U32F32) {
+ // array(0u, 1.0f, 20u);
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, 0_u, 1_f, 20_u);
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'u32', found 'f32'");
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'u32'
+note: argument 1 is of type 'f32')");
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Array_ScalarArgumentTypeMismatch_F32I32) {
+TEST_F(ResolverTypeConstructorValidationTest, ArrayArgumentTypeMismatch_F32I32) {
// array<f32, 1u>(1i);
auto* tc = array<f32, 1>(Expr(Source{{12, 34}}, 1_i));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'i32' cannot be used to construct an array of 'f32')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayArgumentTypeMismatch_F32I32) {
+ // array(1f, 1i);
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, 1_f, 1_i);
+ WrapInFunction(tc);
+
+ EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'f32', found 'i32'");
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'f32'
+note: argument 1 is of type 'i32')");
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Array_ScalarArgumentTypeMismatch_U32I32) {
+TEST_F(ResolverTypeConstructorValidationTest, ArrayArgumentTypeMismatch_U32I32) {
// array<u32, 1u>(1i, 0u, 0u, 0u, 0u, 0u);
- auto* tc =
- array<u32, 1>(Expr(Source{{12, 34}}, 1_i), Expr(0_u), Expr(0_u), Expr(0_u), Expr(0_u));
+ auto* tc = array<u32, 1>(Expr(Source{{12, 34}}, 1_i), 0_u, 0_u, 0_u, 0_u);
+ WrapInFunction(tc);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'i32' cannot be used to construct an array of 'u32')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayArgumentTypeMismatch_U32I32) {
+ // array(1i, 0u, 0u, 0u, 0u, 0u);
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, 1_i, 0_u, 0_u, 0_u, 0_u);
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'u32', found 'i32'");
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'i32'
+note: argument 1 is of type 'u32')");
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Array_ScalarArgumentTypeMismatch_Vec2) {
+TEST_F(ResolverTypeConstructorValidationTest, ArrayArgumentTypeMismatch_I32Vec2) {
// array<i32, 3u>(1i, vec2<i32>());
- auto* tc = array<i32, 3>(Expr(1_i), Construct(Source{{12, 34}}, ty.vec2<i32>()));
+ auto* tc = array<i32, 3>(1_i, vec2<i32>(Source{{12, 34}}));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'i32', found 'vec2<i32>'");
+ R"(12:34 error: 'vec2<i32>' cannot be used to construct an array of 'i32')");
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_ArrayOfVector_SubElemTypeMismatch_I32U32) {
- // array<vec3<i32>, 2u>(vec3<i32>(), vec3<u32>());
- auto* e0 = vec3<i32>();
- SetSource(Source::Location({12, 34}));
- auto* e1 = vec3<u32>();
- auto* t = Construct(ty.array(ty.vec3<i32>(), 2_i), e0, e1);
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayArgumentTypeMismatch_I32Vec2) {
+ // array(1i, vec2<i32>());
+ auto* tc = array(Source{{12, 34}}, nullptr, nullptr, 1_i, vec2<i32>());
+ WrapInFunction(tc);
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'i32'
+note: argument 1 is of type 'vec2<i32>')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
+ // array<vec3<i32>, 2u>(vec3<u32>(), vec3<u32>());
+ auto* t = array(ty.vec3<i32>(), 2_u, vec3<u32>(Source{{12, 34}}), vec3<u32>());
WrapInFunction(t);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'vec3<i32>', found 'vec3<u32>'");
+ R"(12:34 error: 'vec3<u32>' cannot be used to construct an array of 'vec3<i32>')");
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_ArrayOfVector_SubElemTypeMismatch_I32Bool) {
- // array<vec3<i32>, 2u>(vec3<i32>(), vec3<bool>(true, true, false));
- SetSource(Source::Location({12, 34}));
- auto* e0 = vec3<bool>(true, true, false);
- auto* e1 = vec3<i32>();
- auto* t = Construct(ty.array(ty.vec3<i32>(), 2_i), e0, e1);
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
+ // array(vec3<i32>(), vec3<u32>());
+ auto* t = array(Source{{12, 34}}, nullptr, nullptr, vec3<i32>(), vec3<u32>());
WrapInFunction(t);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'vec3<i32>', found 'vec3<bool>'");
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'vec3<i32>'
+note: argument 1 is of type 'vec3<u32>')");
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_ArrayOfArray_SubElemSizeMismatch) {
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3AF) {
+ // array(vec3<i32>(), vec3(1.0));
+ auto* t =
+ array(Source{{12, 34}}, nullptr, nullptr, vec3<i32>(), Construct(ty.vec3(nullptr), 1._a));
+ WrapInFunction(t);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'vec3<i32>'
+note: argument 1 is of type 'vec3<abstract-float>')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
+ // array<vec3<i32>, 2u>(vec3<i32>(), vec3<bool>());
+ auto* t = array(ty.vec3<i32>(), 2_u, vec3<i32>(), vec3<bool>());
+ WrapInFunction(t);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(error: 'vec3<bool>' cannot be used to construct an array of 'vec3<i32>')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
+ // array(vec3<i32>(), vec3<bool>());
+ auto* t = array(Source{{12, 34}}, nullptr, nullptr, vec3<i32>(), vec3<bool>());
+ WrapInFunction(t);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'vec3<i32>'
+note: argument 1 is of type 'vec3<bool>')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, ArrayOfArray_SubElemSizeMismatch) {
// array<array<i32, 2u>, 2u>(array<i32, 3u>(), array<i32, 2u>());
- SetSource(Source::Location({12, 34}));
- auto* e0 = array<i32, 3>();
- auto* e1 = array<i32, 2>();
- auto* t = Construct(ty.array(ty.array<i32, 2>(), 2_i), e0, e1);
+ auto* t = array(Source{{12, 34}}, ty.array<i32, 2>(), 2_i, array<i32, 3>(), array<i32, 2>());
+ WrapInFunction(t);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(error: 'array<i32, 3>' cannot be used to construct an array of 'array<i32, 2>')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayOfArray_SubElemSizeMismatch) {
+ // array<array<i32, 2u>, 2u>(array<i32, 3u>(), array<i32, 2u>());
+ auto* t = array(Source{{12, 34}}, nullptr, nullptr, array<i32, 3>(), array<i32, 2>());
WrapInFunction(t);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'array<i32, 2>', found 'array<i32, 3>'");
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'array<i32, 3>'
+note: argument 1 is of type 'array<i32, 2>')");
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_ArrayOfArray_SubElemTypeMismatch) {
+TEST_F(ResolverTypeConstructorValidationTest, ArrayOfArray_SubElemTypeMismatch) {
// array<array<i32, 2u>, 2u>(array<i32, 2u>(), array<u32, 2u>());
- auto* e0 = array<i32, 2>();
- SetSource(Source::Location({12, 34}));
- auto* e1 = array<u32, 2>();
- auto* t = Construct(ty.array(ty.array<i32, 2>(), 2_i), e0, e1);
+ auto* t = array(Source{{12, 34}}, ty.array<i32, 2>(), 2_i, array<i32, 2>(), array<u32, 2>());
WrapInFunction(t);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: type in array constructor does not match array type: "
- "expected 'array<i32, 2>', found 'array<u32, 2>'");
+ R"(error: 'array<u32, 2>' cannot be used to construct an array of 'array<i32, 2>')");
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_TooFewElements) {
+TEST_F(ResolverTypeConstructorValidationTest, InferredArrayOfArray_SubElemTypeMismatch) {
+ // array<array<i32, 2u>, 2u>(array<i32, 2u>(), array<u32, 2u>());
+ auto* t = array(Source{{12, 34}}, nullptr, nullptr, array<i32, 2>(), array<u32, 2>());
+ WrapInFunction(t);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(12:34 error: cannot infer common array element type from constructor arguments
+note: argument 0 is of type 'array<i32, 2>'
+note: argument 1 is of type 'array<u32, 2>')");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Array_TooFewElements) {
// array<i32, 4u>(1i, 2i, 3i);
SetSource(Source::Location({12, 34}));
auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i));
@@ -581,11 +852,10 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_TooFewEleme
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: array constructor has too few elements: expected 4, "
- "found 3");
+ "12:34 error: array constructor has too few elements: expected 4, found 3");
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_TooManyElements) {
+TEST_F(ResolverTypeConstructorValidationTest, Array_TooManyElements) {
// array<i32, 4u>(1i, 2i, 3i, 4i, 5i);
SetSource(Source::Location({12, 34}));
auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i), Expr(5_i));
@@ -598,29 +868,29 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_TooManyElem
"found 5");
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_Runtime) {
+TEST_F(ResolverTypeConstructorValidationTest, Array_Runtime) {
// array<i32>(1i);
- auto* tc = array(ty.i32(), nullptr, Expr(Source{{12, 34}}, 1_i));
+ auto* tc = array(Source{{12, 34}}, ty.i32(), nullptr, Expr(1_i));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: cannot init a runtime-sized array");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot construct a runtime-sized array");
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_RuntimeZeroValue) {
+TEST_F(ResolverTypeConstructorValidationTest, Array_RuntimeZeroValue) {
// array<i32>();
- auto* tc = array(ty.i32(), nullptr);
+ auto* tc = array(Source{{12, 34}}, ty.i32(), nullptr);
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: cannot init a runtime-sized array");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot construct a runtime-sized array");
}
} // namespace ArrayConstructor
namespace ScalarConstructor {
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_i32_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, I32_Success) {
auto* expr = Construct<i32>(Expr(123_i));
WrapInFunction(expr);
@@ -634,11 +904,11 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_i32_Success) {
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_u32_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, U32_Success) {
auto* expr = Construct<u32>(Expr(123_u));
WrapInFunction(expr);
@@ -652,11 +922,11 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_u32_Success) {
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_f32_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, F32_Success) {
auto* expr = Construct<f32>(Expr(1.23_f));
WrapInFunction(expr);
@@ -670,11 +940,31 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_f32_Success) {
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_f32_to_i32_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, F16_Success) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = Construct<f16>(Expr(1.5_h));
+ WrapInFunction(expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(expr), nullptr);
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::F16>());
+
+ auto* call = Sem().Get<sem::Call>(expr);
+ ASSERT_NE(call, nullptr);
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F16>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Convert_f32_to_i32_Success) {
auto* expr = Construct<i32>(1.23_f);
WrapInFunction(expr);
@@ -688,11 +978,11 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_f32_to_i32_Success) {
auto* ctor = call->Target()->As<sem::TypeConversion>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_i32_to_u32_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, Convert_i32_to_u32_Success) {
auto* expr = Construct<u32>(123_i);
WrapInFunction(expr);
@@ -706,96 +996,122 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_i32_to_u32_Success) {
auto* ctor = call->Target()->As<sem::TypeConversion>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_u32_to_f32_Success) {
- auto* expr = Construct<f32>(123_u);
+TEST_F(ResolverTypeConstructorValidationTest, Convert_u32_to_f16_Success) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = Construct<f16>(123_u);
WrapInFunction(expr);
ASSERT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(expr), nullptr);
- ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::F16>());
auto* call = Sem().Get<sem::Call>(expr);
ASSERT_NE(call, nullptr);
auto* ctor = call->Target()->As<sem::TypeConversion>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
}
+TEST_F(ResolverTypeConstructorValidationTest, Convert_f16_to_f32_Success) {
+ Enable(ast::Extension::kF16);
+
+ auto* expr = Construct<f32>(123_h);
+ WrapInFunction(expr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(expr), nullptr);
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
+
+ auto* call = Sem().Get<sem::Call>(expr);
+ ASSERT_NE(call, nullptr);
+ auto* ctor = call->Target()->As<sem::TypeConversion>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F16>());
+}
+
} // namespace ScalarConstructor
namespace VectorConstructor {
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec2F32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<f32>(), 1_i, 2_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2F32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec2<f32>(Source{{12, 34}}, 1_i, 2_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<f32>(i32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec2U32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<u32>(), 1_u, 2_i));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2F16_Error_ScalarArgumentTypeMismatch) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec2<f16>(Source{{12, 34}}, 1_h, 2_f));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(r()->error(),
+ HasSubstr("12:34 error: no matching constructor for vec2<f16>(f16, f32)"));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Vec2U32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec2<u32>(Source{{12, 34}}, 1_u, 2_i));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<u32>(u32, i32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec2I32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<i32>(), 1_u, 2_i));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2I32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec2<i32>(Source{{12, 34}}, 1_u, 2_i));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<i32>(u32, i32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec2Bool_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<bool>(), true, 1_i));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2Bool_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec2<bool>(Source{{12, 34}}, true, 1_i));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<bool>(bool, i32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec2_Error_Vec3ArgumentCardinalityTooLarge) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<f32>(), vec3<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Error_Vec3ArgumentCardinalityTooLarge) {
+ WrapInFunction(vec2<f32>(Source{{12, 34}}, vec3<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec3<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec2_Error_Vec4ArgumentCardinalityTooLarge) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<f32>(), vec4<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Error_Vec4ArgumentCardinalityTooLarge) {
+ WrapInFunction(vec2<f32>(Source{{12, 34}}, vec4<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec4<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Error_TooManyArgumentsScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<f32>(), 1_f, 2_f, 3_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Error_TooManyArgumentsScalar) {
+ WrapInFunction(vec2<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<f32>(f32, f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Error_TooManyArgumentsVector) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<f32>(), vec2<f32>(), vec2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Error_TooManyArgumentsVector) {
+ WrapInFunction(vec2<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -803,24 +1119,23 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Error_TooMan
HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec2<f32>, vec2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec2_Error_TooManyArgumentsVectorAndScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<f32>(), vec2<f32>(), 1_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Error_TooManyArgumentsVectorAndScalar) {
+ WrapInFunction(vec2<f32>(Source{{12, 34}}, vec2<f32>(), 1_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec2<f32>, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Error_InvalidArgumentType) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec2<f32>(), mat2x2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Error_InvalidArgumentType) {
+ WrapInFunction(vec2<f32>(Source{{12, 34}}, mat2x2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec2<f32>(mat2x2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_ZeroValue) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Success_ZeroValue) {
auto* tc = vec2<f32>();
WrapInFunction(tc);
@@ -836,10 +1151,10 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_Zero
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 0u);
+ ASSERT_EQ(ctor->Parameters().Length(), 0u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2F32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec2F32_Success_Scalar) {
auto* tc = vec2<f32>(1_f, 1_f);
WrapInFunction(tc);
@@ -855,12 +1170,35 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2F32_Success_S
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2U32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec2F16_Success_Scalar) {
+ Enable(ast::Extension::kF16);
+
+ auto* tc = vec2<f16>(1_h, 1_h);
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(tc), nullptr);
+ ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F16>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F16>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Vec2U32_Success_Scalar) {
auto* tc = vec2<u32>(1_u, 1_u);
WrapInFunction(tc);
@@ -876,12 +1214,12 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2U32_Success_S
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2I32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec2I32_Success_Scalar) {
auto* tc = vec2<i32>(1_i, 1_i);
WrapInFunction(tc);
@@ -897,12 +1235,12 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2I32_Success_S
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2Bool_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec2Bool_Success_Scalar) {
auto* tc = vec2<bool>(true, false);
WrapInFunction(tc);
@@ -918,12 +1256,12 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2Bool_Success_
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_Identity) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Success_Identity) {
auto* tc = vec2<f32>(vec2<f32>());
WrapInFunction(tc);
@@ -939,11 +1277,11 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_Iden
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_Vec2TypeConversion) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec2_Success_Vec2TypeConversion) {
auto* tc = vec2<f32>(vec2<i32>());
WrapInFunction(tc);
@@ -959,65 +1297,70 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_Vec2
auto* ctor = call->Target()->As<sem::TypeConversion>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec3F32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), 1_f, 2_f, 3_i));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3F32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f, 3_i));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32, i32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec3U32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<u32>(), 1_u, 2_i, 3_u));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3F16_Error_ScalarArgumentTypeMismatch) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(Source{{12, 34}}, 1_h, 2_h, 3_f));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(r()->error(),
+ HasSubstr("12:34 error: no matching constructor for vec3<f16>(f16, f16, f32)"));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Vec3U32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec3<u32>(Source{{12, 34}}, 1_u, 2_i, 3_u));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<u32>(u32, i32, u32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec3I32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<i32>(), 1_i, 2_u, 3_i));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3I32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec3<i32>(Source{{12, 34}}, 1_i, 2_u, 3_i));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<i32>(i32, u32, i32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec3Bool_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<bool>(), false, 1_i, true));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3Bool_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec3<bool>(Source{{12, 34}}, false, 1_i, true));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<bool>(bool, i32, bool)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec3_Error_Vec4ArgumentCardinalityTooLarge) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), vec4<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_Vec4ArgumentCardinalityTooLarge) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, vec4<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec4<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooFewArgumentsScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), 1_f, 2_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_TooFewArgumentsScalar) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooManyArgumentsScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), 1_f, 2_f, 3_f, 4_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_TooManyArgumentsScalar) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1025,16 +1368,16 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooMan
HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32, f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooFewArgumentsVec2) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), vec2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_TooFewArgumentsVec2) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooManyArgumentsVec2) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), vec2<f32>(), vec2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1042,9 +1385,8 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooMan
HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>, vec2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec3_Error_TooManyArgumentsVec2AndScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), vec2<f32>(), 1_f, 1_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2AndScalar) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>(), 1_f, 1_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1052,23 +1394,23 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>, f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooManyArgumentsVec3) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), vec3<f32>(), 1_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_TooManyArgumentsVec3) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, vec3<f32>(), 1_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec3<f32>, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_InvalidArgumentType) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<f32>(), mat2x2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Error_InvalidArgumentType) {
+ WrapInFunction(vec3<f32>(Source{{12, 34}}, mat2x2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<f32>(mat2x2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_ZeroValue) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Success_ZeroValue) {
auto* tc = vec3<f32>();
WrapInFunction(tc);
@@ -1084,10 +1426,10 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Zero
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 0u);
+ ASSERT_EQ(ctor->Parameters().Length(), 0u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3F32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3F32_Success_Scalar) {
auto* tc = vec3<f32>(1_f, 1_f, 1_f);
WrapInFunction(tc);
@@ -1103,13 +1445,37 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3F32_Success_S
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::F32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3U32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3F16_Success_Scalar) {
+ Enable(ast::Extension::kF16);
+
+ auto* tc = vec3<f16>(1_h, 1_h, 1_h);
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(tc), nullptr);
+ ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+
+ auto* call = Sem().Get<sem::Call>(tc);
+ ASSERT_NE(call, nullptr);
+ auto* ctor = call->Target()->As<sem::TypeConstructor>();
+ ASSERT_NE(ctor, nullptr);
+ EXPECT_EQ(call->Type(), ctor->ReturnType());
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
+ EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F16>());
+ EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F16>());
+ EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::F16>());
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Vec3U32_Success_Scalar) {
auto* tc = vec3<u32>(1_u, 1_u, 1_u);
WrapInFunction(tc);
@@ -1125,13 +1491,13 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3U32_Success_S
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3I32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3I32_Success_Scalar) {
auto* tc = vec3<i32>(1_i, 1_i, 1_i);
WrapInFunction(tc);
@@ -1147,13 +1513,13 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3I32_Success_S
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3Bool_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3Bool_Success_Scalar) {
auto* tc = vec3<bool>(true, false, true);
WrapInFunction(tc);
@@ -1169,13 +1535,13 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3Bool_Success_
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::Bool>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Vec2AndScalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Success_Vec2AndScalar) {
auto* tc = vec3<f32>(vec2<f32>(), 1_f);
WrapInFunction(tc);
@@ -1191,12 +1557,12 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Vec2
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_ScalarAndVec2) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Success_ScalarAndVec2) {
auto* tc = vec3<f32>(1_f, vec2<f32>());
WrapInFunction(tc);
@@ -1212,12 +1578,12 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Scal
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Vector>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Identity) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Success_Identity) {
auto* tc = vec3<f32>(vec3<f32>());
WrapInFunction(tc);
@@ -1233,11 +1599,11 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Iden
auto* ctor = call->Target()->As<sem::TypeConstructor>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Vec3TypeConversion) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec3_Success_Vec3TypeConversion) {
auto* tc = vec3<f32>(vec3<i32>());
WrapInFunction(tc);
@@ -1253,13 +1619,12 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Vec3
auto* ctor = call->Target()->As<sem::TypeConversion>();
ASSERT_NE(ctor, nullptr);
EXPECT_EQ(call->Type(), ctor->ReturnType());
- ASSERT_EQ(ctor->Parameters().size(), 1u);
+ ASSERT_EQ(ctor->Parameters().Length(), 1u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4F32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), 1_f, 1_f, 1_i, 1_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4F32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 1_f, 1_i, 1_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1267,9 +1632,19 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, i32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4U32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<u32>(), 1_u, 1_u, 1_i, 1_u));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4F16_Error_ScalarArgumentTypeMismatch) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec4<f16>(Source{{12, 34}}, 1_h, 1_h, 1_f, 1_h));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(
+ r()->error(),
+ HasSubstr("12:34 error: no matching constructor for vec4<f16>(f16, f16, f32, f16)"));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Vec4U32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec4<u32>(Source{{12, 34}}, 1_u, 1_u, 1_i, 1_u));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1277,9 +1652,8 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<u32>(u32, u32, i32, u32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4I32_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<i32>(), 1_i, 1_i, 1_u, 1_i));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4I32_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec4<i32>(Source{{12, 34}}, 1_i, 1_i, 1_u, 1_i));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1287,9 +1661,8 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<i32>(i32, i32, u32, i32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4Bool_Error_ScalarArgumentTypeMismatch) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<bool>(), true, false, 1_i, true));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4Bool_Error_ScalarArgumentTypeMismatch) {
+ WrapInFunction(vec4<bool>(Source{{12, 34}}, true, false, 1_i, true));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1297,16 +1670,16 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<bool>(bool, bool, i32, bool)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_TooFewArgumentsScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), 1_f, 2_f, 3_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooFewArgumentsScalar) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_TooManyArgumentsScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), 1_f, 2_f, 3_f, 4_f, 5_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsScalar) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f, 5_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1314,18 +1687,16 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_TooMan
HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, f32, f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooFewArgumentsVec2AndScalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec2<f32>(), 1_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooFewArgumentsVec2AndScalar) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), 1_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooManyArgumentsVec2AndScalars) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec2<f32>(), 1_f, 2_f, 3_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndScalars) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), 1_f, 2_f, 3_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1333,9 +1704,8 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, f32, f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooManyArgumentsVec2Vec2Scalar) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec2<f32>(), vec2<f32>(), 1_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Scalar) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>(), 1_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1343,10 +1713,8 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec2<f32>, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooManyArgumentsVec2Vec2Vec2) {
- WrapInFunction(
- Construct(Source{{12, 34}}, ty.vec4<f32>(), vec2<f32>(), vec2<f32>(), vec2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Vec2) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>(), vec2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1355,17 +1723,16 @@ TEST_F(ResolverTypeConstructorValidationTest,
"12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec2<f32>, vec2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_TooFewArgumentsVec3) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec3<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooFewArgumentsVec3) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndScalars) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec3<f32>(), 1_f, 2_f));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndScalars) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), 1_f, 2_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1373,9 +1740,8 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndVec2) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec3<f32>(), vec2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec2) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), vec2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1383,9 +1749,8 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, vec2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooManyArgumentsVec2AndVec3) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec2<f32>(), vec3<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndVec3) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec3<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1393,9 +1758,8 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec3<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndVec3) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), vec3<f32>(), vec3<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec3) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), vec3<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
@@ -1403,15 +1767,15 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, vec3<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_InvalidArgumentType) {
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec4<f32>(), mat2x2<f32>()));
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Error_InvalidArgumentType) {
+ WrapInFunction(vec4<f32>(Source{{12, 34}}, mat2x2<f32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec4<f32>(mat2x2<f32>)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ZeroValue) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_ZeroValue) {
auto* tc = vec4<f32>();
WrapInFunction(tc);
@@ -1423,7 +1787,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Zero
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4F32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4F32_Success_Scalar) {
auto* tc = vec4<f32>(1_f, 1_f, 1_f, 1_f);
WrapInFunction(tc);
@@ -1435,7 +1799,21 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4F32_Success_S
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4U32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4F16_Success_Scalar) {
+ Enable(ast::Extension::kF16);
+
+ auto* tc = vec4<f16>(1_h, 1_h, 1_h, 1_h);
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_NE(TypeOf(tc), nullptr);
+ ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F16>());
+ EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, Vec4U32_Success_Scalar) {
auto* tc = vec4<u32>(1_u, 1_u, 1_u, 1_u);
WrapInFunction(tc);
@@ -1447,7 +1825,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4U32_Success_S
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4I32_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4I32_Success_Scalar) {
auto* tc = vec4<i32>(1_i, 1_i, 1_i, 1_i);
WrapInFunction(tc);
@@ -1459,7 +1837,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4I32_Success_S
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4Bool_Success_Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4Bool_Success_Scalar) {
auto* tc = vec4<bool>(true, false, true, false);
WrapInFunction(tc);
@@ -1471,7 +1849,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4Bool_Success_
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec2ScalarScalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_Vec2ScalarScalar) {
auto* tc = vec4<f32>(vec2<f32>(), 1_f, 1_f);
WrapInFunction(tc);
@@ -1483,7 +1861,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec2
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ScalarVec2Scalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_ScalarVec2Scalar) {
auto* tc = vec4<f32>(1_f, vec2<f32>(), 1_f);
WrapInFunction(tc);
@@ -1495,7 +1873,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Scal
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ScalarScalarVec2) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_ScalarScalarVec2) {
auto* tc = vec4<f32>(1_f, 1_f, vec2<f32>());
WrapInFunction(tc);
@@ -1507,7 +1885,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Scal
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec2AndVec2) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_Vec2AndVec2) {
auto* tc = vec4<f32>(vec2<f32>(), vec2<f32>());
WrapInFunction(tc);
@@ -1519,7 +1897,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec2
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec3AndScalar) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_Vec3AndScalar) {
auto* tc = vec4<f32>(vec3<f32>(), 1_f);
WrapInFunction(tc);
@@ -1531,7 +1909,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec3
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ScalarAndVec3) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_ScalarAndVec3) {
auto* tc = vec4<f32>(1_f, vec3<f32>());
WrapInFunction(tc);
@@ -1543,7 +1921,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Scal
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Identity) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_Identity) {
auto* tc = vec4<f32>(vec4<f32>());
WrapInFunction(tc);
@@ -1555,7 +1933,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Iden
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec4TypeConversion) {
+TEST_F(ResolverTypeConstructorValidationTest, Vec4_Success_Vec4TypeConversion) {
auto* tc = vec4<f32>(vec4<i32>());
WrapInFunction(tc);
@@ -1567,10 +1945,9 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec4
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_NestedVectorConstructors_InnerError) {
+TEST_F(ResolverTypeConstructorValidationTest, NestedVectorConstructors_InnerError) {
WrapInFunction(vec4<f32>(vec4<f32>(1_f, 1_f, //
- Construct(Source{{12, 34}}, ty.vec3<f32>(), 1_f, 1_f)),
+ vec3<f32>(Source{{12, 34}}, 1_f, 1_f)),
1_f));
EXPECT_FALSE(r()->Resolve());
@@ -1578,7 +1955,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_NestedVectorConstructors_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, NestedVectorConstructors_Success) {
auto* tc = vec4<f32>(vec3<f32>(vec2<f32>(1_f, 1_f), 1_f), 1_f);
WrapInFunction(tc);
@@ -1590,29 +1967,29 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_NestedVectorConst
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) {
+TEST_F(ResolverTypeConstructorValidationTest, Vector_Alias_Argument_Error) {
auto* alias = Alias("UnsignedInt", ty.u32());
- Global("uint_var", ty.Of(alias), ast::StorageClass::kPrivate);
+ GlobalVar("uint_var", ty.Of(alias), ast::StorageClass::kPrivate);
- auto* tc = Construct(Source{{12, 34}}, ty.vec2<f32>(), "uint_var");
+ auto* tc = vec2<f32>(Source{{12, 34}}, "uint_var");
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for vec2<f32>(u32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_Alias_Argument_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, Vector_Alias_Argument_Success) {
auto* f32_alias = Alias("Float32", ty.f32());
auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>());
- Global("my_f32", ty.Of(f32_alias), ast::StorageClass::kPrivate);
- Global("my_vec2", ty.Of(vec2_alias), ast::StorageClass::kPrivate);
+ GlobalVar("my_f32", ty.Of(f32_alias), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec2", ty.Of(vec2_alias), ast::StorageClass::kPrivate);
auto* tc = vec3<f32>("my_vec2", "my_f32");
WrapInFunction(tc);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_ElementTypeAlias_Error) {
+TEST_F(ResolverTypeConstructorValidationTest, Vector_ElementTypeAlias_Error) {
auto* f32_alias = Alias("Float32", ty.f32());
// vec2<Float32>(1.0f, 1u)
@@ -1624,7 +2001,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_ElementTyp
HasSubstr("12:34 error: no matching constructor for vec2<f32>(f32, u32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_ElementTypeAlias_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, Vector_ElementTypeAlias_Success) {
auto* f32_alias = Alias("Float32", ty.f32());
// vec2<Float32>(1.0f, 1.0f)
@@ -1635,21 +2012,19 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_ElementTyp
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vector_ArgumentElementTypeAlias_Error) {
+TEST_F(ResolverTypeConstructorValidationTest, Vector_ArgumentElementTypeAlias_Error) {
auto* f32_alias = Alias("Float32", ty.f32());
// vec3<u32>(vec<Float32>(), 1.0f)
auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
- WrapInFunction(Construct(Source{{12, 34}}, ty.vec3<u32>(), Construct(vec_type), 1_f));
+ WrapInFunction(vec3<u32>(Source{{12, 34}}, Construct(vec_type), 1_f));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
HasSubstr("12:34 error: no matching constructor for vec3<u32>(vec2<f32>, f32)"));
}
-TEST_F(ResolverTypeConstructorValidationTest,
- Expr_Constructor_Vector_ArgumentElementTypeAlias_Success) {
+TEST_F(ResolverTypeConstructorValidationTest, Vector_ArgumentElementTypeAlias_Success) {
auto* f32_alias = Alias("Float32", ty.f32());
// vec3<f32>(vec<Float32>(), 1.0f)
@@ -1661,11 +2036,14 @@ TEST_F(ResolverTypeConstructorValidationTest,
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromScalars) {
- auto* vec2_bool = Construct(create<ast::Vector>(nullptr, 2), Expr(true), Expr(false));
- auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1_i), Expr(2_i));
- auto* vec2_u32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1_u), Expr(2_u));
- auto* vec2_f32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1_f), Expr(2_f));
- WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
+ Enable(ast::Extension::kF16);
+
+ auto* vec2_bool = Construct(create<ast::Vector>(nullptr, 2u), Expr(true), Expr(false));
+ auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2u), Expr(1_i), Expr(2_i));
+ auto* vec2_u32 = Construct(create<ast::Vector>(nullptr, 2u), Expr(1_u), Expr(2_u));
+ auto* vec2_f32 = Construct(create<ast::Vector>(nullptr, 2u), Expr(1_f), Expr(2_f));
+ auto* vec2_f16 = Construct(create<ast::Vector>(nullptr, 2u), Expr(1_h), Expr(2_h));
+ WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32, vec2_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1673,26 +2051,33 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromScalars) {
ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec2_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_f16)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
+ EXPECT_EQ(TypeOf(vec2_f16), TypeOf(vec2_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromVec2) {
- auto* vec2_bool = Construct(create<ast::Vector>(nullptr, 2), vec2<bool>(true, false));
- auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), vec2<i32>(1_i, 2_i));
- auto* vec2_u32 = Construct(create<ast::Vector>(nullptr, 2), vec2<u32>(1_u, 2_u));
- auto* vec2_f32 = Construct(create<ast::Vector>(nullptr, 2), vec2<f32>(1_f, 2_f));
- WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
+ Enable(ast::Extension::kF16);
+
+ auto* vec2_bool = Construct(create<ast::Vector>(nullptr, 2u), vec2<bool>(true, false));
+ auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2u), vec2<i32>(1_i, 2_i));
+ auto* vec2_u32 = Construct(create<ast::Vector>(nullptr, 2u), vec2<u32>(1_u, 2_u));
+ auto* vec2_f32 = Construct(create<ast::Vector>(nullptr, 2u), vec2<f32>(1_f, 2_f));
+ auto* vec2_f16 = Construct(create<ast::Vector>(nullptr, 2u), vec2<f16>(1_h, 2_h));
+ WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32, vec2_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1700,27 +2085,34 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromVec2) {
ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec2_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_f16)->As<sem::Vector>()->Width(), 2u);
EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
+ EXPECT_EQ(TypeOf(vec2_f16), TypeOf(vec2_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromScalars) {
+ Enable(ast::Extension::kF16);
+
auto* vec3_bool =
- Construct(create<ast::Vector>(nullptr, 3), Expr(true), Expr(false), Expr(true));
- auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_i), Expr(2_i), Expr(3_i));
- auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_u), Expr(2_u), Expr(3_u));
- auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_f), Expr(2_f), Expr(3_f));
- WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+ Construct(create<ast::Vector>(nullptr, 3u), Expr(true), Expr(false), Expr(true));
+ auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_i), Expr(2_i), Expr(3_i));
+ auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_u), Expr(2_u), Expr(3_u));
+ auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_f), Expr(2_f), Expr(3_f));
+ auto* vec3_f16 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_h), Expr(2_h), Expr(3_h));
+ WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32, vec3_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1728,26 +2120,33 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromScalars) {
ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec3_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_f16)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+ EXPECT_EQ(TypeOf(vec3_f16), TypeOf(vec3_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromVec3) {
- auto* vec3_bool = Construct(create<ast::Vector>(nullptr, 3), vec3<bool>(true, false, true));
- auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3), vec3<i32>(1_i, 2_i, 3_i));
- auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3), vec3<u32>(1_u, 2_u, 3_u));
- auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), vec3<f32>(1_f, 2_f, 3_f));
- WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+ Enable(ast::Extension::kF16);
+
+ auto* vec3_bool = Construct(create<ast::Vector>(nullptr, 3u), vec3<bool>(true, false, true));
+ auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3u), vec3<i32>(1_i, 2_i, 3_i));
+ auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3u), vec3<u32>(1_u, 2_u, 3_u));
+ auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3u), vec3<f32>(1_f, 2_f, 3_f));
+ auto* vec3_f16 = Construct(create<ast::Vector>(nullptr, 3u), vec3<f16>(1_h, 2_h, 3_h));
+ WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32, vec3_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1755,27 +2154,34 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromVec3) {
ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec3_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_f16)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+ EXPECT_EQ(TypeOf(vec3_f16), TypeOf(vec3_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromScalarAndVec2) {
+ Enable(ast::Extension::kF16);
+
auto* vec3_bool =
- Construct(create<ast::Vector>(nullptr, 3), Expr(true), vec2<bool>(false, true));
- auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_i), vec2<i32>(2_i, 3_i));
- auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_u), vec2<u32>(2_u, 3_u));
- auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_f), vec2<f32>(2_f, 3_f));
- WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+ Construct(create<ast::Vector>(nullptr, 3u), Expr(true), vec2<bool>(false, true));
+ auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_i), vec2<i32>(2_i, 3_i));
+ auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_u), vec2<u32>(2_u, 3_u));
+ auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_f), vec2<f32>(2_f, 3_f));
+ auto* vec3_f16 = Construct(create<ast::Vector>(nullptr, 3u), Expr(1_h), vec2<f16>(2_h, 3_h));
+ WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32, vec3_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1783,30 +2189,38 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromScalarAndV
ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec3_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_f16)->As<sem::Vector>()->Width(), 3u);
EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+ EXPECT_EQ(TypeOf(vec3_f16), TypeOf(vec3_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromScalars) {
- auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), Expr(true), Expr(false),
+ Enable(ast::Extension::kF16);
+
+ auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4u), Expr(true), Expr(false),
Expr(true), Expr(false));
auto* vec4_i32 =
- Construct(create<ast::Vector>(nullptr, 4), Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i));
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i));
auto* vec4_u32 =
- Construct(create<ast::Vector>(nullptr, 4), Expr(1_u), Expr(2_u), Expr(3_u), Expr(4_u));
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_u), Expr(2_u), Expr(3_u), Expr(4_u));
auto* vec4_f32 =
- Construct(create<ast::Vector>(nullptr, 4), Expr(1_f), Expr(2_f), Expr(3_f), Expr(4_f));
- WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_f), Expr(2_f), Expr(3_f), Expr(4_f));
+ auto* vec4_f16 =
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_h), Expr(2_h), Expr(3_h), Expr(4_h));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1814,27 +2228,34 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromScalars) {
ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec4_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f16)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f16), TypeOf(vec4_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromVec4) {
+ Enable(ast::Extension::kF16);
+
auto* vec4_bool =
- Construct(create<ast::Vector>(nullptr, 4), vec4<bool>(true, false, true, false));
- auto* vec4_i32 = Construct(create<ast::Vector>(nullptr, 4), vec4<i32>(1_i, 2_i, 3_i, 4_i));
- auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), vec4<u32>(1_u, 2_u, 3_u, 4_u));
- auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4), vec4<f32>(1_f, 2_f, 3_f, 4_f));
- WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+ Construct(create<ast::Vector>(nullptr, 4u), vec4<bool>(true, false, true, false));
+ auto* vec4_i32 = Construct(create<ast::Vector>(nullptr, 4u), vec4<i32>(1_i, 2_i, 3_i, 4_i));
+ auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4u), vec4<u32>(1_u, 2_u, 3_u, 4_u));
+ auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4u), vec4<f32>(1_f, 2_f, 3_f, 4_f));
+ auto* vec4_f16 = Construct(create<ast::Vector>(nullptr, 4u), vec4<f16>(1_h, 2_h, 3_h, 4_h));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1842,30 +2263,38 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromVec4) {
ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec4_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f16)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f16), TypeOf(vec4_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromScalarAndVec3) {
+ Enable(ast::Extension::kF16);
+
auto* vec4_bool =
- Construct(create<ast::Vector>(nullptr, 4), Expr(true), vec3<bool>(false, true, false));
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(true), vec3<bool>(false, true, false));
auto* vec4_i32 =
- Construct(create<ast::Vector>(nullptr, 4), Expr(1_i), vec3<i32>(2_i, 3_i, 4_i));
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_i), vec3<i32>(2_i, 3_i, 4_i));
auto* vec4_u32 =
- Construct(create<ast::Vector>(nullptr, 4), Expr(1_u), vec3<u32>(2_u, 3_u, 4_u));
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_u), vec3<u32>(2_u, 3_u, 4_u));
auto* vec4_f32 =
- Construct(create<ast::Vector>(nullptr, 4), Expr(1_f), vec3<f32>(2_f, 3_f, 4_f));
- WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_f), vec3<f32>(2_f, 3_f, 4_f));
+ auto* vec4_f16 =
+ Construct(create<ast::Vector>(nullptr, 4u), Expr(1_h), vec3<f16>(2_h, 3_h, 4_h));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1873,30 +2302,38 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromScalarAndV
ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec4_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f16)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f16), TypeOf(vec4_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromVec2AndVec2) {
- auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), vec2<bool>(true, false),
+ Enable(ast::Extension::kF16);
+
+ auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4u), vec2<bool>(true, false),
vec2<bool>(true, false));
auto* vec4_i32 =
- Construct(create<ast::Vector>(nullptr, 4), vec2<i32>(1_i, 2_i), vec2<i32>(3_i, 4_i));
+ Construct(create<ast::Vector>(nullptr, 4u), vec2<i32>(1_i, 2_i), vec2<i32>(3_i, 4_i));
auto* vec4_u32 =
- Construct(create<ast::Vector>(nullptr, 4), vec2<u32>(1_u, 2_u), vec2<u32>(3_u, 4_u));
+ Construct(create<ast::Vector>(nullptr, 4u), vec2<u32>(1_u, 2_u), vec2<u32>(3_u, 4_u));
auto* vec4_f32 =
- Construct(create<ast::Vector>(nullptr, 4), vec2<f32>(1_f, 2_f), vec2<f32>(3_f, 4_f));
- WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+ Construct(create<ast::Vector>(nullptr, 4u), vec2<f32>(1_f, 2_f), vec2<f32>(3_f, 4_f));
+ auto* vec4_f16 =
+ Construct(create<ast::Vector>(nullptr, 4u), vec2<f16>(1_h, 2_h), vec2<f16>(3_h, 4_h));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1904,29 +2341,33 @@ TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromVec2AndVec
ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f16)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(vec4_f16)->As<sem::Vector>()->type()->Is<sem::F16>());
EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f16)->As<sem::Vector>()->Width(), 4u);
EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f16), TypeOf(vec4_f16->target.type));
}
TEST_F(ResolverTypeConstructorValidationTest, CannotInferVectorElementTypeWithoutArgs) {
- WrapInFunction(Construct(Source{{12, 34}}, create<ast::Vector>(nullptr, 3)));
+ WrapInFunction(Construct(Source{{12, 34}}, create<ast::Vector>(nullptr, 3u)));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for vec3()"));
}
TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec2ElementTypeFromScalarsMismatch) {
- WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 2),
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 2u),
Expr(Source{{1, 2}}, 1_i), //
Expr(Source{{1, 3}}, 2_u)));
@@ -1935,7 +2376,7 @@ TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec2ElementTypeFromScal
}
TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec3ElementTypeFromScalarsMismatch) {
- WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3u),
Expr(Source{{1, 2}}, 1_i), //
Expr(Source{{1, 3}}, 2_u), //
Expr(Source{{1, 4}}, 3_i)));
@@ -1946,7 +2387,7 @@ TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec3ElementTypeFromScal
}
TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec3ElementTypeFromScalarAndVec2Mismatch) {
- WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3u),
Expr(Source{{1, 2}}, 1_i), //
Construct(Source{{1, 3}}, ty.vec2<f32>(), 2_f, 3_f)));
@@ -1956,7 +2397,7 @@ TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec3ElementTypeFromScal
}
TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromScalarsMismatch) {
- WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4u),
Expr(Source{{1, 2}}, 1_i), //
Expr(Source{{1, 3}}, 2_i), //
Expr(Source{{1, 4}}, 3_f), //
@@ -1968,7 +2409,7 @@ TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromScal
}
TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromScalarAndVec3Mismatch) {
- WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4u),
Expr(Source{{1, 2}}, 1_i), //
Construct(Source{{1, 3}}, ty.vec3<u32>(), 2_u, 3_u, 4_u)));
@@ -1978,7 +2419,7 @@ TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromScal
}
TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromVec2AndVec2Mismatch) {
- WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4u),
Construct(Source{{1, 2}}, ty.vec2<i32>(), 3_i, 4_i), //
Construct(Source{{1, 3}}, ty.vec2<u32>(), 3_u, 4_u)));
@@ -1990,35 +2431,60 @@ TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromVec2
} // namespace VectorConstructor
namespace MatrixConstructor {
-struct MatrixDimensions {
+
+struct MatrixParams {
+ using name_func_ptr = std::string (*)();
+
uint32_t rows;
uint32_t columns;
+ name_func_ptr get_element_type_name;
+ builder::ast_type_func_ptr create_element_ast_type;
+ builder::ast_expr_func_ptr create_element_ast_value;
+ builder::ast_type_func_ptr create_column_ast_type;
+ builder::ast_type_func_ptr create_mat_ast_type;
};
-static std::string MatrixStr(const MatrixDimensions& dimensions) {
- return "mat" + std::to_string(dimensions.columns) + "x" + std::to_string(dimensions.rows) +
- "<f32>";
+template <typename T, uint32_t R, uint32_t C>
+constexpr MatrixParams MatrixParamsFor() {
+ return MatrixParams{
+ R,
+ C,
+ DataType<T>::Name,
+ DataType<T>::AST,
+ DataType<T>::Expr,
+ DataType<tint::resolver::builder::vec<R, T>>::AST,
+ DataType<tint::resolver::builder::mat<C, R, T>>::AST,
+ };
+}
+
+static std::string MatrixStr(const MatrixParams& param) {
+ return "mat" + std::to_string(param.columns) + "x" + std::to_string(param.rows) + "<" +
+ param.get_element_type_name() + ">";
}
-using MatrixConstructorTest = ResolverTestWithParam<MatrixDimensions>;
+using MatrixConstructorTest = ResolverTestWithParam<MatrixParams>;
-TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewArguments) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewArguments) {
// matNxM<f32>(vecM<f32>(), ...); with N - 1 arguments
+ // matNxM<f16>(vecM<f16>(), ...); with N - 1 arguments
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
+ const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns - 1; i++) {
- auto* vec_type = ty.vec<f32>(param.rows);
- args.push_back(Construct(vec_type));
+ auto* vec_type = param.create_column_ast_type(*this);
+ args.Push(Construct(vec_type));
if (i > 0) {
args_tys << ", ";
}
- args_tys << "vec" << param.rows << "<f32>";
+ args_tys << "vec" << param.rows << "<" + element_type_name + ">";
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2027,22 +2493,26 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewArguments) {
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooFewArguments) {
+TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooFewArguments) {
// matNxM<f32>(f32,...,f32); with N*M - 1 arguments
+ // matNxM<f16>(f16,...,f16); with N*M - 1 arguments
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
+ const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns * param.rows - 1; i++) {
- args.push_back(Construct(ty.f32()));
+ args.Push(Construct(param.create_element_ast_type(*this)));
if (i > 0) {
args_tys << ", ";
}
- args_tys << "f32";
+ args_tys << element_type_name;
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2051,23 +2521,27 @@ TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooFewArguments) {
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyArguments) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyArguments) {
// matNxM<f32>(vecM<f32>(), ...); with N + 1 arguments
+ // matNxM<f16>(vecM<f16>(), ...); with N + 1 arguments
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
+ const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns + 1; i++) {
- auto* vec_type = ty.vec<f32>(param.rows);
- args.push_back(Construct(vec_type));
+ auto* vec_type = param.create_column_ast_type(*this);
+ args.Push(Construct(vec_type));
if (i > 0) {
args_tys << ", ";
}
- args_tys << "vec" << param.rows << "<f32>";
+ args_tys << "vec" << param.rows << "<" + element_type_name + ">";
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2076,22 +2550,26 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyArguments) {
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooManyArguments) {
+TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooManyArguments) {
// matNxM<f32>(f32,...,f32); with N*M + 1 arguments
+ // matNxM<f16>(f16,...,f16); with N*M + 1 arguments
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
+ const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns * param.rows + 1; i++) {
- args.push_back(Construct(ty.f32()));
+ args.Push(Construct(param.create_element_ast_type(*this)));
if (i > 0) {
args_tys << ", ";
}
- args_tys << "f32";
+ args_tys << element_type_name;
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2100,23 +2578,26 @@ TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooManyArguments) {
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_InvalidArgumentType) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_InvalidArgumentType) {
// matNxM<f32>(vec<u32>, vec<u32>, ...); N arguments
+ // matNxM<f16>(vec<u32>, vec<u32>, ...); N arguments
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
auto* vec_type = ty.vec<u32>(param.rows);
- args.push_back(Construct(vec_type));
+ args.Push(Construct(vec_type));
if (i > 0) {
args_tys << ", ";
}
args_tys << "vec" << param.rows << "<u32>";
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2125,22 +2606,25 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_InvalidArgumentType)
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_InvalidArgumentType) {
+TEST_P(MatrixConstructorTest, ElementConstructor_Error_InvalidArgumentType) {
// matNxM<f32>(u32, u32, ...); N*M arguments
+ // matNxM<f16>(u32, u32, ...); N*M arguments
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
- args.push_back(Expr(1_u));
+ args.Push(Expr(1_u));
if (i > 0) {
args_tys << ", ";
}
args_tys << "u32";
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2149,8 +2633,9 @@ TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_InvalidArgumentType)
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewRowsInVectorArgument) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewRowsInVectorArgument) {
// matNxM<f32>(vecM<f32>(),...,vecM-1<f32>());
+ // matNxM<f16>(vecM<f16>(),...,vecM-1<f32>());
const auto param = GetParam();
@@ -2159,22 +2644,25 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewRowsInVectorArg
return;
}
+ Enable(ast::Extension::kF16);
+
+ const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
- auto* valid_vec_type = ty.vec<f32>(param.rows);
- args.push_back(Construct(valid_vec_type));
+ auto* valid_vec_type = param.create_column_ast_type(*this);
+ args.Push(Construct(valid_vec_type));
if (i > 0) {
args_tys << ", ";
}
- args_tys << "vec" << param.rows << "<f32>";
+ args_tys << "vec" << param.rows << "<" + element_type_name + ">";
}
const size_t kInvalidLoc = 2 * (param.columns - 1);
- auto* invalid_vec_type = ty.vec<f32>(param.rows - 1);
- args.push_back(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
- args_tys << ", vec" << (param.rows - 1) << "<f32>";
+ auto* invalid_vec_type = ty.vec(param.create_element_ast_type(*this), param.rows - 1);
+ args.Push(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
+ args_tys << ", vec" << (param.rows - 1) << "<" + element_type_name + ">";
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2183,8 +2671,9 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewRowsInVectorArg
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyRowsInVectorArgument) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyRowsInVectorArgument) {
// matNxM<f32>(vecM<f32>(),...,vecM+1<f32>());
+ // matNxM<f16>(vecM<f16>(),...,vecM+1<f16>());
const auto param = GetParam();
@@ -2193,21 +2682,24 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyRowsInVectorAr
return;
}
+ Enable(ast::Extension::kF16);
+
+ const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
- auto* valid_vec_type = ty.vec<f32>(param.rows);
- args.push_back(Construct(valid_vec_type));
+ auto* valid_vec_type = param.create_column_ast_type(*this);
+ args.Push(Construct(valid_vec_type));
if (i > 0) {
args_tys << ", ";
}
- args_tys << "vec" << param.rows << "<f32>";
+ args_tys << "vec" << param.rows << "<" + element_type_name + ">";
}
- auto* invalid_vec_type = ty.vec<f32>(param.rows + 1);
- args.push_back(Construct(invalid_vec_type));
- args_tys << ", vec" << (param.rows + 1) << "<f32>";
+ auto* invalid_vec_type = ty.vec(param.create_element_ast_type(*this), param.rows + 1);
+ args.Push(Construct(invalid_vec_type));
+ args_tys << ", vec" << (param.rows + 1) << "<" + element_type_name + ">";
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2216,70 +2708,84 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyRowsInVectorAr
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_ZeroValue_Success) {
+TEST_P(MatrixConstructorTest, ZeroValue_Success) {
// matNxM<f32>();
+ // matNxM<f16>();
const auto param = GetParam();
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+
+ Enable(ast::Extension::kF16);
+
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{{12, 40}}, matrix_type);
WrapInFunction(tc);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_WithColumns_Success) {
+TEST_P(MatrixConstructorTest, WithColumns_Success) {
// matNxM<f32>(vecM<f32>(), ...); with N arguments
+ // matNxM<f16>(vecM<f16>(), ...); with N arguments
const auto param = GetParam();
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) {
- auto* vec_type = ty.vec<f32>(param.rows);
- args.push_back(Construct(vec_type));
+ auto* vec_type = param.create_column_ast_type(*this);
+ args.Push(Construct(vec_type));
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(matrix_type, std::move(args));
WrapInFunction(tc);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_WithElements_Success) {
+TEST_P(MatrixConstructorTest, WithElements_Success) {
// matNxM<f32>(f32,...,f32); with N*M arguments
+ // matNxM<f16>(f16,...,f16); with N*M arguments
const auto param = GetParam();
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ utils::Vector<const ast::Expression*, 16> args;
for (uint32_t i = 0; i < param.columns * param.rows; i++) {
- args.push_back(Construct(ty.f32()));
+ args.Push(Construct(param.create_element_ast_type(*this)));
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(matrix_type, std::move(args));
WrapInFunction(tc);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Error) {
+TEST_P(MatrixConstructorTest, ElementTypeAlias_Error) {
// matNxM<Float32>(vecM<u32>(), ...); with N arguments
+ // matNxM<Float16>(vecM<u32>(), ...); with N arguments
const auto param = GetParam();
- auto* f32_alias = Alias("Float32", ty.f32());
+
+ Enable(ast::Extension::kF16);
+
+ auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) {
auto* vec_type = ty.vec(ty.u32(), param.rows);
- args.push_back(Construct(vec_type));
+ args.Push(Construct(vec_type));
if (i > 0) {
args_tys << ", ";
}
args_tys << "vec" << param.rows << "<u32>";
}
- auto* matrix_type = ty.mat(ty.Of(f32_alias), param.columns, param.rows);
+ auto* matrix_type = ty.mat(ty.Of(elem_type_alias), param.columns, param.rows);
auto* tc = Construct(Source{{12, 34}}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2288,26 +2794,30 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Error) {
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
+TEST_P(MatrixConstructorTest, ElementTypeAlias_Success) {
// matNxM<Float32>(vecM<f32>(), ...); with N arguments
+ // matNxM<Float16>(vecM<f16>(), ...); with N arguments
const auto param = GetParam();
- auto* f32_alias = Alias("Float32", ty.f32());
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
+
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
- auto* vec_type = ty.vec<f32>(param.rows);
- args.push_back(Construct(vec_type));
+ auto* vec_type = param.create_column_ast_type(*this);
+ args.Push(Construct(vec_type));
}
- auto* matrix_type = ty.mat(ty.Of(f32_alias), param.columns, param.rows);
+ auto* matrix_type = ty.mat(ty.Of(elem_type_alias), param.columns, param.rows);
auto* tc = Construct(Source{}, matrix_type, std::move(args));
WrapInFunction(tc);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_MatrixConstructor_ArgumentTypeAlias_Error) {
+TEST_F(ResolverTypeConstructorValidationTest, MatrixConstructor_ArgumentTypeAlias_Error) {
auto* alias = Alias("VectorUnsigned2", ty.vec2<u32>());
auto* tc = Construct(Source{{12, 34}}, ty.mat2x2<f32>(), Construct(ty.Of(alias)), vec2<f32>());
WrapInFunction(tc);
@@ -2318,15 +2828,18 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_MatrixConstructor_ArgumentTyp
HasSubstr("12:34 error: no matching constructor for mat2x2<f32>(vec2<u32>, vec2<f32>)"));
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentTypeAlias_Success) {
+TEST_P(MatrixConstructorTest, ArgumentTypeAlias_Success) {
const auto param = GetParam();
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
- auto* vec_type = ty.vec<f32>(param.rows);
- auto* vec_alias = Alias("VectorFloat2", vec_type);
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ auto* matrix_type = param.create_mat_ast_type(*this);
+ auto* vec_type = param.create_column_ast_type(*this);
+ auto* vec_alias = Alias("ColVectorAlias", vec_type);
+
+ utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) {
- args.push_back(Construct(ty.Of(vec_alias)));
+ args.Push(Construct(ty.Of(vec_alias)));
}
auto* tc = Construct(Source{}, matrix_type, std::move(args));
@@ -2335,16 +2848,19 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentTypeAlias_Success) {
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Error) {
+TEST_P(MatrixConstructorTest, ArgumentElementTypeAlias_Error) {
const auto param = GetParam();
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
- auto* f32_alias = Alias("UnsignedInt", ty.u32());
+
+ Enable(ast::Extension::kF16);
+
+ auto* matrix_type = param.create_mat_ast_type(*this);
+ auto* u32_type_alias = Alias("UnsignedInt", ty.u32());
std::stringstream args_tys;
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) {
- auto* vec_type = ty.vec(ty.Of(f32_alias), param.rows);
- args.push_back(Construct(vec_type));
+ auto* vec_type = ty.vec(ty.Of(u32_type_alias), param.rows);
+ args.Push(Construct(vec_type));
if (i > 0) {
args_tys << ", ";
}
@@ -2359,17 +2875,20 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Error) {
MatrixStr(param) + "(" + args_tys.str() + ")"));
}
-TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Success) {
+TEST_P(MatrixConstructorTest, ArgumentElementTypeAlias_Success) {
const auto param = GetParam();
- auto* f32_alias = Alias("Float32", ty.f32());
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
+
+ utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) {
- auto* vec_type = ty.vec(ty.Of(f32_alias), param.rows);
- args.push_back(Construct(vec_type));
+ auto* vec_type = ty.vec(ty.Of(elem_type_alias), param.rows);
+ args.Push(Construct(vec_type));
}
- auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+ auto* matrix_type = param.create_mat_ast_type(*this);
auto* tc = Construct(Source{}, matrix_type, std::move(args));
WrapInFunction(tc);
@@ -2379,9 +2898,11 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Success)
TEST_P(MatrixConstructorTest, InferElementTypeFromVectors) {
const auto param = GetParam();
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
- args.push_back(Construct(ty.vec<f32>(param.rows)));
+ args.Push(Construct(param.create_column_ast_type(*this)));
}
auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
@@ -2394,9 +2915,11 @@ TEST_P(MatrixConstructorTest, InferElementTypeFromVectors) {
TEST_P(MatrixConstructorTest, InferElementTypeFromScalars) {
const auto param = GetParam();
- ast::ExpressionList args;
+ Enable(ast::Extension::kF16);
+
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.rows * param.columns; i++) {
- args.push_back(Expr(static_cast<f32>(i)));
+ args.Push(param.create_element_ast_value(*this, static_cast<double>(i)));
}
auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
@@ -2408,22 +2931,24 @@ TEST_P(MatrixConstructorTest, InferElementTypeFromScalars) {
TEST_P(MatrixConstructorTest, CannotInferElementTypeFromVectors_Mismatch) {
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
std::stringstream err;
err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
<< "(";
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
if (i > 0) {
err << ", ";
}
if (i == 1) {
// Odd one out
- args.push_back(Construct(ty.vec<i32>(param.rows)));
+ args.Push(Construct(ty.vec<i32>(param.rows)));
err << "vec" << param.rows << "<i32>";
} else {
- args.push_back(Construct(ty.vec<f32>(param.rows)));
- err << "vec" << param.rows << "<f32>";
+ args.Push(Construct(param.create_column_ast_type(*this)));
+ err << "vec" << param.rows << "<" + param.get_element_type_name() + ">";
}
}
@@ -2437,21 +2962,23 @@ TEST_P(MatrixConstructorTest, CannotInferElementTypeFromVectors_Mismatch) {
TEST_P(MatrixConstructorTest, CannotInferElementTypeFromScalars_Mismatch) {
const auto param = GetParam();
+ Enable(ast::Extension::kF16);
+
std::stringstream err;
err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
<< "(";
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 16> args;
for (uint32_t i = 0; i < param.rows * param.columns; i++) {
if (i > 0) {
err << ", ";
}
if (i == 3) {
- args.push_back(Expr(static_cast<i32>(i))); // The odd one out
+ args.Push(Expr(static_cast<i32>(i))); // The odd one out
err << "i32";
} else {
- args.push_back(Expr(static_cast<f32>(i)));
- err << "f32";
+ args.Push(param.create_element_ast_value(*this, static_cast<double>(i)));
+ err << param.get_element_type_name();
}
}
@@ -2466,15 +2993,24 @@ TEST_P(MatrixConstructorTest, CannotInferElementTypeFromScalars_Mismatch) {
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
MatrixConstructorTest,
- testing::Values(MatrixDimensions{2, 2},
- MatrixDimensions{3, 2},
- MatrixDimensions{4, 2},
- MatrixDimensions{2, 3},
- MatrixDimensions{3, 3},
- MatrixDimensions{4, 3},
- MatrixDimensions{2, 4},
- MatrixDimensions{3, 4},
- MatrixDimensions{4, 4}));
+ testing::Values(MatrixParamsFor<f32, 2, 2>(),
+ MatrixParamsFor<f32, 3, 2>(),
+ MatrixParamsFor<f32, 4, 2>(),
+ MatrixParamsFor<f32, 2, 3>(),
+ MatrixParamsFor<f32, 3, 3>(),
+ MatrixParamsFor<f32, 4, 3>(),
+ MatrixParamsFor<f32, 2, 4>(),
+ MatrixParamsFor<f32, 3, 4>(),
+ MatrixParamsFor<f32, 4, 4>(),
+ MatrixParamsFor<f16, 2, 2>(),
+ MatrixParamsFor<f16, 3, 2>(),
+ MatrixParamsFor<f16, 4, 2>(),
+ MatrixParamsFor<f16, 2, 3>(),
+ MatrixParamsFor<f16, 3, 3>(),
+ MatrixParamsFor<f16, 4, 3>(),
+ MatrixParamsFor<f16, 2, 4>(),
+ MatrixParamsFor<f16, 3, 4>(),
+ MatrixParamsFor<f16, 4, 4>()));
} // namespace MatrixConstructor
namespace StructConstructor {
@@ -2492,13 +3028,18 @@ constexpr CreatePtrs all_types[] = {
CreatePtrsFor<u32>(), //
CreatePtrsFor<i32>(), //
CreatePtrsFor<f32>(), //
+ CreatePtrsFor<f16>(), //
CreatePtrsFor<vec4<bool>>(), //
CreatePtrsFor<vec2<i32>>(), //
CreatePtrsFor<vec3<u32>>(), //
CreatePtrsFor<vec4<f32>>(), //
+ CreatePtrsFor<vec4<f16>>(), //
CreatePtrsFor<mat2x2<f32>>(), //
CreatePtrsFor<mat3x3<f32>>(), //
- CreatePtrsFor<mat4x4<f32>>() //
+ CreatePtrsFor<mat4x4<f32>>(), //
+ CreatePtrsFor<mat2x2<f16>>(), //
+ CreatePtrsFor<mat3x3<f16>>(), //
+ CreatePtrsFor<mat4x4<f16>>() //
};
auto number_of_members = testing::Values(2u, 32u, 64u);
@@ -2511,14 +3052,16 @@ TEST_P(StructConstructorInputsTest, TooFew) {
auto& str_params = std::get<0>(param);
uint32_t N = std::get<1>(param);
- ast::StructMemberList members;
- ast::ExpressionList values;
+ Enable(ast::Extension::kF16);
+
+ utils::Vector<const ast::StructMember*, 16> members;
+ utils::Vector<const ast::Expression*, 16> values;
for (uint32_t i = 0; i < N; i++) {
auto* struct_type = str_params.ast(*this);
- members.push_back(Member("member_" + std::to_string(i), struct_type));
+ members.Push(Member("member_" + std::to_string(i), struct_type));
if (i < N - 1) {
auto* ctor_value_expr = str_params.expr(*this, 0);
- values.push_back(ctor_value_expr);
+ values.Push(ctor_value_expr);
}
}
auto* s = Structure("s", members);
@@ -2534,15 +3077,17 @@ TEST_P(StructConstructorInputsTest, TooMany) {
auto& str_params = std::get<0>(param);
uint32_t N = std::get<1>(param);
- ast::StructMemberList members;
- ast::ExpressionList values;
+ Enable(ast::Extension::kF16);
+
+ utils::Vector<const ast::StructMember*, 16> members;
+ utils::Vector<const ast::Expression*, 8> values;
for (uint32_t i = 0; i < N + 1; i++) {
if (i < N) {
auto* struct_type = str_params.ast(*this);
- members.push_back(Member("member_" + std::to_string(i), struct_type));
+ members.Push(Member("member_" + std::to_string(i), struct_type));
}
auto* ctor_value_expr = str_params.expr(*this, 0);
- values.push_back(ctor_value_expr);
+ values.Push(ctor_value_expr);
}
auto* s = Structure("s", members);
auto* tc = Construct(Source{{12, 34}}, ty.Of(s), values);
@@ -2565,21 +3110,23 @@ TEST_P(StructConstructorTypeTest, AllTypes) {
auto& ctor_params = std::get<1>(param);
uint32_t N = std::get<2>(param);
+ Enable(ast::Extension::kF16);
+
if (str_params.ast == ctor_params.ast) {
return;
}
- ast::StructMemberList members;
- ast::ExpressionList values;
+ utils::Vector<const ast::StructMember*, 16> members;
+ utils::Vector<const ast::Expression*, 8> values;
// make the last value of the constructor to have a different type
uint32_t constructor_value_with_different_type = N - 1;
for (uint32_t i = 0; i < N; i++) {
auto* struct_type = str_params.ast(*this);
- members.push_back(Member("member_" + std::to_string(i), struct_type));
+ members.Push(Member("member_" + std::to_string(i), struct_type));
auto* ctor_value_expr = (i == constructor_value_with_different_type)
? ctor_params.expr(*this, 0)
: str_params.expr(*this, 0);
- values.push_back(ctor_value_expr);
+ values.Push(ctor_value_expr);
}
auto* s = Structure("s", members);
auto* tc = Construct(ty.Of(s), values);
@@ -2600,14 +3147,14 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
testing::ValuesIn(all_types),
number_of_members));
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Nested) {
+TEST_F(ResolverTypeConstructorValidationTest, Struct_Nested) {
auto* inner_m = Member("m", ty.i32());
- auto* inner_s = Structure("inner_s", {inner_m});
+ auto* inner_s = Structure("inner_s", utils::Vector{inner_m});
auto* m0 = Member("m0", ty.i32());
auto* m1 = Member("m1", ty.Of(inner_s));
auto* m2 = Member("m2", ty.i32());
- auto* s = Structure("s", {m0, m1, m2});
+ auto* s = Structure("s", utils::Vector{m0, m1, m2});
auto* tc = Construct(Source{{12, 34}}, ty.Of(s), 1_i, 1_i, 1_i);
WrapInFunction(tc);
@@ -2617,16 +3164,16 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Nested) {
"type: expected 'inner_s', found 'i32'");
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct) {
+TEST_F(ResolverTypeConstructorValidationTest, Struct) {
auto* m = Member("m", ty.i32());
- auto* s = Structure("MyInputs", {m});
+ auto* s = Structure("MyInputs", utils::Vector{m});
auto* tc = Construct(Source{{12, 34}}, ty.Of(s));
WrapInFunction(tc);
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Empty) {
- auto* str = Structure("S", {
+TEST_F(ResolverTypeConstructorValidationTest, Struct_Empty) {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
Member("c", ty.vec3<i32>()),
@@ -2653,7 +3200,7 @@ TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_AtomicArray)
}
TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_AtomicStructMember) {
- auto* str = Structure("S", {Member("a", ty.atomic(ty.i32()))});
+ auto* str = Structure("S", utils::Vector{Member("a", ty.atomic(ty.i32()))});
WrapInFunction(Assign(Phony(), Construct(Source{{12, 34}}, ty.Of(str))));
EXPECT_FALSE(r()->Resolve());
@@ -2669,7 +3216,7 @@ TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Sampler) {
}
TEST_F(ResolverTypeConstructorValidationTest, TypeConstructorAsStatement) {
- WrapInFunction(CallStmt(Construct(Source{{12, 34}}, ty.vec2<f32>(), 1_f, 2_f)));
+ WrapInFunction(CallStmt(vec2<f32>(Source{{12, 34}}, 1_f, 2_f)));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: type constructor evaluated but not used");
diff --git a/chromium/third_party/dawn/src/tint/resolver/type_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/type_validation_test.cc
index a5e68cef343..d7c2e647107 100644
--- a/chromium/third_party/dawn/src/tint/resolver/type_validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/type_validation_test.cc
@@ -75,31 +75,24 @@ TEST_F(ResolverTypeValidationTest, VariableDeclNoConstructor_Pass) {
TEST_F(ResolverTypeValidationTest, GlobalOverrideNoConstructor_Pass) {
// @id(0) override a :i32;
- Override(Source{{12, 34}}, "a", ty.i32(), nullptr, ast::AttributeList{Id(0)});
+ Override(Source{{12, 34}}, "a", ty.i32(), nullptr,
+ utils::Vector{
+ Id(0),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) {
// var<private> global_var: f32;
- Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeValidationTest, GlobalLetWithStorageClass_Fail) {
- // let<private> global_var: f32;
- AST().AddGlobalVariable(create<ast::Variable>(
- Source{{12, 34}}, Symbols().Register("global_var"), ast::StorageClass::kPrivate,
- ast::Access::kUndefined, ty.f32(), true, false, Expr(1.23_f), ast::AttributeList{}));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: global constants shouldn't have a storage class");
-}
-
TEST_F(ResolverTypeValidationTest, GlobalConstNoStorageClass_Pass) {
- // let global_var: f32;
- GlobalConst(Source{{12, 34}}, "global_var", ty.f32(), Construct(ty.f32()));
+ // const global_const: f32 = f32();
+ GlobalConst(Source{{12, 34}}, "global_const", ty.f32(), Construct(ty.f32()));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -108,9 +101,9 @@ TEST_F(ResolverTypeValidationTest, GlobalVariableUnique_Pass) {
// var global_var0 : f32 = 0.1;
// var global_var1 : i32 = 0;
- Global("global_var0", ty.f32(), ast::StorageClass::kPrivate, Expr(0.1_f));
+ GlobalVar("global_var0", ty.f32(), ast::StorageClass::kPrivate, Expr(0.1_f));
- Global(Source{{12, 34}}, "global_var1", ty.f32(), ast::StorageClass::kPrivate, Expr(1_f));
+ GlobalVar(Source{{12, 34}}, "global_var1", ty.f32(), ast::StorageClass::kPrivate, Expr(1_f));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -121,11 +114,12 @@ TEST_F(ResolverTypeValidationTest, GlobalVariableFunctionVariableNotUnique_Pass)
// }
// var a: f32 = 2.1;
- auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2_f));
-
- Func("my_func", ast::VariableList{}, ty.void_(), {Decl(var)});
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2_f))),
+ });
- Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -172,15 +166,14 @@ TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierDifferentFunctions_Pass)
auto* var1 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(1_f));
- Func("func0", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("func0", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Source{{12, 34}}, var0),
Return(),
- },
- ast::AttributeList{});
+ });
- Func("func1", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("func1", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Source{{13, 34}}, var1),
Return(),
});
@@ -190,160 +183,181 @@ TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierDifferentFunctions_Pass)
TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Pass) {
// var<private> a : array<f32, 4>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_a)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_a)), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Pass) {
// var<private> a : array<f32, 4u>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_u)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_u)), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Pass) {
// var<private> a : array<f32, 4i>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_i)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_i)), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLet_Pass) {
- // let size = 4u;
+TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConst_Pass) {
+ // const size = 4u;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(4_u));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeValidationTest, ArraySize_SignedLet_Pass) {
- // let size = 4i;
+TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Pass) {
+ // const size = 4i;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(4_i));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Zero) {
// var<private> a : array<f32, 0>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_a)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_a)), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+ EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
}
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Zero) {
// var<private> a : array<f32, 0u>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_u)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_u)), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+ EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
}
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Zero) {
// var<private> a : array<f32, 0i>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_i)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_i)), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+ EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
}
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Negative) {
// var<private> a : array<f32, -10i>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10_i)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10_i)), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+ EXPECT_EQ(r()->error(), "12:34 error: array size (-10) must be greater than 0");
}
-TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLet_Zero) {
- // let size = 0u;
+TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConst_Zero) {
+ // const size = 0u;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(0_u));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+ EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
}
-TEST_F(ResolverTypeValidationTest, ArraySize_SignedLet_Zero) {
- // let size = 0i;
+TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Zero) {
+ // const size = 0i;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(0_i));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+ EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
}
-TEST_F(ResolverTypeValidationTest, ArraySize_SignedLet_Negative) {
- // let size = -10i;
+TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Negative) {
+ // const size = -10i;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(-10_i));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+ EXPECT_EQ(r()->error(), "12:34 error: array size (-10) must be greater than 0");
}
TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
// var<private> a : array<f32, 10.0>;
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10_f)), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10_f)), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: array size must evaluate to a constant integer expression, but is type "
+ "'f32'");
}
TEST_F(ResolverTypeValidationTest, ArraySize_IVecLiteral) {
// var<private> a : array<f32, vec2<i32>(10, 10)>;
- Global("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10_i, 10_i)),
- ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10_i, 10_i)),
+ ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: array size must evaluate to a constant integer expression, but is type "
+ "'vec2<i32>'");
}
-TEST_F(ResolverTypeValidationTest, ArraySize_FloatLet) {
- // let size = 10.0;
+TEST_F(ResolverTypeValidationTest, ArraySize_FloatConst) {
+ // const size = 10.0;
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Expr(10_f));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: array size must evaluate to a constant integer expression, but is type "
+ "'f32'");
}
-TEST_F(ResolverTypeValidationTest, ArraySize_IVecLet) {
- // let size = vec2<i32>(100, 100);
+TEST_F(ResolverTypeValidationTest, ArraySize_IVecConst) {
+ // const size = vec2<i32>(100, 100);
// var<private> a : array<f32, size>;
GlobalConst("size", nullptr, Construct(ty.vec2<i32>(), 100_i, 100_i));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: array size must evaluate to a constant integer expression, but is type "
+ "'vec2<i32>'");
}
TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
// var<private> a : array<f32, 0x40000000u>;
- Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x40000000_u), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), 0x40000000_u), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: array size in bytes must not exceed 0xffffffff, but "
- "is 0x100000000");
+ "12:34 error: array size (0x100000000) must not exceed 0xffffffff bytes");
}
TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ExplicitStride) {
// var<private> a : @stride(8) array<f32, 0x20000000u>;
- Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x20000000_u, 8), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), 0x20000000_u, 8),
+ ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: array size in bytes must not exceed 0xffffffff, but "
- "is 0x100000000");
+ "12:34 error: array size (0x100000000) must not exceed 0xffffffff bytes");
}
TEST_F(ResolverTypeValidationTest, ArraySize_Overridable) {
// override size = 10i;
// var<private> a : array<f32, size>;
Override("size", nullptr, Expr(10_i));
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size expression must not be pipeline-overridable");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: array size must evaluate to a constant integer expression");
}
TEST_F(ResolverTypeValidationTest, ArraySize_ModuleVar) {
// var<private> size : i32 = 10i;
// var<private> a : array<f32, size>;
- Global("size", ty.i32(), Expr(10_i), ast::StorageClass::kPrivate);
- Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+ GlobalVar("size", ty.i32(), Expr(10_i), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size identifier must be a module-scope constant");
+ EXPECT_EQ(r()->error(),
+ R"(12:34 error: var 'size' cannot not be referenced at module-scope
+note: var 'size' declared here)");
+}
+
+TEST_F(ResolverTypeValidationTest, ArraySize_FunctionConst) {
+ // {
+ // const size = 10;
+ // var a : array<f32, size>;
+ // }
+ auto* size = Const("size", nullptr, Expr(10_i));
+ auto* a = Var("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")));
+ WrapInFunction(size, a);
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverTypeValidationTest, ArraySize_FunctionLet) {
@@ -353,19 +367,17 @@ TEST_F(ResolverTypeValidationTest, ArraySize_FunctionLet) {
// }
auto* size = Let("size", nullptr, Expr(10_i));
auto* a = Var("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")));
- WrapInFunction(Block(Decl(size), Decl(a)));
+ WrapInFunction(size, a);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: array size identifier must be a module-scope constant");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: array size must evaluate to a constant integer expression");
}
-TEST_F(ResolverTypeValidationTest, ArraySize_InvalidExpr) {
+TEST_F(ResolverTypeValidationTest, ArraySize_ComplexExpr) {
// var a : array<f32, i32(4i)>;
auto* a = Var("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.i32(), 4_i)));
- WrapInFunction(Block(Decl(a)));
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: array size expression must be either a literal or a "
- "module-scope constant");
+ WrapInFunction(a);
+ EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
@@ -374,18 +386,18 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
auto* var = Var(Source{{12, 34}}, "a", ty.array<i32>(), ast::StorageClass::kNone);
- Func("func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kVertex),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
-12:34 note: while instantiating variable a)");
+12:34 note: while instantiating 'var' a)");
}
TEST_F(ResolverTypeValidationTest, Struct_Member_VectorNoType) {
@@ -393,7 +405,9 @@ TEST_F(ResolverTypeValidationTest, Struct_Member_VectorNoType) {
// a: vec3;
// };
- Structure("S", {Member("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))});
+ Structure("S", utils::Vector{
+ Member("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3u)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
@@ -403,7 +417,9 @@ TEST_F(ResolverTypeValidationTest, Struct_Member_MatrixNoType) {
// struct S {
// a: mat3x3;
// };
- Structure("S", {Member("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))});
+ Structure("S", utils::Vector{
+ Member("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3u, 3u)),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
@@ -416,17 +432,14 @@ TEST_F(ResolverTypeValidationTest, Struct_TooBig) {
// };
Structure(Source{{12, 34}}, "Foo",
- {
+ utils::Vector{
Member("a", ty.array<f32, 0x20000000>()),
Member("b", ty.array<f32, 0x20000000>()),
});
- WrapInFunction();
-
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: struct size in bytes must not exceed 0xffffffff, but "
- "is 0x100000000");
+ "12:34 error: struct size (0x100000000) must not exceed 0xffffffff bytes");
}
TEST_F(ResolverTypeValidationTest, Struct_MemberOffset_TooBig) {
@@ -436,18 +449,15 @@ TEST_F(ResolverTypeValidationTest, Struct_MemberOffset_TooBig) {
// c: f32;
// };
- Structure("Foo", {
+ Structure("Foo", utils::Vector{
Member("a", ty.array<f32, 0x3fffffff>()),
Member("b", ty.f32()),
Member(Source{{12, 34}}, "c", ty.f32()),
});
- WrapInFunction();
-
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: struct member has byte offset 0x100000000, but must "
- "not exceed 0xffffffff");
+ "12:34 error: struct member offset (0x100000000) must not exceed 0xffffffff bytes");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayIsLast_Pass) {
@@ -456,13 +466,11 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayIsLast_Pass) {
// rt: array<f32>;
// };
- Structure("Foo", {
+ Structure("Foo", utils::Vector{
Member("vf", ty.f32()),
Member("rt", ty.array<f32>()),
});
- WrapInFunction();
-
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -471,12 +479,13 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInArray) {
// rt : array<array<f32>, 4u>;
// };
- Structure("Foo", {Member("rt", ty.array(Source{{12, 34}}, ty.array<f32>(), 4_u))});
+ Structure("Foo", utils::Vector{
+ Member("rt", ty.array(Source{{12, 34}}, ty.array<f32>(), 4_u)),
+ });
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
- "12:34 error: an array element type cannot contain a runtime-sized "
- "array");
+ "12:34 error: an array element type cannot contain a runtime-sized array");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayInStructInArray) {
@@ -485,13 +494,14 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInStructInArray) {
// };
// var<private> a : array<Foo, 4>;
- auto* foo = Structure("Foo", {Member("rt", ty.array<f32>())});
- Global("v", ty.array(Source{{12, 34}}, ty.Of(foo), 4_u), ast::StorageClass::kPrivate);
+ auto* foo = Structure("Foo", utils::Vector{
+ Member("rt", ty.array<f32>()),
+ });
+ GlobalVar("v", ty.array(Source{{12, 34}}, ty.Of(foo), 4_u), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
- "12:34 error: an array element type cannot contain a runtime-sized "
- "array");
+ "12:34 error: an array element type cannot contain a runtime-sized array");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayInStructInStruct) {
@@ -502,13 +512,17 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInStructInStruct) {
// inner : Foo;
// };
- auto* foo = Structure("Foo", {Member("rt", ty.array<f32>())});
- Structure("Outer", {Member(Source{{12, 34}}, "inner", ty.Of(foo))});
+ auto* foo = Structure("Foo", utils::Vector{
+ Member("rt", ty.array<f32>()),
+ });
+ Structure("Outer", utils::Vector{
+ Member(Source{{12, 34}}, "inner", ty.Of(foo)),
+ });
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
- "12:34 error: a struct that contains a runtime array cannot be "
- "nested inside another struct");
+ "12:34 error: a struct that contains a runtime array cannot be nested inside another "
+ "struct");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayIsNotLast_Fail) {
@@ -517,26 +531,24 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayIsNotLast_Fail) {
// vf: f32;
// };
- Structure("Foo", {
+ Structure("Foo", utils::Vector{
Member(Source{{12, 34}}, "rt", ty.array<f32>()),
Member("vf", ty.f32()),
});
- WrapInFunction();
-
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
R"(12:34 error: runtime arrays may only appear as the last member of a struct)");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
- Global(Source{{56, 78}}, "g", ty.array<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar(Source{{56, 78}}, "g", ty.array<i32>(), ast::StorageClass::kPrivate);
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
@@ -547,7 +559,7 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
EXPECT_EQ(r()->error(),
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
-56:78 note: while instantiating variable g)");
+56:78 note: while instantiating 'var' g)");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
@@ -556,17 +568,16 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
auto* param = Param(Source{{12, 34}}, "a", ty.array<i32>());
- Func("func", ast::VariableList{param}, ty.void_(),
- ast::StatementList{
+ Func("func", utils::Vector{param}, ty.void_(),
+ utils::Vector{
Return(),
- },
- ast::AttributeList{});
+ });
- Func("main", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kVertex),
});
@@ -582,11 +593,10 @@ TEST_F(ResolverTypeValidationTest, PtrToRuntimeArrayAsParameter_Fail) {
auto* param =
Param(Source{{12, 34}}, "a", ty.pointer(ty.array<i32>(), ast::StorageClass::kWorkgroup));
- Func("func", ast::VariableList{param}, ty.void_(),
- ast::StatementList{
+ Func("func", utils::Vector{param}, ty.void_(),
+ utils::Vector{
Return(),
- },
- ast::AttributeList{});
+ });
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
@@ -602,17 +612,14 @@ TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsNotLast_Fail) {
//}
auto* alias = Alias("RTArr", ty.array<u32>());
- Structure("s", {
+ Structure("s", utils::Vector{
Member(Source{{12, 34}}, "b", ty.Of(alias)),
Member("a", ty.u32()),
});
- WrapInFunction();
-
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
- "12:34 error: runtime arrays may only appear as the last member of "
- "a struct");
+ "12:34 error: runtime arrays may only appear as the last member of a struct");
}
TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsLast_Pass) {
@@ -623,31 +630,28 @@ TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsLast_Pass) {
//}
auto* alias = Alias("RTArr", ty.array<u32>());
- Structure("s", {
+ Structure("s", utils::Vector{
Member("a", ty.u32()),
Member("b", ty.Of(alias)),
});
- WrapInFunction();
-
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
auto* tex_ty = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
- Global("arr", ty.array(Source{{12, 34}}, tex_ty, 4_i), ast::StorageClass::kPrivate);
+ GlobalVar("arr", ty.array(Source{{12, 34}}, tex_ty, 4_i), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: texture_2d<f32> cannot be used as an element type of "
- "an array");
+ "12:34 error: texture_2d<f32> cannot be used as an element type of an array");
}
TEST_F(ResolverTypeValidationTest, VariableAsType) {
// var<private> a : i32;
// var<private> b : a;
- Global("a", ty.i32(), ast::StorageClass::kPrivate);
- Global("b", ty.type_name("a"), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.type_name("a"), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -658,8 +662,8 @@ note: 'a' declared here)");
TEST_F(ResolverTypeValidationTest, FunctionAsType) {
// fn f() {}
// var<private> v : f;
- Func("f", {}, ty.void_(), {});
- Global("v", ty.type_name("f"), ast::StorageClass::kPrivate);
+ Func("f", utils::Empty, ty.void_(), {});
+ GlobalVar("v", ty.type_name("f"), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -669,7 +673,7 @@ note: 'f' declared here)");
TEST_F(ResolverTypeValidationTest, BuiltinAsType) {
// var<private> v : max;
- Global("v", ty.type_name("max"), ast::StorageClass::kPrivate);
+ GlobalVar("v", ty.type_name("max"), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "error: cannot use builtin 'max' as type");
@@ -680,14 +684,14 @@ TEST_F(ResolverTypeValidationTest, F16TypeUsedWithExtension) {
// var<private> v : f16;
Enable(ast::Extension::kF16);
- Global("v", ty.f16(), ast::StorageClass::kPrivate);
+ GlobalVar("v", ty.f16(), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverTypeValidationTest, F16TypeUsedWithoutExtension) {
// var<private> v : f16;
- Global("v", ty.f16(), ast::StorageClass::kPrivate);
+ GlobalVar("v", ty.f16(), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "error: f16 used without 'f16' extension enabled");
@@ -759,8 +763,11 @@ struct DimensionParams {
using SampledTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
TEST_P(SampledTextureDimensionTest, All) {
auto& params = GetParam();
- Global(Source{{12, 34}}, "a", ty.sampled_texture(params.dim, ty.i32()),
- ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar(Source{{12, 34}}, "a", ty.sampled_texture(params.dim, ty.i32()),
+ ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -777,8 +784,11 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
using MultisampledTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
TEST_P(MultisampledTextureDimensionTest, All) {
auto& params = GetParam();
- Global(Source{{12, 34}}, "a", ty.multisampled_texture(params.dim, ty.i32()),
- ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a", ty.multisampled_texture(Source{{12, 34}}, params.dim, ty.i32()),
+ ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -828,17 +838,19 @@ static constexpr TypeParams type_cases[] = {
using SampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
TEST_P(SampledTextureTypeTest, All) {
auto& params = GetParam();
- Global(Source{{12, 34}}, "a",
- ty.sampled_texture(ast::TextureDimension::k2d, params.type_func(*this)),
- ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar(
+ "a",
+ ty.sampled_texture(Source{{12, 34}}, ast::TextureDimension::k2d, params.type_func(*this)),
+ ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: texture_2d<type>: type must be f32, "
- "i32 or u32");
+ EXPECT_EQ(r()->error(), "12:34 error: texture_2d<type>: type must be f32, i32 or u32");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -848,17 +860,20 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
using MultisampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
TEST_P(MultisampledTextureTypeTest, All) {
auto& params = GetParam();
- Global(Source{{12, 34}}, "a",
- ty.multisampled_texture(ast::TextureDimension::k2d, params.type_func(*this)),
- ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a",
+ ty.multisampled_texture(Source{{12, 34}}, ast::TextureDimension::k2d,
+ params.type_func(*this)),
+ ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: texture_multisampled_2d<type>: type must be f32, "
- "i32 or u32");
+ "12:34 error: texture_multisampled_2d<type>: type must be f32, i32 or u32");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -890,15 +905,17 @@ TEST_P(StorageTextureDimensionTest, All) {
auto* st = ty.storage_texture(Source{{12, 34}}, params.dim, ast::TexelFormat::kR32Uint,
ast::Access::kWrite);
- Global("a", st, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a", st, ast::StorageClass::kNone,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: cube dimensions for storage textures are not "
- "supported");
+ "12:34 error: cube dimensions for storage textures are not supported");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -941,26 +958,37 @@ TEST_P(StorageTextureFormatTest, All) {
auto* st_a = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d, params.format,
ast::Access::kWrite);
- Global("a", st_a, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a", st_a, ast::StorageClass::kNone,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
auto* st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format, ast::Access::kWrite);
- Global("b", st_b, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 1)});
+ GlobalVar("b", st_b, ast::StorageClass::kNone,
+ utils::Vector{
+ GroupAndBinding(0, 1),
+ });
auto* st_c =
ty.storage_texture(ast::TextureDimension::k2dArray, params.format, ast::Access::kWrite);
- Global("c", st_c, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 2)});
+ GlobalVar("c", st_c, ast::StorageClass::kNone,
+ utils::Vector{
+ GroupAndBinding(0, 2),
+ });
auto* st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format, ast::Access::kWrite);
- Global("d", st_d, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 3)});
+ GlobalVar("d", st_d, ast::StorageClass::kNone,
+ utils::Vector{
+ GroupAndBinding(0, 3),
+ });
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: image format must be one of the texel formats "
- "specified for storage textues in "
- "https://gpuweb.github.io/gpuweb/wgsl/#texel-formats");
+ "12:34 error: image format must be one of the texel formats specified for "
+ "storage textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -976,7 +1004,10 @@ TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
ast::TexelFormat::kR32Uint, ast::Access::kUndefined);
- Global("a", st, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a", st, ast::StorageClass::kNone,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: storage texture missing access control");
@@ -989,12 +1020,14 @@ TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
ast::TexelFormat::kR32Uint, ast::Access::kReadWrite);
- Global("a", st, ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a", st, ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: storage textures currently only support 'write' "
- "access control");
+ "12:34 error: storage textures currently only support 'write' access control");
}
TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
@@ -1004,12 +1037,14 @@ TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
ast::TexelFormat::kR32Uint, ast::Access::kRead);
- Global("a", st, ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a", st, ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: storage textures currently only support 'write' "
- "access control");
+ "12:34 error: storage textures currently only support 'write' access control");
}
TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
@@ -1019,7 +1054,10 @@ TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
auto* st = ty.storage_texture(ast::TextureDimension::k1d, ast::TexelFormat::kR32Uint,
ast::Access::kWrite);
- Global("a", st, ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
+ GlobalVar("a", st, ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ GroupAndBinding(0, 0),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -1042,8 +1080,11 @@ using ValidMatrixTypes = ResolverTestWithParam<Params>;
TEST_P(ValidMatrixTypes, Okay) {
// var a : matNxM<EL_TY>;
auto& params = GetParam();
- Global("a", ty.mat(params.elem_ty(*this), params.columns, params.rows),
- ast::StorageClass::kPrivate);
+
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.mat(params.elem_ty(*this), params.columns, params.rows),
+ ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -1059,16 +1100,31 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
ParamsFor<f32>(4, 4),
ParamsFor<alias<f32>>(4, 2),
ParamsFor<alias<f32>>(4, 3),
- ParamsFor<alias<f32>>(4, 4)));
+ ParamsFor<alias<f32>>(4, 4),
+ ParamsFor<f16>(2, 2),
+ ParamsFor<f16>(2, 3),
+ ParamsFor<f16>(2, 4),
+ ParamsFor<f16>(3, 2),
+ ParamsFor<f16>(3, 3),
+ ParamsFor<f16>(3, 4),
+ ParamsFor<f16>(4, 2),
+ ParamsFor<f16>(4, 3),
+ ParamsFor<f16>(4, 4),
+ ParamsFor<alias<f16>>(4, 2),
+ ParamsFor<alias<f16>>(4, 3),
+ ParamsFor<alias<f16>>(4, 4)));
using InvalidMatrixElementTypes = ResolverTestWithParam<Params>;
TEST_P(InvalidMatrixElementTypes, InvalidElementType) {
// var a : matNxM<EL_TY>;
auto& params = GetParam();
- Global("a", ty.mat(Source{{12, 34}}, params.elem_ty(*this), params.columns, params.rows),
- ast::StorageClass::kPrivate);
+
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.mat(Source{{12, 34}}, params.elem_ty(*this), params.columns, params.rows),
+ ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32'");
+ EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32' or 'f16'");
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
InvalidMatrixElementTypes,
@@ -1076,12 +1132,17 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
ParamsFor<i32>(4, 3),
ParamsFor<u32>(4, 4),
ParamsFor<vec2<f32>>(2, 2),
+ ParamsFor<vec2<f16>>(2, 2),
ParamsFor<vec3<i32>>(2, 3),
ParamsFor<vec4<u32>>(2, 4),
ParamsFor<mat2x2<f32>>(3, 2),
ParamsFor<mat3x3<f32>>(3, 3),
ParamsFor<mat4x4<f32>>(3, 4),
- ParamsFor<array<2, f32>>(4, 2)));
+ ParamsFor<mat2x2<f16>>(3, 2),
+ ParamsFor<mat3x3<f16>>(3, 3),
+ ParamsFor<mat4x4<f16>>(3, 4),
+ ParamsFor<array<2, f32>>(4, 2),
+ ParamsFor<array<2, f16>>(4, 2)));
} // namespace MatrixTests
namespace VectorTests {
@@ -1099,25 +1160,32 @@ using ValidVectorTypes = ResolverTestWithParam<Params>;
TEST_P(ValidVectorTypes, Okay) {
// var a : vecN<EL_TY>;
auto& params = GetParam();
- Global("a", ty.vec(params.elem_ty(*this), params.width), ast::StorageClass::kPrivate);
+
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.vec(params.elem_ty(*this), params.width), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
ValidVectorTypes,
testing::Values(ParamsFor<bool>(2),
ParamsFor<f32>(2),
+ ParamsFor<f16>(2),
ParamsFor<i32>(2),
ParamsFor<u32>(2),
ParamsFor<bool>(3),
ParamsFor<f32>(3),
+ ParamsFor<f16>(3),
ParamsFor<i32>(3),
ParamsFor<u32>(3),
ParamsFor<bool>(4),
ParamsFor<f32>(4),
+ ParamsFor<f16>(4),
ParamsFor<i32>(4),
ParamsFor<u32>(4),
ParamsFor<alias<bool>>(4),
ParamsFor<alias<f32>>(4),
+ ParamsFor<alias<f16>>(4),
ParamsFor<alias<i32>>(4),
ParamsFor<alias<u32>>(4)));
@@ -1125,11 +1193,14 @@ using InvalidVectorElementTypes = ResolverTestWithParam<Params>;
TEST_P(InvalidVectorElementTypes, InvalidElementType) {
// var a : vecN<EL_TY>;
auto& params = GetParam();
- Global("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
- ast::StorageClass::kPrivate);
+
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
+ ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: vector element type must be 'bool', 'f32', 'i32' "
+ "12:34 error: vector element type must be 'bool', 'f32', 'f16', 'i32' "
"or 'u32'");
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -1138,7 +1209,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
ParamsFor<vec3<i32>>(2),
ParamsFor<vec4<u32>>(2),
ParamsFor<mat2x2<f32>>(2),
- ParamsFor<mat3x3<f32>>(2),
+ ParamsFor<mat3x3<f16>>(2),
ParamsFor<mat4x4<f32>>(2),
ParamsFor<array<2, f32>>(2)));
} // namespace VectorTests
diff --git a/chromium/third_party/dawn/src/tint/resolver/uniformity.cc b/chromium/third_party/dawn/src/tint/resolver/uniformity.cc
index 97612a40100..e4c31c93949 100644
--- a/chromium/third_party/dawn/src/tint/resolver/uniformity.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/uniformity.cc
@@ -35,6 +35,7 @@
#include "src/tint/sem/type_constructor.h"
#include "src/tint/sem/type_conversion.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/sem/while_statement.h"
#include "src/tint/utils/block_allocator.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/unique_vector.h"
@@ -101,14 +102,14 @@ struct Node {
uint32_t arg_index;
/// The set of edges from this node to other nodes in the graph.
- utils::UniqueVector<Node*> edges;
+ utils::UniqueVector<Node*, 4> edges;
/// The node that this node was visited from, or nullptr if not visited.
Node* visited_from = nullptr;
/// Add an edge to the `to` node.
/// @param to the destination node
- void AddEdge(Node* to) { edges.add(to); }
+ void AddEdge(Node* to) { edges.Add(to); }
};
/// ParameterInfo holds information about the uniformity requirements and effects for a particular
@@ -151,8 +152,8 @@ struct FunctionInfo {
}
// Create nodes for parameters.
- parameters.resize(func->params.size());
- for (size_t i = 0; i < func->params.size(); i++) {
+ parameters.resize(func->params.Length());
+ for (size_t i = 0; i < func->params.Length(); i++) {
auto* param = func->params[i];
auto param_name = builder->Symbols().NameFor(param->symbol);
auto* sem = builder->Sem().Get<sem::Parameter>(param);
@@ -305,7 +306,7 @@ class UniformityGraph {
/// @param ast the optional AST node that this node corresponds to
/// @returns the new node
Node* CreateNode(std::string tag, const ast::Node* ast = nullptr) {
- return current_function_->CreateNode(tag, ast);
+ return current_function_->CreateNode(std::move(tag), ast);
}
/// Process a function.
@@ -336,21 +337,21 @@ class UniformityGraph {
// Look at which nodes are reachable from "RequiredToBeUniform".
{
- utils::UniqueVector<Node*> reachable;
+ utils::UniqueVector<Node*, 4> reachable;
Traverse(current_function_->required_to_be_uniform, &reachable);
- if (reachable.contains(current_function_->may_be_non_uniform)) {
+ if (reachable.Contains(current_function_->may_be_non_uniform)) {
MakeError(*current_function_, current_function_->may_be_non_uniform);
return false;
}
- if (reachable.contains(current_function_->cf_start)) {
+ if (reachable.Contains(current_function_->cf_start)) {
current_function_->callsite_tag = CallSiteRequiredToBeUniform;
}
// Set the parameter tag to ParameterRequiredToBeUniform for each parameter node that
// was reachable.
- for (size_t i = 0; i < func->params.size(); i++) {
+ for (size_t i = 0; i < func->params.Length(); i++) {
auto* param = func->params[i];
- if (reachable.contains(current_function_->variables.Get(sem_.Get(param)))) {
+ if (reachable.Contains(current_function_->variables.Get(sem_.Get(param)))) {
current_function_->parameters[i].tag = ParameterRequiredToBeUniform;
}
}
@@ -358,17 +359,17 @@ class UniformityGraph {
// Look at which nodes are reachable from "CF_return"
{
- utils::UniqueVector<Node*> reachable;
+ utils::UniqueVector<Node*, 4> reachable;
Traverse(current_function_->cf_return, &reachable);
- if (reachable.contains(current_function_->may_be_non_uniform)) {
+ if (reachable.Contains(current_function_->may_be_non_uniform)) {
current_function_->function_tag = SubsequentControlFlowMayBeNonUniform;
}
// Set the parameter tag to ParameterRequiredToBeUniformForSubsequentControlFlow for
// each parameter node that was reachable.
- for (size_t i = 0; i < func->params.size(); i++) {
+ for (size_t i = 0; i < func->params.Length(); i++) {
auto* param = func->params[i];
- if (reachable.contains(current_function_->variables.Get(sem_.Get(param)))) {
+ if (reachable.Contains(current_function_->variables.Get(sem_.Get(param)))) {
current_function_->parameters[i].tag =
ParameterRequiredToBeUniformForSubsequentControlFlow;
}
@@ -377,17 +378,17 @@ class UniformityGraph {
// If "Value_return" exists, look at which nodes are reachable from it
if (current_function_->value_return) {
- utils::UniqueVector<Node*> reachable;
+ utils::UniqueVector<Node*, 4> reachable;
Traverse(current_function_->value_return, &reachable);
- if (reachable.contains(current_function_->may_be_non_uniform)) {
+ if (reachable.Contains(current_function_->may_be_non_uniform)) {
current_function_->function_tag = ReturnValueMayBeNonUniform;
}
// Set the parameter tag to ParameterRequiredToBeUniformForReturnValue for each
// parameter node that was reachable.
- for (size_t i = 0; i < func->params.size(); i++) {
+ for (size_t i = 0; i < func->params.Length(); i++) {
auto* param = func->params[i];
- if (reachable.contains(current_function_->variables.Get(sem_.Get(param)))) {
+ if (reachable.Contains(current_function_->variables.Get(sem_.Get(param)))) {
current_function_->parameters[i].tag =
ParameterRequiredToBeUniformForReturnValue;
}
@@ -395,7 +396,7 @@ class UniformityGraph {
}
// Traverse the graph for each pointer parameter.
- for (size_t i = 0; i < func->params.size(); i++) {
+ for (size_t i = 0; i < func->params.Length(); i++) {
if (current_function_->parameters[i].pointer_return_value == nullptr) {
continue;
}
@@ -403,16 +404,16 @@ class UniformityGraph {
// Reset "visited" state for all nodes.
current_function_->ResetVisited();
- utils::UniqueVector<Node*> reachable;
+ utils::UniqueVector<Node*, 4> reachable;
Traverse(current_function_->parameters[i].pointer_return_value, &reachable);
- if (reachable.contains(current_function_->may_be_non_uniform)) {
+ if (reachable.Contains(current_function_->may_be_non_uniform)) {
current_function_->parameters[i].pointer_may_become_non_uniform = true;
}
// Check every other parameter to see if they feed into this parameter's final value.
- for (size_t j = 0; j < func->params.size(); j++) {
+ for (size_t j = 0; j < func->params.Length(); j++) {
auto* param_source = sem_.Get<sem::Parameter>(func->params[j]);
- if (reachable.contains(current_function_->parameters[j].init_value)) {
+ if (reachable.Contains(current_function_->parameters[j].init_value)) {
current_function_->parameters[i].pointer_param_output_sources.push_back(
param_source);
}
@@ -491,7 +492,7 @@ class UniformityGraph {
// Find the loop or switch statement that we are in.
auto* parent = sem_.Get(b)
->FindFirstParent<sem::SwitchStatement, sem::LoopStatement,
- sem::ForLoopStatement>();
+ sem::ForLoopStatement, sem::WhileStatement>();
TINT_ASSERT(Resolver, current_function_->loop_switch_infos.count(parent));
auto& info = current_function_->loop_switch_infos.at(parent);
@@ -535,8 +536,9 @@ class UniformityGraph {
[&](const ast::ContinueStatement* c) {
// Find the loop statement that we are in.
- auto* parent =
- sem_.Get(c)->FindFirstParent<sem::LoopStatement, sem::ForLoopStatement>();
+ auto* parent = sem_.Get(c)
+ ->FindFirstParent<sem::LoopStatement, sem::ForLoopStatement,
+ sem::WhileStatement>();
TINT_ASSERT(Resolver, current_function_->loop_switch_infos.count(parent));
auto& info = current_function_->loop_switch_infos.at(parent);
@@ -638,6 +640,68 @@ class UniformityGraph {
}
},
+ [&](const ast::WhileStatement* w) {
+ auto* sem_loop = sem_.Get(w);
+ auto* cfx = CreateNode("loop_start");
+
+ auto* cf_start = cf;
+
+ auto& info = current_function_->loop_switch_infos[sem_loop];
+ info.type = "whileloop";
+
+ // Create input nodes for any variables declared before this loop.
+ for (auto* v : current_function_->local_var_decls) {
+ auto name = builder_->Symbols().NameFor(v->Declaration()->symbol);
+ auto* in_node = CreateNode(name + "_value_forloop_in");
+ in_node->AddEdge(current_function_->variables.Get(v));
+ info.var_in_nodes[v] = in_node;
+ current_function_->variables.Set(v, in_node);
+ }
+
+ // Insert the condition at the start of the loop body.
+ {
+ auto [cf_cond, v] = ProcessExpression(cfx, w->condition);
+ auto* cf_condition_end = CreateNode("while_condition_CFend", w);
+ cf_condition_end->affects_control_flow = true;
+ cf_condition_end->AddEdge(v);
+ cf_start = cf_condition_end;
+ }
+
+ // Propagate assignments to the loop exit nodes.
+ for (auto* var : current_function_->local_var_decls) {
+ auto* exit_node = utils::GetOrCreate(info.var_exit_nodes, var, [&]() {
+ auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
+ return CreateNode(name + "_value_" + info.type + "_exit");
+ });
+ exit_node->AddEdge(current_function_->variables.Get(var));
+ }
+ auto* cf1 = ProcessStatement(cf_start, w->body);
+ cfx->AddEdge(cf1);
+ cfx->AddEdge(cf);
+
+ // Add edges from variable loop input nodes to their values at the end of the loop.
+ for (auto v : info.var_in_nodes) {
+ auto* in_node = v.second;
+ auto* out_node = current_function_->variables.Get(v.first);
+ if (out_node != in_node) {
+ in_node->AddEdge(out_node);
+ }
+ }
+
+ // Set each variable's exit node as its value in the outer scope.
+ for (auto v : info.var_exit_nodes) {
+ current_function_->variables.Set(v.first, v.second);
+ }
+
+ current_function_->loop_switch_infos.erase(sem_loop);
+
+ if (sem_loop->Behaviors() == sem::Behaviors{sem::Behavior::kNext}) {
+ return cf;
+ } else {
+ return cfx;
+ }
+ },
+
[&](const ast::IfStatement* i) {
auto* sem_if = sem_.Get(i);
auto [_, v_cond] = ProcessExpression(cf, i->condition);
@@ -783,6 +847,7 @@ class UniformityGraph {
return cfx;
}
},
+
[&](const ast::ReturnStatement* r) {
Node* cf_ret;
if (r->value) {
@@ -806,6 +871,7 @@ class UniformityGraph {
return cf_ret;
},
+
[&](const ast::SwitchStatement* s) {
auto* sem_switch = sem_.Get(s);
auto [cfx, v_cond] = ProcessExpression(cf, s->condition);
@@ -874,6 +940,7 @@ class UniformityGraph {
return cf_end ? cf_end : cf;
},
+
[&](const ast::VariableDeclStatement* decl) {
Node* node;
if (decl->variable->constructor) {
@@ -885,13 +952,18 @@ class UniformityGraph {
}
current_function_->variables.Set(sem_.Get(decl->variable), node);
- if (!decl->variable->is_const) {
+ if (decl->variable->Is<ast::Var>()) {
current_function_->local_var_decls.insert(
sem_.Get<sem::LocalVariable>(decl->variable));
}
return cf;
},
+
+ [&](const ast::StaticAssert*) {
+ return cf; // No impact on uniformity
+ },
+
[&](Default) {
TINT_ICE(Resolver, diagnostics_)
<< "unknown statement type: " << std::string(stmt->TypeInfo().name);
@@ -909,8 +981,8 @@ class UniformityGraph {
auto has_nonuniform_entry_point_attribute = [](auto* obj) {
// Only the num_workgroups and workgroup_id builtins are uniform.
if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(obj->attributes)) {
- if (builtin->builtin == ast::Builtin::kNumWorkgroups ||
- builtin->builtin == ast::Builtin::kWorkgroupId) {
+ if (builtin->builtin == ast::BuiltinValue::kNumWorkgroups ||
+ builtin->builtin == ast::BuiltinValue::kWorkgroupId) {
return false;
}
}
@@ -918,7 +990,7 @@ class UniformityGraph {
};
auto name = builder_->Symbols().NameFor(ident->symbol);
- auto* sem = sem_.Get<sem::VariableUser>(ident)->Variable();
+ auto* sem = sem_.Get(ident)->UnwrapMaterialize()->As<sem::VariableUser>()->Variable();
auto* node = CreateNode(name + "_ident_expr", ident);
return Switch(
sem,
@@ -954,7 +1026,8 @@ class UniformityGraph {
},
[&](const sem::GlobalVariable* global) {
- if (global->Declaration()->is_const || global->Access() == ast::Access::kRead) {
+ if (!global->Declaration()->Is<ast::Var>() ||
+ global->Access() == ast::Access::kRead) {
node->AddEdge(cf);
} else {
node->AddEdge(current_function_->may_be_non_uniform);
@@ -1139,7 +1212,7 @@ class UniformityGraph {
// Process call arguments
Node* cf_last_arg = cf;
std::vector<Node*> args;
- for (size_t i = 0; i < call->args.size(); i++) {
+ for (size_t i = 0; i < call->args.Length(); i++) {
auto [cf_i, arg_i] = ProcessExpression(cf_last_arg, call->args[i]);
// Capture the index of this argument in a new node.
@@ -1248,6 +1321,10 @@ class UniformityGraph {
if (func_info->parameters[i].pointer_may_become_non_uniform) {
ptr_result->AddEdge(current_function_->may_be_non_uniform);
} else {
+ // Add edge to the call to catch when it's called in non-uniform control
+ // flow.
+ ptr_result->AddEdge(call_node);
+
// Add edges from the resulting pointer value to any other arguments that
// feed it.
for (auto* source : func_info->parameters[i].pointer_param_output_sources) {
@@ -1279,7 +1356,7 @@ class UniformityGraph {
/// recording which node they were reached from.
/// @param source the starting node
/// @param reachable the set of reachable nodes to populate, if required
- void Traverse(Node* source, utils::UniqueVector<Node*>* reachable = nullptr) {
+ void Traverse(Node* source, utils::UniqueVector<Node*, 4>* reachable = nullptr) {
std::vector<Node*> to_visit{source};
while (!to_visit.empty()) {
@@ -1287,7 +1364,7 @@ class UniformityGraph {
to_visit.pop_back();
if (reachable) {
- reachable->add(node);
+ reachable->Add(node);
}
for (auto* to : node->edges) {
if (to->visited_from == nullptr) {
diff --git a/chromium/third_party/dawn/src/tint/resolver/uniformity_test.cc b/chromium/third_party/dawn/src/tint/resolver/uniformity_test.cc
index 7ed4a6b5c84..bbf7a4b712d 100644
--- a/chromium/third_party/dawn/src/tint/resolver/uniformity_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/uniformity_test.cc
@@ -84,7 +84,7 @@ class BasicTest : public UniformityAnalysisTestBase,
kTrue,
kFalse,
kLiteral,
- kModuleLet,
+ kModuleConst,
kPipelineOverridable,
kFuncLetUniformRhs,
kFuncVarUniform,
@@ -137,8 +137,8 @@ class BasicTest : public UniformityAnalysisTestBase,
return "false";
case kLiteral:
return "7 == 7";
- case kModuleLet:
- return "module_let == 0";
+ case kModuleConst:
+ return "module_const == 0";
case kPipelineOverridable:
return "pipeline_overridable == 0";
case kFuncLetUniformRhs:
@@ -231,7 +231,7 @@ class BasicTest : public UniformityAnalysisTestBase,
CASE(kTrue);
CASE(kFalse);
CASE(kLiteral);
- CASE(kModuleLet);
+ CASE(kModuleConst);
CASE(kPipelineOverridable);
CASE(kFuncLetUniformRhs);
CASE(kFuncVarUniform);
@@ -290,7 +290,7 @@ var<workgroup> w : i32;
@group(1) @binding(2) var s : sampler;
@group(1) @binding(3) var sc : sampler_comparison;
-let module_let : i32 = 42;
+const module_const : i32 = 42;
@id(42) override pipeline_overridable : i32;
fn user_no_restriction() {}
@@ -2311,6 +2311,304 @@ fn foo() {
RunTest(src, true);
}
+TEST_F(UniformityAnalysisTest, While_CallInside_UniformCondition) {
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read> n : i32;
+
+fn foo() {
+ var i = 0;
+ while (i < n) {
+ workgroupBarrier();
+ i = i + 1;
+ }
+}
+)";
+
+ RunTest(src, true);
+}
+
+TEST_F(UniformityAnalysisTest, While_CallInside_NonUniformCondition) {
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> n : i32;
+
+fn foo() {
+ var i = 0;
+ while (i < n) {
+ workgroupBarrier();
+ i = i + 1;
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:7:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:6:3 note: control flow depends on non-uniform value
+ while (i < n) {
+ ^^^^^
+
+test:6:14 note: reading from read_write storage buffer 'n' may result in a non-uniform value
+ while (i < n) {
+ ^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, While_VarBecomesNonUniformInLoopAfterBarrier) {
+ // Use a variable for a conditional barrier in a loop, and then assign a non-uniform value to
+ // that variable later in that loop.
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+fn foo() {
+ var v = 0;
+ var i = 0;
+ while (i < 10) {
+ if (v == 0) {
+ workgroupBarrier();
+ break;
+ }
+
+ v = non_uniform;
+ i++;
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:9:7 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:8:5 note: control flow depends on non-uniform value
+ if (v == 0) {
+ ^^
+
+test:13:9 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
+ v = non_uniform;
+ ^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, While_ConditionalAssignNonUniformWithBreak_BarrierInLoop) {
+ // In a conditional block, assign a non-uniform value and then break, then use a variable for a
+ // conditional barrier later in the loop.
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+fn foo() {
+ var v = 0;
+ var i = 0;
+ while (i < 10) {
+ if (true) {
+ v = non_uniform;
+ break;
+ }
+ if (v == 0) {
+ workgroupBarrier();
+ }
+ i++;
+ }
+}
+)";
+
+ RunTest(src, true);
+}
+
+TEST_F(UniformityAnalysisTest, While_ConditionalAssignNonUniformWithBreak_BarrierAfterLoop) {
+ // In a conditional block, assign a non-uniform value and then break, then use a variable for a
+ // conditional barrier after the loop.
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+fn foo() {
+ var v = 0;
+ var i = 0;
+ while (i < 10) {
+ if (true) {
+ v = non_uniform;
+ break;
+ }
+ v = 5;
+ i++;
+ }
+
+ if (v == 0) {
+ workgroupBarrier();
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:17:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:16:3 note: control flow depends on non-uniform value
+ if (v == 0) {
+ ^^
+
+test:9:11 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
+ v = non_uniform;
+ ^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, While_VarRemainsNonUniformAtLoopEnd_BarrierAfterLoop) {
+ // Assign a non-uniform value, assign a uniform value before all explicit break points but leave
+ // the value non-uniform at loop exit, then use a variable for a conditional barrier after the
+ // loop.
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+fn foo() {
+ var v = 0;
+ var i = 0;
+ while (i < 10) {
+ if (true) {
+ v = 5;
+ break;
+ }
+
+ v = non_uniform;
+
+ if (true) {
+ v = 6;
+ break;
+ }
+ i++;
+ }
+
+ if (v == 0) {
+ workgroupBarrier();
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:23:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:22:3 note: control flow depends on non-uniform value
+ if (v == 0) {
+ ^^
+
+test:13:9 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
+ v = non_uniform;
+ ^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, While_VarBecomesNonUniformBeforeConditionalContinue_BarrierAtStart) {
+ // Use a variable for a conditional barrier in a loop, assign a non-uniform value to
+ // that variable later in that loop, then perform a conditional continue before assigning a
+ // uniform value to that variable.
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+fn foo() {
+ var v = 0;
+ var i = 0;
+ while (i < 10) {
+ if (v == 0) {
+ workgroupBarrier();
+ break;
+ }
+
+ v = non_uniform;
+ if (true) {
+ continue;
+ }
+
+ v = 5;
+ i++;
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:9:7 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:8:5 note: control flow depends on non-uniform value
+ if (v == 0) {
+ ^^
+
+test:13:9 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
+ v = non_uniform;
+ ^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, While_VarBecomesNonUniformBeforeConditionalContinue) {
+ // Use a variable for a conditional barrier in a loop, assign a non-uniform value to
+ // that variable later in that loop, then perform a conditional continue before assigning a
+ // uniform value to that variable.
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+fn foo() {
+ var v = 0;
+ var i = 0;
+ while (i < 10) {
+ if (v == 0) {
+ workgroupBarrier();
+ break;
+ }
+
+ v = non_uniform;
+ if (true) {
+ continue;
+ }
+
+ v = 5;
+ i++;
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:9:7 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:8:5 note: control flow depends on non-uniform value
+ if (v == 0) {
+ ^^
+
+test:13:9 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
+ v = non_uniform;
+ ^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, While_NonUniformCondition_Reconverge) {
+ // Loops reconverge at exit, so test that we can call workgroupBarrier() after a loop that has a
+ // non-uniform condition.
+ std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> n : i32;
+
+fn foo() {
+ var i = 0;
+ while (i < n) {
+ }
+ workgroupBarrier();
+ i = i + 1;
+}
+)";
+
+ RunTest(src, true);
+}
+
} // namespace LoopTest
////////////////////////////////////////////////////////////////////////////////
@@ -3124,8 +3422,13 @@ fn foo() {
)";
RunTest(src, false);
- EXPECT_EQ(error_,
- R"(test:14:7 warning: 'workgroupBarrier' must only be called from uniform control flow
+ EXPECT_EQ(
+ error_,
+ R"(test:11:7 warning: use of deprecated language feature: fallthrough is set to be removed from WGSL. Case can accept multiple selectors if the existing case bodies are empty. default is not yet supported in a case selector list.
+ fallthrough;
+ ^^^^^^^^^^^
+
+test:14:7 warning: 'workgroupBarrier' must only be called from uniform control flow
workgroupBarrier();
^^^^^^^^^^^^^^^^
@@ -3189,8 +3492,13 @@ fn foo() {
)";
RunTest(src, false);
- EXPECT_EQ(error_,
- R"(test:14:9 warning: 'workgroupBarrier' must only be called from uniform control flow
+ EXPECT_EQ(
+ error_,
+ R"(test:10:7 warning: use of deprecated language feature: fallthrough is set to be removed from WGSL. Case can accept multiple selectors if the existing case bodies are empty. default is not yet supported in a case selector list.
+ fallthrough;
+ ^^^^^^^^^^^
+
+test:14:9 warning: 'workgroupBarrier' must only be called from uniform control flow
workgroupBarrier();
^^^^^^^^^^^^^^^^
@@ -3243,32 +3551,6 @@ test:6:11 note: reading from read_write storage buffer 'non_uniform' may result
)");
}
-TEST_F(UniformityAnalysisTest, Switch_VarBecomesUniformInDifferentCase_WithFallthrough) {
- std::string src = R"(
-@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
-@group(0) @binding(0) var<uniform> condition : i32;
-
-fn foo() {
- var x = non_uniform;
- switch (condition) {
- case 0: {
- x = 5;
- fallthrough;
- }
- case 42: {
- if (x == 0) {
- workgroupBarrier();
- }
- }
- default: {
- }
- }
-}
-)";
-
- RunTest(src, true);
-}
-
TEST_F(UniformityAnalysisTest, Switch_VarBecomesNonUniformInCase_BarrierAfter) {
std::string src = R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@@ -4624,6 +4906,145 @@ test:12:11 note: reading from read_write storage buffer 'non_uniform' may result
)");
}
+TEST_F(UniformityAnalysisTest, PointerParamModifiedInNonUniformControlFlow) {
+ std::string src = R"(
+@binding(0) @group(0) var<storage, read_write> non_uniform_global : i32;
+
+fn foo(p : ptr<function, i32>) {
+ *p = 42;
+}
+
+@compute @workgroup_size(64)
+fn main() {
+ var a : i32;
+ if (non_uniform_global == 0) {
+ foo(&a);
+ }
+
+ if (a == 0) {
+ workgroupBarrier();
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:16:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:11:3 note: control flow depends on non-uniform value
+ if (non_uniform_global == 0) {
+ ^^
+
+test:11:7 note: reading from read_write storage buffer 'non_uniform_global' may result in a non-uniform value
+ if (non_uniform_global == 0) {
+ ^^^^^^^^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, PointerParamAssumedModifiedInNonUniformControlFlow) {
+ std::string src = R"(
+@binding(0) @group(0) var<storage, read_write> non_uniform_global : i32;
+
+fn foo(p : ptr<function, i32>) {
+ // Do not modify 'p', uniformity analysis presently assumes it will be.
+}
+
+@compute @workgroup_size(64)
+fn main() {
+ var a : i32;
+ if (non_uniform_global == 0) {
+ foo(&a);
+ }
+
+ if (a == 0) {
+ workgroupBarrier();
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:16:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:11:3 note: control flow depends on non-uniform value
+ if (non_uniform_global == 0) {
+ ^^
+
+test:11:7 note: reading from read_write storage buffer 'non_uniform_global' may result in a non-uniform value
+ if (non_uniform_global == 0) {
+ ^^^^^^^^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, PointerParamModifiedInNonUniformControlFlow_NestedCall) {
+ std::string src = R"(
+@binding(0) @group(0) var<storage, read_write> non_uniform_global : i32;
+
+fn foo2(p : ptr<function, i32>) {
+ *p = 42;
+}
+
+fn foo(p : ptr<function, i32>) {
+ foo2(p);
+}
+
+@compute @workgroup_size(64)
+fn main() {
+ var a : i32;
+ if (non_uniform_global == 0) {
+ foo(&a);
+ }
+
+ if (a == 0) {
+ workgroupBarrier();
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:20:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:15:3 note: control flow depends on non-uniform value
+ if (non_uniform_global == 0) {
+ ^^
+
+test:15:7 note: reading from read_write storage buffer 'non_uniform_global' may result in a non-uniform value
+ if (non_uniform_global == 0) {
+ ^^^^^^^^^^^^^^^^^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, PointerParamModifiedInUniformControlFlow) {
+ std::string src = R"(
+@binding(0) @group(0) var<uniform> uniform_global : i32;
+
+fn foo(p : ptr<function, i32>) {
+ *p = 42;
+}
+
+@compute @workgroup_size(64)
+fn main() {
+ var a : i32;
+ if (uniform_global == 0) {
+ foo(&a);
+ }
+
+ if (a == 0) {
+ workgroupBarrier();
+ }
+}
+)";
+
+ RunTest(src, true);
+}
+
TEST_F(UniformityAnalysisTest, NonUniformPointerParameterBecomesUniform_AfterUse) {
std::string src = R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@@ -4862,18 +5283,18 @@ TEST_F(UniformityAnalysisTest, MaximumNumberOfPointerParameters) {
// ...
// *p254 = rhs;
// }
- ast::VariableList params;
- ast::StatementList foo_body;
+ utils::Vector<const ast::Parameter*, 8> params;
+ utils::Vector<const ast::Statement*, 8> foo_body;
const ast::Expression* rhs_init = b.Deref("p0");
for (int i = 1; i < 255; i++) {
rhs_init = b.Add(rhs_init, b.Deref("p" + std::to_string(i)));
}
- foo_body.push_back(b.Decl(b.Let("rhs", nullptr, rhs_init)));
+ foo_body.Push(b.Decl(b.Let("rhs", nullptr, rhs_init)));
for (int i = 0; i < 255; i++) {
- params.push_back(
+ params.Push(
b.Param("p" + std::to_string(i), ty.pointer(ty.i32(), ast::StorageClass::kFunction)));
if (i > 0) {
- foo_body.push_back(b.Assign(b.Deref("p" + std::to_string(i)), "rhs"));
+ foo_body.Push(b.Assign(b.Deref("p" + std::to_string(i)), "rhs"));
}
}
b.Func("foo", std::move(params), ty.void_(), foo_body);
@@ -4890,19 +5311,18 @@ TEST_F(UniformityAnalysisTest, MaximumNumberOfPointerParameters) {
// workgroupBarrier();
// }
// }
- b.Global("non_uniform_global", ty.i32(), ast::StorageClass::kPrivate);
- ast::StatementList main_body;
- ast::ExpressionList args;
+ b.GlobalVar("non_uniform_global", ty.i32(), ast::StorageClass::kPrivate);
+ utils::Vector<const ast::Statement*, 8> main_body;
+ utils::Vector<const ast::Expression*, 8> args;
for (int i = 0; i < 255; i++) {
auto name = "v" + std::to_string(i);
- main_body.push_back(b.Decl(b.Var(name, ty.i32())));
- args.push_back(b.AddressOf(name));
+ main_body.Push(b.Decl(b.Var(name, ty.i32())));
+ args.Push(b.AddressOf(name));
}
- main_body.push_back(b.Assign("v0", "non_uniform_global"));
- main_body.push_back(b.CallStmt(b.create<ast::CallExpression>(b.Expr("foo"), args)));
- main_body.push_back(
- b.If(b.Equal("v254", 0_i), b.Block(b.CallStmt(b.Call("workgroupBarrier")))));
- b.Func("main", {}, ty.void_(), main_body);
+ main_body.Push(b.Assign("v0", "non_uniform_global"));
+ main_body.Push(b.CallStmt(b.create<ast::CallExpression>(b.Expr("foo"), args)));
+ main_body.Push(b.If(b.Equal("v254", 0_i), b.Block(b.CallStmt(b.Call("workgroupBarrier")))));
+ b.Func("main", utils::Empty, ty.void_(), main_body);
// TODO(jrprice): Expect false when uniformity issues become errors.
EXPECT_TRUE(RunTest(std::move(b))) << error_;
@@ -6101,16 +6521,16 @@ TEST_F(UniformityAnalysisTest, StressGraphTraversalDepth) {
// workgroupBarrier();
// }
// }
- b.Global("v0", ty.i32(), ast::StorageClass::kPrivate, b.Expr(0_i));
- ast::StatementList foo_body;
+ b.GlobalVar("v0", ty.i32(), ast::StorageClass::kPrivate, b.Expr(0_i));
+ utils::Vector<const ast::Statement*, 8> foo_body;
std::string v_last = "v0";
for (int i = 1; i < 100000; i++) {
auto v = "v" + std::to_string(i);
- foo_body.push_back(b.Decl(b.Var(v, nullptr, b.Expr(v_last))));
+ foo_body.Push(b.Decl(b.Var(v, nullptr, b.Expr(v_last))));
v_last = v;
}
- foo_body.push_back(b.If(b.Equal(v_last, 0_i), b.Block(b.CallStmt(b.Call("workgroupBarrier")))));
- b.Func("foo", {}, ty.void_(), foo_body);
+ foo_body.Push(b.If(b.Equal(v_last, 0_i), b.Block(b.CallStmt(b.Call("workgroupBarrier")))));
+ b.Func("foo", utils::Empty, ty.void_(), foo_body);
// TODO(jrprice): Expect false when uniformity issues become errors.
EXPECT_TRUE(RunTest(std::move(b))) << error_;
diff --git a/chromium/third_party/dawn/src/tint/resolver/validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/validation_test.cc
index 4fe5b2bfe3b..52d4c876b15 100644
--- a/chromium/third_party/dawn/src/tint/resolver/validation_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/validation_test.cc
@@ -50,24 +50,32 @@ using ResolverValidationTest = ResolverTest;
class FakeStmt final : public Castable<FakeStmt, ast::Statement> {
public:
- FakeStmt(ProgramID pid, Source src) : Base(pid, src) {}
+ FakeStmt(ProgramID pid, ast::NodeID nid, Source src) : Base(pid, nid, src) {}
FakeStmt* Clone(CloneContext*) const override { return nullptr; }
};
class FakeExpr final : public Castable<FakeExpr, ast::Expression> {
public:
- FakeExpr(ProgramID pid, Source src) : Base(pid, src) {}
+ FakeExpr(ProgramID pid, ast::NodeID nid, Source src) : Base(pid, nid, src) {}
FakeExpr* Clone(CloneContext*) const override { return nullptr; }
};
TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInVertexStage) {
- Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
- Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
- Func(Source{{9, 10}}, "f0", ast::VariableList{}, ty.vec4<f32>(), {stmt, Return(Expr("dst"))},
- ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
- ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+ Func(Source{{9, 10}}, "f0", utils::Empty, ty.vec4<f32>(),
+ utils::Vector{
+ stmt,
+ Return(Expr("dst")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -85,14 +93,19 @@ TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInFragmentStage) {
// f1();
//}
- Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
- Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
- Func(Source{{5, 6}}, "f2", {}, ty.void_(), {stmt});
- Func(Source{{7, 8}}, "f1", {}, ty.void_(), {CallStmt(Call("f2"))});
- Func(Source{{9, 10}}, "f0", {}, ty.void_(), {CallStmt(Call("f1"))},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ Func(Source{{5, 6}}, "f2", utils::Empty, ty.void_(), utils::Vector{stmt});
+ Func(Source{{7, 8}}, "f1", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("f2")),
+ });
+ Func(Source{{9, 10}}, "f0", utils::Empty, ty.void_(), utils::Vector{CallStmt(Call("f1"))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -145,7 +158,7 @@ TEST_F(ResolverValidationTest, Expr_ErrUnknownExprType) {
}
TEST_F(ResolverValidationTest, Expr_DontCall_Function) {
- Func("func", {}, ty.void_(), {}, {});
+ Func("func", utils::Empty, ty.void_(), utils::Empty, {});
WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "func"));
EXPECT_FALSE(r()->Resolve());
@@ -213,10 +226,10 @@ TEST_F(ResolverValidationTest, UsingUndefinedVariableGlobalVariable_Pass) {
// return;
// }
- Global("global_var", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
+ GlobalVar("global_var", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Expr(Source{{12, 34}}, "global_var"), 3.14_f),
Return(),
});
@@ -289,32 +302,38 @@ TEST_F(ResolverValidationTest, UsingUndefinedVariableDifferentScope_Fail) {
TEST_F(ResolverValidationTest, StorageClass_FunctionVariableWorkgroupClass) {
auto* var = Var("var", ty.i32(), ast::StorageClass::kWorkgroup);
- auto* stmt = Decl(var);
- Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(var),
+ });
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: function variable has a non-function storage class");
+ EXPECT_EQ(r()->error(),
+ "error: function-scope 'var' declaration must use 'function' storage class");
}
TEST_F(ResolverValidationTest, StorageClass_FunctionVariableI32) {
auto* var = Var("s", ty.i32(), ast::StorageClass::kPrivate);
- auto* stmt = Decl(var);
- Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(var),
+ });
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: function variable has a non-function storage class");
+ EXPECT_EQ(r()->error(),
+ "error: function-scope 'var' declaration must use 'function' storage class");
}
TEST_F(ResolverValidationTest, StorageClass_SamplerExplicitStorageClass) {
auto* t = ty.sampler(ast::SamplerKind::kSampler);
- Global(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
EXPECT_FALSE(r()->Resolve());
@@ -324,11 +343,11 @@ TEST_F(ResolverValidationTest, StorageClass_SamplerExplicitStorageClass) {
TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
- Global(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
EXPECT_FALSE(r()->Resolve()) << r()->error();
@@ -337,7 +356,7 @@ TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
}
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
- Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "xyqz");
@@ -349,7 +368,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
}
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
- Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "rgyw");
@@ -362,7 +381,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
}
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
- Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* ident = Expr(Source{{{3, 3}, {3, 8}}}, "zzzzz");
auto* mem = MemberAccessor("my_vec", ident);
@@ -373,7 +392,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
}
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
- Global("my_vec", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec2<f32>(), ast::StorageClass::kPrivate);
auto* ident = Expr(Source{{3, 3}}, "z");
auto* mem = MemberAccessor("my_vec", ident);
@@ -411,7 +430,11 @@ TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncGoodParent) {
auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
auto* accessor_expr = MemberAccessor(star_p, z);
auto* x = Var("x", ty.f32(), accessor_expr);
- Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
+ Func("func", utils::Vector{p}, ty.f32(),
+ utils::Vector{
+ Decl(x),
+ Return(x),
+ });
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -425,7 +448,11 @@ TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncBadParent) {
auto* accessor_expr = MemberAccessor(p, z);
auto* star_p = Deref(accessor_expr);
auto* x = Var("x", ty.f32(), star_p);
- Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
+ Func("func", utils::Vector{p}, ty.f32(),
+ utils::Vector{
+ Decl(x),
+ Return(x),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
@@ -792,8 +819,14 @@ TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Indirect_ViaCall) {
// }
// }
- Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
- Func("SomeFunc", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
+ Func("MayDiscard", utils::Empty, ty.void_(),
+ utils::Vector{
+ If(true, Block(Discard())),
+ });
+ Func("SomeFunc", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("MayDiscard")),
+ });
WrapInFunction(Loop( // outer loop
Block(), // outer loop block
@@ -912,8 +945,14 @@ TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Indirect_ViaCall) {
// break;
// }
- Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
- Func("F", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
+ Func("MayDiscard", utils::Empty, ty.void_(),
+ utils::Vector{
+ If(true, Block(Discard())),
+ });
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("MayDiscard")),
+ });
WrapInFunction(For(nullptr, nullptr,
Loop(Source{{56, 78}}, //
@@ -972,6 +1011,26 @@ TEST_F(ResolverTest, Stmt_ForLoop_CondIsNotBool) {
EXPECT_EQ(r()->error(), "12:34 error: for-loop condition must be bool, got f32");
}
+TEST_F(ResolverTest, Stmt_While_CondIsBoolRef) {
+ // var cond : bool = false;
+ // while (cond) {
+ // }
+
+ auto* cond = Var("cond", ty.bool_(), Expr(false));
+ WrapInFunction(Decl(cond), While("cond", Block()));
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, Stmt_While_CondIsNotBool) {
+ // while (1.0f) {
+ // }
+
+ WrapInFunction(While(Expr(Source{{12, 34}}, 1_f), Block()));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: while condition must be bool, got f32");
+}
+
TEST_F(ResolverValidationTest, Stmt_ContinueInLoop) {
WrapInFunction(Loop(Block(If(false, Block(Break())), //
Continue(Source{{12, 34}}))));
@@ -1157,30 +1216,40 @@ TEST_F(ResolverValidationTest, Stmt_BreakNotInLoopOrSwitch) {
}
TEST_F(ResolverValidationTest, StructMemberDuplicateName) {
- Structure("S",
- {Member(Source{{12, 34}}, "a", ty.i32()), Member(Source{{56, 78}}, "a", ty.i32())});
+ Structure("S", utils::Vector{
+ Member(Source{{12, 34}}, "a", ty.i32()),
+ Member(Source{{56, 78}}, "a", ty.i32()),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"56:78 error: redefinition of 'a'\n12:34 note: previous definition "
"is here");
}
TEST_F(ResolverValidationTest, StructMemberDuplicateNameDifferentTypes) {
- Structure("S", {Member(Source{{12, 34}}, "a", ty.bool_()),
- Member(Source{{12, 34}}, "a", ty.vec3<f32>())});
+ Structure("S", utils::Vector{
+ Member(Source{{12, 34}}, "a", ty.bool_()),
+ Member(Source{{12, 34}}, "a", ty.vec3<f32>()),
+ });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: redefinition of 'a'\n12:34 note: previous definition "
"is here");
}
TEST_F(ResolverValidationTest, StructMemberDuplicateNamePass) {
- Structure("S", {Member("a", ty.i32()), Member("b", ty.f32())});
- Structure("S1", {Member("a", ty.i32()), Member("b", ty.f32())});
+ Structure("S", utils::Vector{
+ Member("a", ty.i32()),
+ Member("b", ty.f32()),
+ });
+ Structure("S1", utils::Vector{
+ Member("a", ty.i32()),
+ Member("b", ty.f32()),
+ });
EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
- Structure("S", {
- Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 3)}),
+ Structure("S", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 3)}),
});
EXPECT_FALSE(r()->Resolve());
@@ -1188,8 +1257,8 @@ TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
}
TEST_F(ResolverValidationTest, ZeroStructMemberAlignAttribute) {
- Structure("S", {
- Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 0)}),
+ Structure("S", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 0)}),
});
EXPECT_FALSE(r()->Resolve());
@@ -1197,8 +1266,8 @@ TEST_F(ResolverValidationTest, ZeroStructMemberAlignAttribute) {
}
TEST_F(ResolverValidationTest, ZeroStructMemberSizeAttribute) {
- Structure("S", {
- Member("a", ty.f32(), {MemberSize(Source{{12, 34}}, 0)}),
+ Structure("S", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberSize(Source{{12, 34}}, 0)}),
});
EXPECT_FALSE(r()->Resolve());
@@ -1206,8 +1275,9 @@ TEST_F(ResolverValidationTest, ZeroStructMemberSizeAttribute) {
}
TEST_F(ResolverValidationTest, OffsetAndSizeAttribute) {
- Structure("S", {
- Member(Source{{12, 34}}, "a", ty.f32(), {MemberOffset(0), MemberSize(4)}),
+ Structure("S", utils::Vector{
+ Member(Source{{12, 34}}, "a", ty.f32(),
+ utils::Vector{MemberOffset(0), MemberSize(4)}),
});
EXPECT_FALSE(r()->Resolve());
@@ -1217,8 +1287,9 @@ TEST_F(ResolverValidationTest, OffsetAndSizeAttribute) {
}
TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) {
- Structure("S", {
- Member(Source{{12, 34}}, "a", ty.f32(), {MemberOffset(0), MemberAlign(4)}),
+ Structure("S", utils::Vector{
+ Member(Source{{12, 34}}, "a", ty.f32(),
+ utils::Vector{MemberOffset(0), MemberAlign(4)}),
});
EXPECT_FALSE(r()->Resolve());
@@ -1228,9 +1299,9 @@ TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) {
}
TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeAttribute) {
- Structure("S", {
+ Structure("S", utils::Vector{
Member(Source{{12, 34}}, "a", ty.f32(),
- {MemberOffset(0), MemberAlign(4), MemberSize(4)}),
+ utils::Vector{MemberOffset(0), MemberAlign(4), MemberSize(4)}),
});
EXPECT_FALSE(r()->Resolve());
diff --git a/chromium/third_party/dawn/src/tint/resolver/validator.cc b/chromium/third_party/dawn/src/tint/resolver/validator.cc
index 2b4d8a99d3d..6382d34d932 100644
--- a/chromium/third_party/dawn/src/tint/resolver/validator.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/validator.cc
@@ -72,11 +72,13 @@
#include "src/tint/sem/type_constructor.h"
#include "src/tint/sem/type_conversion.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/sem/while_statement.h"
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/math.h"
#include "src/tint/utils/reverse.h"
#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/string.h"
#include "src/tint/utils/transform.h"
namespace tint::resolver {
@@ -139,7 +141,7 @@ void TraverseCallChain(diag::List& diagnostics,
callback(f);
return;
}
- if (f->TransitivelyCalledFunctions().contains(to)) {
+ if (f->TransitivelyCalledFunctions().Contains(to)) {
TraverseCallChain(diagnostics, f, to, callback);
callback(f);
return;
@@ -237,6 +239,11 @@ const ast::Statement* Validator::ClosestContinuing(bool stop_at_loop,
break;
}
}
+ if (Is<sem::WhileStatement>(s->Parent())) {
+ if (stop_at_loop) {
+ break;
+ }
+ }
}
return nullptr;
}
@@ -278,35 +285,58 @@ bool Validator::StorageTexture(const ast::StorageTexture* t) const {
return true;
}
-bool Validator::Materialize(const sem::Materialize* m) const {
- auto* from = m->Expr()->Type();
- auto* to = m->Type();
+bool Validator::SampledTexture(const sem::SampledTexture* t, const Source& source) const {
+ if (!t->type()->UnwrapRef()->is_numeric_scalar()) {
+ AddError("texture_2d<type>: type must be f32, i32 or u32", source);
+ return false;
+ }
+
+ return true;
+}
+
+bool Validator::MultisampledTexture(const sem::MultisampledTexture* t, const Source& source) const {
+ if (t->dim() != ast::TextureDimension::k2d) {
+ AddError("only 2d multisampled textures are supported", source);
+ return false;
+ }
+
+ if (!t->type()->UnwrapRef()->is_numeric_scalar()) {
+ AddError("texture_multisampled_2d<type>: type must be f32, i32 or u32", source);
+ return false;
+ }
+
+ return true;
+}
+bool Validator::Materialize(const sem::Type* to,
+ const sem::Type* from,
+ const Source& source) const {
if (sem::Type::ConversionRank(from, to) == sem::Type::kNoConversion) {
AddError("cannot convert value of type '" + sem_.TypeNameOf(from) + "' to type '" +
sem_.TypeNameOf(to) + "'",
- m->Expr()->Declaration()->source);
+ source);
return false;
}
return true;
}
-bool Validator::VariableConstructorOrCast(const ast::Variable* var,
- ast::StorageClass storage_class,
- const sem::Type* storage_ty,
- const sem::Type* rhs_ty) const {
- auto* value_type = rhs_ty->UnwrapRef(); // Implicit load of RHS
+bool Validator::VariableInitializer(const ast::Variable* v,
+ ast::StorageClass storage_class,
+ const sem::Type* storage_ty,
+ const sem::Expression* initializer) const {
+ auto* initializer_ty = initializer->Type();
+ auto* value_type = initializer_ty->UnwrapRef(); // Implicit load of RHS
// Value type has to match storage type
if (storage_ty != value_type) {
- std::string decl = var->is_const ? "let" : "var";
- AddError("cannot initialize " + decl + " of type '" + sem_.TypeNameOf(storage_ty) +
- "' with value of type '" + sem_.TypeNameOf(rhs_ty) + "'",
- var->source);
+ std::stringstream s;
+ s << "cannot initialize " << v->Kind() << " of type '" << sem_.TypeNameOf(storage_ty)
+ << "' with value of type '" << sem_.TypeNameOf(initializer_ty) << "'";
+ AddError(s.str(), v->source);
return false;
}
- if (!var->is_const) {
+ if (v->Is<ast::Var>()) {
switch (storage_class) {
case ast::StorageClass::kPrivate:
case ast::StorageClass::kFunction:
@@ -315,11 +345,11 @@ bool Validator::VariableConstructorOrCast(const ast::Variable* var,
// https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
// Optionally has an initializer expression, if the variable is in the
// private or function storage classes.
- AddError("var of storage class '" + std::string(ast::ToString(storage_class)) +
+ AddError("var of storage class '" + utils::ToString(storage_class) +
"' cannot have an initializer. var initializers are only "
"supported for the storage classes "
"'private' and 'function'",
- var->source);
+ v->source);
return false;
}
}
@@ -363,6 +393,16 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
return true;
}
+ // Temporally forbid using f16 types in "uniform" and "storage" storage class.
+ // TODO(tint:1473, tint:1502): Remove this error after f16 is supported in "uniform" and
+ // "storage" storage class but keep for "push_constant" storage class.
+ if (Is<sem::F16>(sem::Type::DeepestElementOf(store_ty))) {
+ AddError(
+ "using f16 types in '" + utils::ToString(sc) + "' storage class is not implemented yet",
+ source);
+ return false;
+ }
+
if (auto* str = store_ty->As<sem::Struct>()) {
for (size_t i = 0; i < str->Members().size(); ++i) {
auto* const m = str->Members()[i];
@@ -379,7 +419,7 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
if (m->Offset() % required_align != 0) {
AddError("the offset of a struct member of type '" +
m->Type()->UnwrapRef()->FriendlyName(symbols_) +
- "' in storage class '" + ast::ToString(sc) +
+ "' in storage class '" + utils::ToString(sc) +
"' must be a multiple of " + std::to_string(required_align) +
" bytes, but '" + member_name_of(m) + "' is currently at offset " +
std::to_string(m->Offset()) + ". Consider setting @align(" +
@@ -476,7 +516,19 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
}
bool Validator::StorageClassLayout(const sem::Variable* var,
+ const ast::Extensions& enabled_extensions,
ValidTypeStorageLayouts& layouts) const {
+ if (var->StorageClass() == ast::StorageClass::kPushConstant &&
+ !enabled_extensions.Contains(ast::Extension::kChromiumExperimentalPushConstant) &&
+ IsValidationEnabled(var->Declaration()->attributes,
+ ast::DisabledValidation::kIgnoreStorageClass)) {
+ AddError(
+ "use of variable storage class 'push_constant' requires enabling extension "
+ "'chromium_experimental_push_constant'",
+ var->Declaration()->source);
+ return false;
+ }
+
if (auto* str = var->Type()->UnwrapRef()->As<sem::Struct>()) {
if (!StorageClassLayout(str, var->StorageClass(), str->Declaration()->source, layouts)) {
AddNote("see declaration of variable", var->Declaration()->source);
@@ -495,63 +547,125 @@ bool Validator::StorageClassLayout(const sem::Variable* var,
return true;
}
+bool Validator::LocalVariable(const sem::Variable* v) const {
+ auto* decl = v->Declaration();
+ return Switch(
+ decl, //
+ [&](const ast::Var* var) {
+ if (IsValidationEnabled(var->attributes,
+ ast::DisabledValidation::kIgnoreStorageClass)) {
+ if (!v->Type()->UnwrapRef()->IsConstructible()) {
+ AddError("function-scope 'var' must have a constructible type",
+ var->type ? var->type->source : var->source);
+ return false;
+ }
+ }
+ return Var(v);
+ }, //
+ [&](const ast::Let*) { return Let(v); }, //
+ [&](const ast::Const*) { return true; }, //
+ [&](Default) {
+ TINT_ICE(Resolver, diagnostics_)
+ << "Validator::Variable() called with a unknown variable type: "
+ << decl->TypeInfo().name;
+ return false;
+ });
+}
+
bool Validator::GlobalVariable(
- const sem::Variable* var,
- std::unordered_map<uint32_t, const sem::Variable*> constant_ids,
- std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const {
- auto* decl = var->Declaration();
- if (!NoDuplicateAttributes(decl->attributes)) {
- return false;
- }
+ const sem::GlobalVariable* global,
+ const std::unordered_map<OverrideId, const sem::Variable*>& override_ids,
+ const std::unordered_map<const sem::Type*, const Source&>& atomic_composite_info) const {
+ auto* decl = global->Declaration();
+ bool ok = Switch(
+ decl, //
+ [&](const ast::Var* var) {
+ if (auto* init = global->Constructor();
+ init && init->Stage() > sem::EvaluationStage::kOverride) {
+ AddError("module-scope 'var' initializer must be a constant or override expression",
+ init->Declaration()->source);
+ return false;
+ }
- for (auto* attr : decl->attributes) {
- if (decl->is_const) {
- if (auto* id_attr = attr->As<ast::IdAttribute>()) {
- uint32_t id = id_attr->value;
- auto it = constant_ids.find(id);
- if (it != constant_ids.end() && it->second != var) {
- AddError("pipeline constant IDs must be unique", attr->source);
- AddNote(
- "a pipeline constant with an ID of " + std::to_string(id) +
- " was previously declared "
- "here:",
- ast::GetAttribute<ast::IdAttribute>(it->second->Declaration()->attributes)
- ->source);
+ if (global->StorageClass() == ast::StorageClass::kNone) {
+ AddError("module-scope 'var' declaration must have a storage class", decl->source);
+ return false;
+ }
+
+ for (auto* attr : decl->attributes) {
+ bool is_shader_io_attribute =
+ attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
+ ast::InvariantAttribute, ast::LocationAttribute>();
+ bool has_io_storage_class = global->StorageClass() == ast::StorageClass::kIn ||
+ global->StorageClass() == ast::StorageClass::kOut;
+ if (!attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
+ ast::InternalAttribute>() &&
+ (!is_shader_io_attribute || !has_io_storage_class)) {
+ AddError("attribute is not valid for module-scope 'var'", attr->source);
return false;
}
- if (id > 65535) {
- AddError("pipeline constant IDs must be between 0 and 65535", attr->source);
+ }
+
+ // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
+ // The access mode always has a default, and except for variables in the
+ // storage storage class, must not be written.
+ if (var->declared_access != ast::Access::kUndefined) {
+ if (global->StorageClass() == ast::StorageClass::kStorage) {
+ // The access mode for the storage address space can only be 'read' or
+ // 'read_write'.
+ if (var->declared_access == ast::Access::kWrite) {
+ AddError("access mode 'write' is not valid for the 'storage' address space",
+ decl->source);
+ return false;
+ }
+ } else {
+ AddError("only variables in <storage> storage class may declare an access mode",
+ decl->source);
return false;
}
- } else {
- AddError("attribute is not valid for constants", attr->source);
+ }
+
+ if (!AtomicVariable(global, atomic_composite_info)) {
return false;
}
- } else {
- bool is_shader_io_attribute =
- attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
- ast::InvariantAttribute, ast::LocationAttribute>();
- bool has_io_storage_class = var->StorageClass() == ast::StorageClass::kInput ||
- var->StorageClass() == ast::StorageClass::kOutput;
- if (!(attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
- ast::InternalAttribute>()) &&
- (!is_shader_io_attribute || !has_io_storage_class)) {
- AddError("attribute is not valid for variables", attr->source);
+
+ auto name = symbols_.NameFor(var->symbol);
+ if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
+ AddError(
+ "'" + name + "' is a builtin and cannot be redeclared as a module-scope 'var'",
+ var->source);
return false;
}
- }
+
+ return Var(global);
+ },
+ [&](const ast::Override*) { return Override(global, override_ids); },
+ [&](const ast::Const*) {
+ if (!decl->attributes.IsEmpty()) {
+ AddError("attribute is not valid for module-scope 'const' declaration",
+ decl->attributes[0]->source);
+ return false;
+ }
+ return Const(global);
+ },
+ [&](Default) {
+ TINT_ICE(Resolver, diagnostics_)
+ << "Validator::GlobalVariable() called with a unknown variable type: "
+ << decl->TypeInfo().name;
+ return false;
+ });
+
+ if (!ok) {
+ return false;
}
- if (var->StorageClass() == ast::StorageClass::kFunction) {
- AddError(
- "variables declared at module scope must not be in the function "
- "storage class",
- decl->source);
+ if (global->StorageClass() == ast::StorageClass::kFunction) {
+ AddError("module-scope 'var' must not use storage class 'function'", decl->source);
return false;
}
auto binding_point = decl->BindingPoint();
- switch (var->StorageClass()) {
+ switch (global->StorageClass()) {
case ast::StorageClass::kUniform:
case ast::StorageClass::kStorage:
case ast::StorageClass::kHandle: {
@@ -559,10 +673,7 @@ bool Validator::GlobalVariable(
// Each resource variable must be declared with both group and binding
// attributes.
if (!binding_point) {
- AddError(
- "resource variables require @group and @binding "
- "attributes",
- decl->source);
+ AddError("resource variables require @group and @binding attributes", decl->source);
return false;
}
break;
@@ -571,31 +682,13 @@ bool Validator::GlobalVariable(
if (binding_point.binding || binding_point.group) {
// https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
// Must only be applied to a resource variable
- AddError(
- "non-resource variables must not have @group or @binding "
- "attributes",
- decl->source);
+ AddError("non-resource variables must not have @group or @binding attributes",
+ decl->source);
return false;
}
}
- // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
- // The access mode always has a default, and except for variables in the
- // storage storage class, must not be written.
- if (var->StorageClass() != ast::StorageClass::kStorage &&
- decl->declared_access != ast::Access::kUndefined) {
- AddError("only variables in <storage> storage class may declare an access mode",
- decl->source);
- return false;
- }
-
- if (!decl->is_const) {
- if (!AtomicVariable(var, atomic_composite_info)) {
- return false;
- }
- }
-
- return Variable(var);
+ return true;
}
// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
@@ -639,102 +732,135 @@ bool Validator::AtomicVariable(
return true;
}
-bool Validator::Variable(const sem::Variable* var) const {
- auto* decl = var->Declaration();
- auto* storage_ty = var->Type()->UnwrapRef();
+bool Validator::Var(const sem::Variable* v) const {
+ auto* var = v->Declaration()->As<ast::Var>();
+ auto* storage_ty = v->Type()->UnwrapRef();
- if (var->Is<sem::GlobalVariable>()) {
- auto name = symbols_.NameFor(decl->symbol);
- if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
- auto* kind = var->Declaration()->is_const ? "let" : "var";
- AddError(
- "'" + name + "' is a builtin and cannot be redeclared as a module-scope " + kind,
- decl->source);
- return false;
- }
+ if (!IsStorable(storage_ty)) {
+ AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a var", var->source);
+ return false;
}
- if (!decl->is_const && !IsStorable(storage_ty)) {
- AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a var",
- decl->source);
+ if (storage_ty->is_handle() && var->declared_storage_class != ast::StorageClass::kNone) {
+ // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
+ // If the store type is a texture type or a sampler type, then the
+ // variable declaration must not have a storage class attribute. The
+ // storage class will always be handle.
+ AddError(
+ "variables of type '" + sem_.TypeNameOf(storage_ty) + "' must not have a storage class",
+ var->source);
return false;
}
- if (decl->is_const && !var->Is<sem::Parameter>() &&
- !(storage_ty->IsConstructible() || storage_ty->Is<sem::Pointer>())) {
- AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a let",
- decl->source);
+ if (IsValidationEnabled(var->attributes, ast::DisabledValidation::kIgnoreStorageClass) &&
+ (var->declared_storage_class == ast::StorageClass::kIn ||
+ var->declared_storage_class == ast::StorageClass::kOut)) {
+ AddError("invalid use of input/output storage class", var->source);
return false;
}
+ return true;
+}
- if (auto* r = storage_ty->As<sem::SampledTexture>()) {
- if (!r->type()->UnwrapRef()->is_numeric_scalar()) {
- AddError("texture_2d<type>: type must be f32, i32 or u32", decl->source);
- return false;
- }
+bool Validator::Let(const sem::Variable* v) const {
+ auto* decl = v->Declaration();
+ auto* storage_ty = v->Type()->UnwrapRef();
+
+ if (!(storage_ty->IsConstructible() || storage_ty->Is<sem::Pointer>())) {
+ AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a 'let'",
+ decl->source);
+ return false;
}
+ return true;
+}
- if (auto* r = storage_ty->As<sem::MultisampledTexture>()) {
- if (r->dim() != ast::TextureDimension::k2d) {
- AddError("only 2d multisampled textures are supported", decl->source);
- return false;
- }
+bool Validator::Override(
+ const sem::Variable* v,
+ const std::unordered_map<OverrideId, const sem::Variable*>& override_ids) const {
+ auto* decl = v->Declaration();
+ auto* storage_ty = v->Type()->UnwrapRef();
- if (!r->type()->UnwrapRef()->is_numeric_scalar()) {
- AddError("texture_multisampled_2d<type>: type must be f32, i32 or u32", decl->source);
- return false;
- }
+ if (auto* init = v->Constructor(); init && init->Stage() > sem::EvaluationStage::kOverride) {
+ AddError("'override' initializer must be an override expression",
+ init->Declaration()->source);
+ return false;
}
- if (var->Is<sem::LocalVariable>() && !decl->is_const &&
- IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreStorageClass)) {
- if (!var->Type()->UnwrapRef()->IsConstructible()) {
- AddError("function variable must have a constructible type",
- decl->type ? decl->type->source : decl->source);
+ for (auto* attr : decl->attributes) {
+ if (auto* id_attr = attr->As<ast::IdAttribute>()) {
+ uint32_t id = id_attr->value;
+ if (id > std::numeric_limits<decltype(OverrideId::value)>::max()) {
+ AddError(
+ "override IDs must be between 0 and " +
+ std::to_string(std::numeric_limits<decltype(OverrideId::value)>::max()),
+ attr->source);
+ return false;
+ }
+ if (auto it =
+ override_ids.find(OverrideId{static_cast<decltype(OverrideId::value)>(id)});
+ it != override_ids.end() && it->second != v) {
+ AddError("override IDs must be unique", attr->source);
+ AddNote("a override with an ID of " + std::to_string(id) +
+ " was previously declared here:",
+ ast::GetAttribute<ast::IdAttribute>(it->second->Declaration()->attributes)
+ ->source);
+ return false;
+ }
+ } else {
+ AddError("attribute is not valid for 'override' declaration", attr->source);
return false;
}
}
- if (storage_ty->is_handle() && decl->declared_storage_class != ast::StorageClass::kNone) {
- // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
- // If the store type is a texture type or a sampler type, then the
- // variable declaration must not have a storage class attribute. The
- // storage class will always be handle.
- AddError(
- "variables of type '" + sem_.TypeNameOf(storage_ty) + "' must not have a storage class",
- decl->source);
+ auto name = symbols_.NameFor(decl->symbol);
+ if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
+ AddError("'" + name + "' is a builtin and cannot be redeclared as a 'override'",
+ decl->source);
+ return false;
+ }
+
+ if (!storage_ty->is_scalar()) {
+ AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a 'override'",
+ decl->source);
return false;
}
- if (IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreStorageClass) &&
- (decl->declared_storage_class == ast::StorageClass::kInput ||
- decl->declared_storage_class == ast::StorageClass::kOutput)) {
- AddError("invalid use of input/output storage class", decl->source);
+ if (storage_ty->Is<sem::F16>()) {
+ AddError("'override' of type f16 is not implemented yet", decl->source);
return false;
}
+
return true;
}
-bool Validator::FunctionParameter(const ast::Function* func, const sem::Variable* var) const {
- if (!Variable(var)) {
+bool Validator::Const(const sem::Variable* v) const {
+ auto* decl = v->Declaration();
+
+ auto name = symbols_.NameFor(decl->symbol);
+ if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
+ AddError("'" + name + "' is a builtin and cannot be redeclared as a 'const'", decl->source);
return false;
}
+ return true;
+}
+
+bool Validator::Parameter(const ast::Function* func, const sem::Variable* var) const {
auto* decl = var->Declaration();
+ if (IsValidationDisabled(decl->attributes, ast::DisabledValidation::kFunctionParameter)) {
+ return true;
+ }
+
for (auto* attr : decl->attributes) {
if (!func->IsEntryPoint() && !attr->Is<ast::InternalAttribute>()) {
AddError("attribute is not valid for non-entry point function parameters",
attr->source);
return false;
- } else if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InvariantAttribute,
- ast::LocationAttribute, ast::InterpolateAttribute,
- ast::InternalAttribute>() &&
- (IsValidationEnabled(decl->attributes,
- ast::DisabledValidation::kEntryPointParameter) &&
- IsValidationEnabled(
- decl->attributes,
- ast::DisabledValidation::kIgnoreConstructibleFunctionParameter))) {
+ }
+ if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InvariantAttribute, ast::LocationAttribute,
+ ast::InterpolateAttribute, ast::InternalAttribute>() &&
+ (IsValidationEnabled(decl->attributes,
+ ast::DisabledValidation::kEntryPointParameter))) {
AddError("attribute is not valid for function parameters", attr->source);
return false;
}
@@ -753,14 +879,12 @@ bool Validator::FunctionParameter(const ast::Function* func, const sem::Variable
}
if (IsPlain(var->Type())) {
- if (!var->Type()->IsConstructible() &&
- IsValidationEnabled(decl->attributes,
- ast::DisabledValidation::kIgnoreConstructibleFunctionParameter)) {
- AddError("store type of function parameter must be a constructible type", decl->source);
+ if (!var->Type()->IsConstructible()) {
+ AddError("type of function parameter must be constructible", decl->source);
return false;
}
} else if (!var->Type()->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
- AddError("store type of function parameter cannot be " + sem_.TypeNameOf(var->Type()),
+ AddError("type of function parameter cannot be " + sem_.TypeNameOf(var->Type()),
decl->source);
return false;
}
@@ -778,7 +902,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
bool is_stage_mismatch = false;
bool is_output = !is_input;
switch (attr->builtin) {
- case ast::Builtin::kPosition:
+ case ast::BuiltinValue::kPosition:
if (stage != ast::PipelineStage::kNone &&
!((is_input && stage == ast::PipelineStage::kFragment) ||
(is_output && stage == ast::PipelineStage::kVertex))) {
@@ -790,10 +914,10 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
return false;
}
break;
- case ast::Builtin::kGlobalInvocationId:
- case ast::Builtin::kLocalInvocationId:
- case ast::Builtin::kNumWorkgroups:
- case ast::Builtin::kWorkgroupId:
+ case ast::BuiltinValue::kGlobalInvocationId:
+ case ast::BuiltinValue::kLocalInvocationId:
+ case ast::BuiltinValue::kNumWorkgroups:
+ case ast::BuiltinValue::kWorkgroupId:
if (stage != ast::PipelineStage::kNone &&
!(stage == ast::PipelineStage::kCompute && is_input)) {
is_stage_mismatch = true;
@@ -804,7 +928,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
return false;
}
break;
- case ast::Builtin::kFragDepth:
+ case ast::BuiltinValue::kFragDepth:
if (stage != ast::PipelineStage::kNone &&
!(stage == ast::PipelineStage::kFragment && !is_input)) {
is_stage_mismatch = true;
@@ -814,7 +938,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
return false;
}
break;
- case ast::Builtin::kFrontFacing:
+ case ast::BuiltinValue::kFrontFacing:
if (stage != ast::PipelineStage::kNone &&
!(stage == ast::PipelineStage::kFragment && is_input)) {
is_stage_mismatch = true;
@@ -824,7 +948,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
return false;
}
break;
- case ast::Builtin::kLocalInvocationIndex:
+ case ast::BuiltinValue::kLocalInvocationIndex:
if (stage != ast::PipelineStage::kNone &&
!(stage == ast::PipelineStage::kCompute && is_input)) {
is_stage_mismatch = true;
@@ -834,8 +958,8 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
return false;
}
break;
- case ast::Builtin::kVertexIndex:
- case ast::Builtin::kInstanceIndex:
+ case ast::BuiltinValue::kVertexIndex:
+ case ast::BuiltinValue::kInstanceIndex:
if (stage != ast::PipelineStage::kNone &&
!(stage == ast::PipelineStage::kVertex && is_input)) {
is_stage_mismatch = true;
@@ -845,7 +969,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
return false;
}
break;
- case ast::Builtin::kSampleMask:
+ case ast::BuiltinValue::kSampleMask:
if (stage != ast::PipelineStage::kNone && !(stage == ast::PipelineStage::kFragment)) {
is_stage_mismatch = true;
}
@@ -854,7 +978,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
return false;
}
break;
- case ast::Builtin::kSampleIndex:
+ case ast::BuiltinValue::kSampleIndex:
if (stage != ast::PipelineStage::kNone &&
!(stage == ast::PipelineStage::kFragment && is_input)) {
is_stage_mismatch = true;
@@ -920,17 +1044,11 @@ bool Validator::Function(const sem::Function* func, ast::PipelineStage stage) co
}
}
- if (decl->params.size() > 255) {
+ if (decl->params.Length() > 255) {
AddError("functions may declare at most 255 parameters", decl->source);
return false;
}
- for (size_t i = 0; i < decl->params.size(); i++) {
- if (!FunctionParameter(decl, func->Parameters()[i])) {
- return false;
- }
- }
-
if (!func->ReturnType()->Is<sem::Void>()) {
if (!func->ReturnType()->IsConstructible()) {
AddError("function return type must be a constructible type",
@@ -964,9 +1082,8 @@ bool Validator::Function(const sem::Function* func, ast::PipelineStage stage) co
ast::InvariantAttribute>() &&
(IsValidationEnabled(decl->attributes,
ast::DisabledValidation::kEntryPointParameter) &&
- IsValidationEnabled(
- decl->attributes,
- ast::DisabledValidation::kIgnoreConstructibleFunctionParameter))) {
+ IsValidationEnabled(decl->attributes,
+ ast::DisabledValidation::kFunctionParameter))) {
AddError("attribute is not valid for entry point return types", attr->source);
return false;
}
@@ -1001,7 +1118,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
// already been seen, in order to catch conflicts.
// TODO(jrprice): This state could be stored in sem::Function instead, and
// then passed to sem::Function since it would be useful there too.
- std::unordered_set<ast::Builtin> builtins;
+ std::unordered_set<ast::BuiltinValue> builtins;
std::unordered_set<uint32_t> locations;
enum class ParamOrRetType {
kParameter,
@@ -1009,10 +1126,18 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
};
// Inner lambda that is applied to a type and all of its members.
- auto validate_entry_point_attributes_inner = [&](const ast::AttributeList& attrs,
+ auto validate_entry_point_attributes_inner = [&](utils::VectorRef<const ast::Attribute*> attrs,
const sem::Type* ty, Source source,
ParamOrRetType param_or_ret,
bool is_struct_member) {
+ // Temporally forbid using f16 types in entry point IO.
+ // TODO(tint:1473, tint:1502): Remove this error after f16 is supported in entry point
+ // IO.
+ if (Is<sem::F16>(sem::Type::DeepestElementOf(ty))) {
+ AddError("entry point IO of f16 types is not implemented yet", source);
+ return false;
+ }
+
// Scan attributes for pipeline IO attributes.
// Check for overlap with attributes that have been seen previously.
const ast::Attribute* pipeline_io_attribute = nullptr;
@@ -1129,7 +1254,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
bool has_position = false;
if (pipeline_io_attribute) {
if (auto* builtin = pipeline_io_attribute->As<ast::BuiltinAttribute>()) {
- has_position = (builtin->builtin == ast::Builtin::kPosition);
+ has_position = (builtin->builtin == ast::BuiltinValue::kPosition);
}
}
if (!has_position) {
@@ -1145,8 +1270,9 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
};
// Outer lambda for validating the entry point attributes for a type.
- auto validate_entry_point_attributes = [&](const ast::AttributeList& attrs, const sem::Type* ty,
- Source source, ParamOrRetType param_or_ret) {
+ auto validate_entry_point_attributes = [&](utils::VectorRef<const ast::Attribute*> attrs,
+ const sem::Type* ty, Source source,
+ ParamOrRetType param_or_ret) {
if (!validate_entry_point_attributes_inner(attrs, ty, source, param_or_ret,
/*is_struct_member*/ false)) {
return false;
@@ -1190,13 +1316,13 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
}
if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
- builtins.count(ast::Builtin::kPosition) == 0) {
+ builtins.count(ast::BuiltinValue::kPosition) == 0) {
// Check module-scope variables, as the SPIR-V sanitizer generates these.
bool found = false;
for (auto* global : func->TransitivelyReferencedGlobals()) {
if (auto* builtin =
ast::GetAttribute<ast::BuiltinAttribute>(global->Declaration()->attributes)) {
- if (builtin->builtin == ast::Builtin::kPosition) {
+ if (builtin->builtin == ast::BuiltinValue::kPosition) {
found = true;
break;
}
@@ -1223,12 +1349,12 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
// Validate there are no resource variable binding collisions
std::unordered_map<sem::BindingPoint, const ast::Variable*> binding_points;
- for (auto* var : func->TransitivelyReferencedGlobals()) {
- auto* var_decl = var->Declaration();
- if (!var_decl->BindingPoint()) {
+ for (auto* global : func->TransitivelyReferencedGlobals()) {
+ auto* var_decl = global->Declaration()->As<ast::Var>();
+ if (!var_decl || !var_decl->BindingPoint()) {
continue;
}
- auto bp = var->BindingPoint();
+ auto bp = global->BindingPoint();
auto res = binding_points.emplace(bp, var_decl);
if (!res.second &&
IsValidationEnabled(decl->attributes,
@@ -1255,7 +1381,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
return true;
}
-bool Validator::Statements(const ast::StatementList& stmts) const {
+bool Validator::Statements(utils::VectorRef<const ast::Statement*> stmts) const {
for (auto* stmt : stmts) {
if (!sem_.Get(stmt)->IsReachable()) {
/// TODO(https://github.com/gpuweb/gpuweb/issues/2378): This may need to
@@ -1319,7 +1445,7 @@ bool Validator::BreakStatement(const sem::Statement* stmt,
return fail("break statement is not directly in if statement block",
stmt->Declaration()->source);
}
- if (block->Declaration()->statements.size() != 1) {
+ if (block->Declaration()->statements.Length() != 1) {
return fail("if statement block contains multiple statements",
block->Declaration()->source);
}
@@ -1383,28 +1509,21 @@ bool Validator::Call(const sem::Call* call, sem::Statement* current_statement) c
bool is_call_stmt =
current_statement && Is<ast::CallStatement>(current_statement->Declaration(),
[&](auto* stmt) { return stmt->expr == expr; });
-
- return Switch(
- call->Target(), //
- [&](const sem::TypeConversion*) {
- if (is_call_stmt) {
+ if (is_call_stmt) {
+ return Switch(
+ call->Target(), //
+ [&](const sem::TypeConversion*) {
AddError("type conversion evaluated but not used", call->Declaration()->source);
return false;
- }
- return true;
- },
- [&](const sem::TypeConstructor* ctor) {
- if (is_call_stmt) {
+ },
+ [&](const sem::TypeConstructor*) {
AddError("type constructor evaluated but not used", call->Declaration()->source);
return false;
- }
- return Switch(
- ctor->ReturnType(), //
- [&](const sem::Array* arr) { return ArrayConstructor(expr, arr); },
- [&](const sem::Struct* str) { return StructureConstructor(expr, str); },
- [&](Default) { return true; });
- },
- [&](Default) { return true; });
+ },
+ [&](Default) { return true; });
+ }
+
+ return true;
}
bool Validator::DiscardStatement(const sem::Statement* stmt,
@@ -1425,7 +1544,7 @@ bool Validator::FallthroughStatement(const sem::Statement* stmt) const {
if (auto* c = As<sem::CaseStatement>(block->Parent())) {
if (block->Declaration()->Last() == stmt->Declaration()) {
if (auto* s = As<sem::SwitchStatement>(c->Parent())) {
- if (c->Declaration() != s->Declaration()->body.back()) {
+ if (c->Declaration() != s->Declaration()->body.Back()) {
return true;
}
AddError(
@@ -1466,6 +1585,22 @@ bool Validator::ForLoopStatement(const sem::ForLoopStatement* stmt) const {
return true;
}
+bool Validator::WhileStatement(const sem::WhileStatement* stmt) const {
+ if (stmt->Behaviors().Empty()) {
+ AddError("while does not exit", stmt->Declaration()->source.Begin());
+ return false;
+ }
+ if (auto* cond = stmt->Condition()) {
+ auto* cond_ty = cond->Type()->UnwrapRef();
+ if (!cond_ty->Is<sem::Bool>()) {
+ AddError("while condition must be bool, got " + sem_.TypeNameOf(cond_ty),
+ stmt->Condition()->Declaration()->source);
+ return false;
+ }
+ }
+ return true;
+}
+
bool Validator::IfStatement(const sem::IfStatement* stmt) const {
auto* cond_ty = stmt->Condition()->Type()->UnwrapRef();
if (!cond_ty->Is<sem::Bool>()) {
@@ -1479,9 +1614,14 @@ bool Validator::IfStatement(const sem::IfStatement* stmt) const {
bool Validator::BuiltinCall(const sem::Call* call) const {
if (call->Type()->Is<sem::Void>()) {
bool is_call_statement = false;
- if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
- if (call_stmt->expr == call->Declaration()) {
- is_call_statement = true;
+ // Some built-in call are not owned by a statement, e.g. a built-in called in global
+ // variable declaration. Calling no-return-value built-in in these context is invalid as
+ // well.
+ if (auto* call_stmt = call->Stmt()) {
+ if (auto* call_stmt_ast = As<ast::CallStatement>(call_stmt->Declaration())) {
+ if (call_stmt_ast->expr == call->Declaration()) {
+ is_call_statement = true;
+ }
}
}
if (!is_call_statement) {
@@ -1508,16 +1648,16 @@ bool Validator::TextureBuiltinFunction(const sem::Call* call) const {
auto& signature = builtin->Signature();
auto check_arg_is_constexpr = [&](sem::ParameterUsage usage, int min, int max) {
- auto index = signature.IndexOf(usage);
- if (index < 0) {
+ auto signed_index = signature.IndexOf(usage);
+ if (signed_index < 0) {
return true;
}
+ auto index = static_cast<size_t>(signed_index);
std::string name = sem::str(usage);
auto* arg = call->Arguments()[index];
if (auto values = arg->ConstantValue()) {
// Assert that the constant values are of the expected type.
- if (!values.Type()->IsAnyOf<sem::I32, sem::Vector>() ||
- !values.ElementType()->Is<sem::I32>()) {
+ if (!values->Type()->is_integer_scalar_or_vector()) {
TINT_ICE(Resolver, diagnostics_)
<< "failed to resolve '" + func_name + "' " << name << " parameter type";
return false;
@@ -1535,24 +1675,26 @@ bool Validator::TextureBuiltinFunction(const sem::Call* call) const {
return ast::TraverseAction::Stop;
});
if (is_const_expr) {
- auto vector = builtin->Parameters()[index]->Type()->Is<sem::Vector>();
- for (size_t i = 0, n = values.ElementCount(); i < n; i++) {
- auto value = values.Element<AInt>(i).value;
- if (value < min || value > max) {
- if (vector) {
+ if (auto* vector = builtin->Parameters()[index]->Type()->As<sem::Vector>()) {
+ for (size_t i = 0; i < vector->Width(); i++) {
+ auto value = values->Index(i)->As<AInt>();
+ if (value < min || value > max) {
AddError("each component of the " + name +
" argument must be at least " + std::to_string(min) +
" and at most " + std::to_string(max) + ". " + name +
" component " + std::to_string(i) + " is " +
std::to_string(value),
arg->Declaration()->source);
- } else {
- AddError("the " + name + " argument must be at least " +
- std::to_string(min) + " and at most " +
- std::to_string(max) + ". " + name + " is " +
- std::to_string(value),
- arg->Declaration()->source);
+ return false;
}
+ }
+ } else {
+ auto value = values->As<AInt>();
+ if (value < min || value > max) {
+ AddError("the " + name + " argument must be at least " +
+ std::to_string(min) + " and at most " + std::to_string(max) +
+ ". " + name + " is " + std::to_string(value),
+ arg->Declaration()->source);
return false;
}
}
@@ -1577,13 +1719,13 @@ bool Validator::RequiredExtensionForBuiltinFunction(
}
const auto extension = builtin->RequiredExtension();
- if (extension == ast::Extension::kNone) {
+ if (extension == ast::Extension::kInvalid) {
return true;
}
- if (!enabled_extensions.contains(extension)) {
+ if (!enabled_extensions.Contains(extension)) {
AddError("cannot call built-in function '" + std::string(builtin->str()) +
- "' without extension " + ast::str(extension),
+ "' without extension " + utils::ToString(extension),
call->Declaration()->source);
return false;
}
@@ -1597,6 +1739,11 @@ bool Validator::FunctionCall(const sem::Call* call, sem::Statement* current_stat
auto sym = decl->target.name->symbol;
auto name = symbols_.NameFor(sym);
+ if (!current_statement) { // Function call at module-scope.
+ AddError("functions cannot be called at module-scope", decl->source);
+ return false;
+ }
+
if (target->Declaration()->IsEntryPoint()) {
// https://www.w3.org/TR/WGSL/#function-restriction
// An entry point must never be the target of a function call.
@@ -1604,17 +1751,17 @@ bool Validator::FunctionCall(const sem::Call* call, sem::Statement* current_stat
return false;
}
- if (decl->args.size() != target->Parameters().size()) {
- bool more = decl->args.size() > target->Parameters().size();
+ if (decl->args.Length() != target->Parameters().Length()) {
+ bool more = decl->args.Length() > target->Parameters().Length();
AddError("too " + (more ? std::string("many") : std::string("few")) +
" arguments in call to '" + name + "', expected " +
- std::to_string(target->Parameters().size()) + ", got " +
- std::to_string(call->Arguments().size()),
+ std::to_string(target->Parameters().Length()) + ", got " +
+ std::to_string(call->Arguments().Length()),
decl->source);
return false;
}
- for (size_t i = 0; i < call->Arguments().size(); ++i) {
+ for (size_t i = 0; i < call->Arguments().Length(); ++i) {
const sem::Variable* param = target->Parameters()[i];
const ast::Expression* arg_expr = decl->args[i];
auto* param_type = param->Type();
@@ -1647,12 +1794,6 @@ bool Validator::FunctionCall(const sem::Call* call, sem::Statement* current_stat
TINT_ICE(Resolver, diagnostics_) << "failed to resolve identifier";
return false;
}
- if (var->Declaration()->is_const) {
- TINT_ICE(Resolver, diagnostics_)
- << "Resolver::FunctionCall() encountered an address-of "
- "expression of a constant identifier expression";
- return false;
- }
is_valid = true;
}
}
@@ -1708,12 +1849,12 @@ bool Validator::StructureConstructor(const ast::CallExpression* ctor,
return false;
}
- if (ctor->args.size() > 0) {
- if (ctor->args.size() != struct_type->Members().size()) {
- std::string fm = ctor->args.size() < struct_type->Members().size() ? "few" : "many";
+ if (ctor->args.Length() > 0) {
+ if (ctor->args.Length() != struct_type->Members().size()) {
+ std::string fm = ctor->args.Length() < struct_type->Members().size() ? "few" : "many";
AddError("struct constructor has too " + fm + " inputs: expected " +
std::to_string(struct_type->Members().size()) + ", found " +
- std::to_string(ctor->args.size()),
+ std::to_string(ctor->args.Length()),
ctor->source);
return false;
}
@@ -1740,33 +1881,32 @@ bool Validator::ArrayConstructor(const ast::CallExpression* ctor,
auto* elem_ty = array_type->ElemType();
for (auto* value : values) {
auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
- if (value_ty != elem_ty) {
- AddError(
- "type in array constructor does not match array type: "
- "expected '" +
- sem_.TypeNameOf(elem_ty) + "', found '" + sem_.TypeNameOf(value_ty) + "'",
- value->source);
+ if (sem::Type::ConversionRank(value_ty, elem_ty) == sem::Type::kNoConversion) {
+ AddError("'" + sem_.TypeNameOf(value_ty) +
+ "' cannot be used to construct an array of '" + sem_.TypeNameOf(elem_ty) +
+ "'",
+ value->source);
return false;
}
}
if (array_type->IsRuntimeSized()) {
- AddError("cannot init a runtime-sized array", ctor->source);
+ AddError("cannot construct a runtime-sized array", ctor->source);
return false;
} else if (!elem_ty->IsConstructible()) {
AddError("array constructor has non-constructible element type", ctor->source);
return false;
- } else if (!values.empty() && (values.size() != array_type->Count())) {
- std::string fm = values.size() < array_type->Count() ? "few" : "many";
+ } else if (!values.IsEmpty() && (values.Length() != array_type->Count())) {
+ std::string fm = values.Length() < array_type->Count() ? "few" : "many";
AddError("array constructor has too " + fm + " elements: expected " +
std::to_string(array_type->Count()) + ", found " +
- std::to_string(values.size()),
+ std::to_string(values.Length()),
ctor->source);
return false;
- } else if (values.size() > array_type->Count()) {
+ } else if (values.Length() > array_type->Count()) {
AddError("array constructor has too many elements: expected " +
std::to_string(array_type->Count()) + ", found " +
- std::to_string(values.size()),
+ std::to_string(values.Length()),
ctor->source);
return false;
}
@@ -1775,7 +1915,7 @@ bool Validator::ArrayConstructor(const ast::CallExpression* ctor,
bool Validator::Vector(const sem::Vector* ty, const Source& source) const {
if (!ty->type()->is_scalar()) {
- AddError("vector element type must be 'bool', 'f32', 'i32' or 'u32'", source);
+ AddError("vector element type must be 'bool', 'f32', 'f16', 'i32' or 'u32'", source);
return false;
}
return true;
@@ -1783,7 +1923,7 @@ bool Validator::Vector(const sem::Vector* ty, const Source& source) const {
bool Validator::Matrix(const sem::Matrix* ty, const Source& source) const {
if (!ty->is_float_matrix()) {
- AddError("matrix element type must be 'f32'", source);
+ AddError("matrix element type must be 'f32' or 'f16'", source);
return false;
}
return true;
@@ -1874,9 +2014,81 @@ bool Validator::PipelineStages(const std::vector<sem::Function*>& entry_points)
return true;
}
+bool Validator::PushConstants(const std::vector<sem::Function*>& entry_points) const {
+ for (auto* entry_point : entry_points) {
+ // State checked and modified by check_push_constant so that it remembers previously seen
+ // push_constant variables for an entry-point.
+ const sem::Variable* push_constant_var = nullptr;
+ const sem::Function* push_constant_func = nullptr;
+
+ auto check_push_constant = [&](const sem::Function* func, const sem::Function* ep) {
+ for (auto* var : func->DirectlyReferencedGlobals()) {
+ if (var->StorageClass() != ast::StorageClass::kPushConstant ||
+ var == push_constant_var) {
+ continue;
+ }
+
+ if (push_constant_var == nullptr) {
+ push_constant_var = var;
+ push_constant_func = func;
+ continue;
+ }
+
+ AddError("entry point '" + symbols_.NameFor(ep->Declaration()->symbol) +
+ "' uses two different 'push_constant' variables.",
+ ep->Declaration()->source);
+ AddNote("first 'push_constant' variable declaration is here",
+ var->Declaration()->source);
+ if (func != ep) {
+ TraverseCallChain(diagnostics_, ep, func, [&](const sem::Function* f) {
+ AddNote("called by function '" +
+ symbols_.NameFor(f->Declaration()->symbol) + "'",
+ f->Declaration()->source);
+ });
+ AddNote("called by entry point '" +
+ symbols_.NameFor(ep->Declaration()->symbol) + "'",
+ ep->Declaration()->source);
+ }
+ AddNote("second 'push_constant' variable declaration is here",
+ push_constant_var->Declaration()->source);
+ if (push_constant_func != ep) {
+ TraverseCallChain(
+ diagnostics_, ep, push_constant_func, [&](const sem::Function* f) {
+ AddNote("called by function '" +
+ symbols_.NameFor(f->Declaration()->symbol) + "'",
+ f->Declaration()->source);
+ });
+ AddNote("called by entry point '" +
+ symbols_.NameFor(ep->Declaration()->symbol) + "'",
+ ep->Declaration()->source);
+ }
+ return false;
+ }
+
+ return true;
+ };
+
+ if (!check_push_constant(entry_point, entry_point)) {
+ return false;
+ }
+ for (auto* func : entry_point->TransitivelyCalledFunctions()) {
+ if (!check_push_constant(func, entry_point)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
bool Validator::Array(const sem::Array* arr, const Source& source) const {
auto* el_ty = arr->ElemType();
+ if (!IsPlain(el_ty)) {
+ AddError(sem_.TypeNameOf(el_ty) + " cannot be used as an element type of an array", source);
+ return false;
+ }
+
if (!IsFixedFootprint(el_ty)) {
AddError("an array element type cannot contain a runtime-sized array", source);
return false;
@@ -1886,8 +2098,7 @@ bool Validator::Array(const sem::Array* arr, const Source& source) const {
bool Validator::ArrayStrideAttribute(const ast::StrideAttribute* attr,
uint32_t el_size,
- uint32_t el_align,
- const Source& source) const {
+ uint32_t el_align) const {
auto stride = attr->stride;
bool is_valid_stride = (stride >= el_size) && (stride >= el_align) && (stride % el_align == 0);
if (!is_valid_stride) {
@@ -1898,8 +2109,8 @@ bool Validator::ArrayStrideAttribute(const ast::StrideAttribute* attr,
AddError(
"arrays decorated with the stride attribute must have a stride "
"that is at least the size of the element type, and be a multiple "
- "of the element type's alignment value.",
- source);
+ "of the element type's alignment value",
+ attr->source);
return false;
}
return true;
@@ -1981,7 +2192,7 @@ bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) cons
/* is_input */ false)) {
return false;
}
- if (builtin->builtin == ast::Builtin::kPosition) {
+ if (builtin->builtin == ast::BuiltinValue::kPosition) {
has_position = true;
}
} else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
@@ -2156,16 +2367,16 @@ bool Validator::Assignment(const ast::Statement* a, const sem::Type* rhs_ty) con
// https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
auto const* lhs_ty = sem_.TypeOf(lhs);
- if (auto* var = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
- auto* decl = var->Declaration();
- if (var->Is<sem::Parameter>()) {
- AddError("cannot assign to function parameter", lhs->source);
- AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
- return false;
- }
- if (decl->is_const) {
- AddError("cannot assign to const", lhs->source);
- AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
+ if (auto* variable = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
+ auto* v = variable->Declaration();
+ const char* err = Switch(
+ v, //
+ [&](const ast::Parameter*) { return "cannot assign to function parameter"; },
+ [&](const ast::Let*) { return "cannot assign to 'let'"; },
+ [&](const ast::Override*) { return "cannot assign to 'override'"; });
+ if (err) {
+ AddError(err, lhs->source);
+ AddNote("'" + symbols_.NameFor(v->symbol) + "' is declared here:", v->source);
return false;
}
}
@@ -2204,16 +2415,16 @@ bool Validator::IncrementDecrementStatement(const ast::IncrementDecrementStateme
// https://gpuweb.github.io/gpuweb/wgsl/#increment-decrement
- if (auto* var = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
- auto* decl = var->Declaration();
- if (var->Is<sem::Parameter>()) {
- AddError("cannot modify function parameter", lhs->source);
- AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
- return false;
- }
- if (decl->is_const) {
- AddError("cannot modify constant value", lhs->source);
- AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
+ if (auto* variable = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
+ auto* v = variable->Declaration();
+ const char* err = Switch(
+ v, //
+ [&](const ast::Parameter*) { return "cannot modify function parameter"; },
+ [&](const ast::Let*) { return "cannot modify 'let'"; },
+ [&](const ast::Override*) { return "cannot modify 'override'"; });
+ if (err) {
+ AddError(err, lhs->source);
+ AddNote("'" + symbols_.NameFor(v->symbol) + "' is declared here:", v->source);
return false;
}
}
@@ -2239,7 +2450,7 @@ bool Validator::IncrementDecrementStatement(const ast::IncrementDecrementStateme
return true;
}
-bool Validator::NoDuplicateAttributes(const ast::AttributeList& attributes) const {
+bool Validator::NoDuplicateAttributes(utils::VectorRef<const ast::Attribute*> attributes) const {
std::unordered_map<const TypeInfo*, Source> seen;
for (auto* d : attributes) {
auto res = seen.emplace(&d->TypeInfo(), d->source);
@@ -2252,7 +2463,7 @@ bool Validator::NoDuplicateAttributes(const ast::AttributeList& attributes) cons
return true;
}
-bool Validator::IsValidationDisabled(const ast::AttributeList& attributes,
+bool Validator::IsValidationDisabled(utils::VectorRef<const ast::Attribute*> attributes,
ast::DisabledValidation validation) const {
for (auto* attribute : attributes) {
if (auto* dv = attribute->As<ast::DisableValidationAttribute>()) {
@@ -2264,7 +2475,7 @@ bool Validator::IsValidationDisabled(const ast::AttributeList& attributes,
return false;
}
-bool Validator::IsValidationEnabled(const ast::AttributeList& attributes,
+bool Validator::IsValidationEnabled(utils::VectorRef<const ast::Attribute*> attributes,
ast::DisabledValidation validation) const {
return !IsValidationDisabled(attributes, validation);
}
diff --git a/chromium/third_party/dawn/src/tint/resolver/validator.h b/chromium/third_party/dawn/src/tint/resolver/validator.h
index b30fdc72a14..57ac0648c85 100644
--- a/chromium/third_party/dawn/src/tint/resolver/validator.h
+++ b/chromium/third_party/dawn/src/tint/resolver/validator.h
@@ -44,12 +44,14 @@ class ReturnStatement;
class SwitchStatement;
class UnaryOpExpression;
class Variable;
+class WhileStatement;
} // namespace tint::ast
namespace tint::sem {
class Array;
class Atomic;
class BlockStatement;
class Builtin;
+class Call;
class CaseStatement;
class ForLoopStatement;
class IfStatement;
@@ -58,6 +60,7 @@ class Materialize;
class Statement;
class SwitchStatement;
class TypeConstructor;
+class WhileStatement;
} // namespace tint::sem
namespace tint::resolver {
@@ -113,6 +116,11 @@ class Validator {
/// @returns true on success, false otherwise.
bool PipelineStages(const std::vector<sem::Function*>& entry_points) const;
+ /// Validates push_constant variables
+ /// @param entry_points the entry points to the module
+ /// @returns true on success, false otherwise.
+ bool PushConstants(const std::vector<sem::Function*>& entry_points) const;
+
/// Validates aliases
/// @param alias the alias to validate
/// @returns true on success, false otherwise.
@@ -128,12 +136,10 @@ class Validator {
/// @param attr the stride attribute to validate
/// @param el_size the element size
/// @param el_align the element alignment
- /// @param source the source of the attribute
/// @returns true on success, false otherwise
bool ArrayStrideAttribute(const ast::StrideAttribute* attr,
uint32_t el_size,
- uint32_t el_align,
- const Source& source) const;
+ uint32_t el_align) const;
/// Validates an atomic
/// @param a the atomic ast node to validate
@@ -207,6 +213,11 @@ class Validator {
/// @returns true on success, false otherwise
bool ForLoopStatement(const sem::ForLoopStatement* stmt) const;
+ /// Validates a while loop
+ /// @param stmt the while statement to validate
+ /// @returns true on success, false otherwise
+ bool WhileStatement(const sem::WhileStatement* stmt) const;
+
/// Validates a fallthrough statement
/// @param stmt the fallthrough to validate
/// @returns true on success, false otherwise
@@ -226,13 +237,13 @@ class Validator {
/// Validates a global variable
/// @param var the global variable to validate
- /// @param constant_ids the set of constant ids in the module
+ /// @param override_id the set of override ids in the module
/// @param atomic_composite_info atomic composite info in the module
/// @returns true on success, false otherwise
bool GlobalVariable(
- const sem::Variable* var,
- std::unordered_map<uint32_t, const sem::Variable*> constant_ids,
- std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const;
+ const sem::GlobalVariable* var,
+ const std::unordered_map<OverrideId, const sem::Variable*>& override_id,
+ const std::unordered_map<const sem::Type*, const Source&>& atomic_composite_info) const;
/// Validates an if statement
/// @param stmt the statement to validate
@@ -256,6 +267,11 @@ class Validator {
/// @returns true on success, false otherwise.
bool BuiltinCall(const sem::Call* call) const;
+ /// Validates a local variable
+ /// @param v the variable to validate
+ /// @returns true on success, false otherwise.
+ bool LocalVariable(const sem::Variable* v) const;
+
/// Validates a location attribute
/// @param location the location attribute to validate
/// @param type the variable type
@@ -276,10 +292,12 @@ class Validator {
/// @returns true on success, false otherwise.
bool LoopStatement(const sem::LoopStatement* stmt) const;
- /// Validates a materialize of an abstract numeric value
- /// @param m the materialize to validate
+ /// Validates a materialize of an abstract numeric value from the type `from` to the type `to`.
+ /// @param to the target type
+ /// @param from the abstract numeric type
+ /// @param source the source of the materialization
/// @returns true on success, false otherwise
- bool Materialize(const sem::Materialize* m) const;
+ bool Materialize(const sem::Type* to, const sem::Type* from, const Source& source) const;
/// Validates a matrix
/// @param ty the matrix to validate
@@ -291,7 +309,7 @@ class Validator {
/// @param func the function the variable is for
/// @param var the variable to validate
/// @returns true on success, false otherwise
- bool FunctionParameter(const ast::Function* func, const sem::Variable* var) const;
+ bool Parameter(const ast::Function* func, const sem::Variable* var) const;
/// Validates a return
/// @param ret the return statement to validate
@@ -307,13 +325,25 @@ class Validator {
/// Validates a list of statements
/// @param stmts the statements to validate
/// @returns true on success, false otherwise
- bool Statements(const ast::StatementList& stmts) const;
+ bool Statements(utils::VectorRef<const ast::Statement*> stmts) const;
/// Validates a storage texture
/// @param t the texture to validate
/// @returns true on success, false otherwise
bool StorageTexture(const ast::StorageTexture* t) const;
+ /// Validates a sampled texture
+ /// @param t the texture to validate
+ /// @param source the source of the texture
+ /// @returns true on success, false otherwise
+ bool SampledTexture(const sem::SampledTexture* t, const Source& source) const;
+
+ /// Validates a multisampled texture
+ /// @param t the texture to validate
+ /// @param source the source of the texture
+ /// @returns true on success, false otherwise
+ bool MultisampledTexture(const sem::MultisampledTexture* t, const Source& source) const;
+
/// Validates a structure
/// @param str the structure to validate
/// @param stage the current pipeline stage
@@ -332,21 +362,38 @@ class Validator {
/// @returns true on success, false otherwise
bool SwitchStatement(const ast::SwitchStatement* s);
- /// Validates a variable
- /// @param var the variable to validate
+ /// Validates a 'var' variable declaration
+ /// @param v the variable to validate
/// @returns true on success, false otherwise.
- bool Variable(const sem::Variable* var) const;
+ bool Var(const sem::Variable* v) const;
- /// Validates a variable constructor or cast
- /// @param var the variable to validate
+ /// Validates a 'let' variable declaration
+ /// @param v the variable to validate
+ /// @returns true on success, false otherwise.
+ bool Let(const sem::Variable* v) const;
+
+ /// Validates a 'override' variable declaration
+ /// @param v the variable to validate
+ /// @param override_id the set of override ids in the module
+ /// @returns true on success, false otherwise.
+ bool Override(const sem::Variable* v,
+ const std::unordered_map<OverrideId, const sem::Variable*>& override_id) const;
+
+ /// Validates a 'const' variable declaration
+ /// @param v the variable to validate
+ /// @returns true on success, false otherwise.
+ bool Const(const sem::Variable* v) const;
+
+ /// Validates a variable initializer
+ /// @param v the variable to validate
/// @param storage_class the storage class of the variable
/// @param storage_type the type of the storage
- /// @param rhs_type the right hand side of the expression
+ /// @param initializer the RHS initializer expression
/// @returns true on succes, false otherwise
- bool VariableConstructorOrCast(const ast::Variable* var,
- ast::StorageClass storage_class,
- const sem::Type* storage_type,
- const sem::Type* rhs_type) const;
+ bool VariableInitializer(const ast::Variable* v,
+ ast::StorageClass storage_class,
+ const sem::Type* storage_type,
+ const sem::Expression* initializer) const;
/// Validates a vector
/// @param ty the vector to validate
@@ -375,7 +422,7 @@ class Validator {
/// Validates there are no duplicate attributes
/// @param attributes the list of attributes to validate
/// @returns true on success, false otherwise.
- bool NoDuplicateAttributes(const ast::AttributeList& attributes) const;
+ bool NoDuplicateAttributes(utils::VectorRef<const ast::Attribute*> attributes) const;
/// Validates a storage class layout
/// @param type the type to validate
@@ -391,15 +438,18 @@ class Validator {
/// Validates a storage class layout
/// @param var the variable to validate
/// @param layouts previously validated storage layouts
+ /// @param enabled_extensions all the extensions declared in current module
/// @returns true on success, false otherwise.
- bool StorageClassLayout(const sem::Variable* var, ValidTypeStorageLayouts& layouts) const;
+ bool StorageClassLayout(const sem::Variable* var,
+ const ast::Extensions& enabled_extensions,
+ ValidTypeStorageLayouts& layouts) const;
/// @returns true if the attribute list contains a
/// ast::DisableValidationAttribute with the validation mode equal to
/// `validation`
/// @param attributes the attribute list to check
/// @param validation the validation mode to check
- bool IsValidationDisabled(const ast::AttributeList& attributes,
+ bool IsValidationDisabled(utils::VectorRef<const ast::Attribute*> attributes,
ast::DisabledValidation validation) const;
/// @returns true if the attribute list does not contains a
@@ -407,7 +457,7 @@ class Validator {
/// `validation`
/// @param attributes the attribute list to check
/// @param validation the validation mode to check
- bool IsValidationEnabled(const ast::AttributeList& attributes,
+ bool IsValidationEnabled(utils::VectorRef<const ast::Attribute*> attributes,
ast::DisabledValidation validation) const;
private:
diff --git a/chromium/third_party/dawn/src/tint/resolver/validator_is_storeable_test.cc b/chromium/third_party/dawn/src/tint/resolver/validator_is_storeable_test.cc
index a5f612c9050..88ec9114030 100644
--- a/chromium/third_party/dawn/src/tint/resolver/validator_is_storeable_test.cc
+++ b/chromium/third_party/dawn/src/tint/resolver/validator_is_storeable_test.cc
@@ -32,6 +32,7 @@ TEST_F(ValidatorIsStorableTest, Scalar) {
EXPECT_TRUE(v()->IsStorable(create<sem::I32>()));
EXPECT_TRUE(v()->IsStorable(create<sem::U32>()));
EXPECT_TRUE(v()->IsStorable(create<sem::F32>()));
+ EXPECT_TRUE(v()->IsStorable(create<sem::F16>()));
}
TEST_F(ValidatorIsStorableTest, Vector) {
@@ -44,21 +45,36 @@ TEST_F(ValidatorIsStorableTest, Vector) {
EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F32>(), 2u)));
EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F32>(), 3u)));
EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F32>(), 4u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F16>(), 2u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F16>(), 3u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F16>(), 4u)));
}
TEST_F(ValidatorIsStorableTest, Matrix) {
- auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
- auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
- auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2, 2u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2, 3u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2, 4u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3, 2u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3, 3u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3, 4u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4, 2u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4, 3u)));
- EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4, 4u)));
+ auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2u);
+ auto* vec3_f32 = create<sem::Vector>(create<sem::F32>(), 3u);
+ auto* vec4_f32 = create<sem::Vector>(create<sem::F32>(), 4u);
+ auto* vec2_f16 = create<sem::Vector>(create<sem::F16>(), 2u);
+ auto* vec3_f16 = create<sem::Vector>(create<sem::F16>(), 3u);
+ auto* vec4_f16 = create<sem::Vector>(create<sem::F16>(), 4u);
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2_f32, 2u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2_f32, 3u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2_f32, 4u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3_f32, 2u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3_f32, 3u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3_f32, 4u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4_f32, 2u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4_f32, 3u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4_f32, 4u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2_f16, 2u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2_f16, 3u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2_f16, 4u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3_f16, 2u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3_f16, 3u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3_f16, 4u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4_f16, 2u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4_f16, 3u)));
+ EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4_f16, 4u)));
}
TEST_F(ValidatorIsStorableTest, Pointer) {
diff --git a/chromium/third_party/dawn/src/tint/resolver/var_let_test.cc b/chromium/third_party/dawn/src/tint/resolver/var_let_test.cc
deleted file mode 100644
index 43067365396..00000000000
--- a/chromium/third_party/dawn/src/tint/resolver/var_let_test.cc
+++ /dev/null
@@ -1,676 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/resolver/resolver.h"
-#include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/reference.h"
-
-#include "gmock/gmock.h"
-
-using namespace tint::number_suffixes; // NOLINT
-
-namespace tint::resolver {
-namespace {
-
-struct ResolverVarLetTest : public resolver::TestHelper, public testing::Test {};
-
-TEST_F(ResolverVarLetTest, VarDeclWithoutConstructor) {
- // struct S { i : i32; }
- // alias A = S;
- // fn F(){
- // var i : i32;
- // var u : u32;
- // var f : f32;
- // var b : bool;
- // var s : S;
- // var a : A;
- // }
-
- auto* S = Structure("S", {Member("i", ty.i32())});
- auto* A = Alias("A", ty.Of(S));
-
- auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
- auto* u = Var("u", ty.u32(), ast::StorageClass::kNone);
- auto* f = Var("f", ty.f32(), ast::StorageClass::kNone);
- auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone);
- auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone);
- auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone);
-
- Func("F", {}, ty.void_(),
- {
- Decl(i),
- Decl(u),
- Decl(f),
- Decl(b),
- Decl(s),
- Decl(a),
- });
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- // `var` declarations are always of reference type
- ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
-
- EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
- EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
- EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
- EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
- EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
- EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
-
- EXPECT_EQ(Sem().Get(i)->Constructor(), nullptr);
- EXPECT_EQ(Sem().Get(u)->Constructor(), nullptr);
- EXPECT_EQ(Sem().Get(f)->Constructor(), nullptr);
- EXPECT_EQ(Sem().Get(b)->Constructor(), nullptr);
- EXPECT_EQ(Sem().Get(s)->Constructor(), nullptr);
- EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr);
-}
-
-TEST_F(ResolverVarLetTest, VarDeclWithConstructor) {
- // struct S { i : i32; }
- // alias A = S;
- // fn F(){
- // var i : i32 = 1i;
- // var u : u32 = 1u;
- // var f : f32 = 1.f;
- // var b : bool = true;
- // var s : S = S(1);
- // var a : A = A(1);
- // }
-
- auto* S = Structure("S", {Member("i", ty.i32())});
- auto* A = Alias("A", ty.Of(S));
-
- auto* i_c = Expr(1_i);
- auto* u_c = Expr(1_u);
- auto* f_c = Expr(1_f);
- auto* b_c = Expr(true);
- auto* s_c = Construct(ty.Of(S), Expr(1_i));
- auto* a_c = Construct(ty.Of(A), Expr(1_i));
-
- auto* i = Var("i", ty.i32(), ast::StorageClass::kNone, i_c);
- auto* u = Var("u", ty.u32(), ast::StorageClass::kNone, u_c);
- auto* f = Var("f", ty.f32(), ast::StorageClass::kNone, f_c);
- auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone, b_c);
- auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone, s_c);
- auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone, a_c);
-
- Func("F", {}, ty.void_(),
- {
- Decl(i),
- Decl(u),
- Decl(f),
- Decl(b),
- Decl(s),
- Decl(a),
- });
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- // `var` declarations are always of reference type
- ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
-
- EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
- EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
- EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
- EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
- EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
- EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
-
- EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
- EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
- EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
- EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
- EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
- EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
-}
-
-TEST_F(ResolverVarLetTest, LetDecl) {
- // struct S { i : i32; }
- // fn F(){
- // var v : i32;
- // let i : i32 = 1i;
- // let u : u32 = 1u;
- // let f : f32 = 1.;
- // let b : bool = true;
- // let s : S = S(1);
- // let a : A = A(1);
- // let p : pointer<function, i32> = &v;
- // }
-
- auto* S = Structure("S", {Member("i", ty.i32())});
- auto* A = Alias("A", ty.Of(S));
- auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
-
- auto* i_c = Expr(1_i);
- auto* u_c = Expr(1_u);
- auto* f_c = Expr(1_f);
- auto* b_c = Expr(true);
- auto* s_c = Construct(ty.Of(S), Expr(1_i));
- auto* a_c = Construct(ty.Of(A), Expr(1_i));
- auto* p_c = AddressOf(v);
-
- auto* i = Let("i", ty.i32(), i_c);
- auto* u = Let("u", ty.u32(), u_c);
- auto* f = Let("f", ty.f32(), f_c);
- auto* b = Let("b", ty.bool_(), b_c);
- auto* s = Let("s", ty.Of(S), s_c);
- auto* a = Let("a", ty.Of(A), a_c);
- auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), p_c);
-
- Func("F", {}, ty.void_(),
- {
- Decl(v),
- Decl(i),
- Decl(u),
- Decl(f),
- Decl(b),
- Decl(s),
- Decl(a),
- Decl(p),
- });
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- // `let` declarations are always of the storage type
- ASSERT_TRUE(TypeOf(i)->Is<sem::I32>());
- ASSERT_TRUE(TypeOf(u)->Is<sem::U32>());
- ASSERT_TRUE(TypeOf(f)->Is<sem::F32>());
- ASSERT_TRUE(TypeOf(b)->Is<sem::Bool>());
- ASSERT_TRUE(TypeOf(s)->Is<sem::Struct>());
- ASSERT_TRUE(TypeOf(a)->Is<sem::Struct>());
- ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
- ASSERT_TRUE(TypeOf(p)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
-
- EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
- EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
- EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
- EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
- EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
- EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
- EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c);
-}
-
-TEST_F(ResolverVarLetTest, DefaultVarStorageClass) {
- // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
-
- auto* buf = Structure("S", {Member("m", ty.i32())});
- auto* function = Var("f", ty.i32());
- auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
- auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
- auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
- auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
- auto* handle = Global("h", ty.depth_texture(ast::TextureDimension::k2d),
- ast::AttributeList{
- create<ast::BindingAttribute>(2),
- create<ast::GroupAttribute>(0),
- });
-
- WrapInFunction(function);
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_TRUE(TypeOf(function)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(private_)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(workgroup)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(uniform)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(handle)->Is<sem::Reference>());
-
- EXPECT_EQ(TypeOf(function)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
- EXPECT_EQ(TypeOf(private_)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
- EXPECT_EQ(TypeOf(workgroup)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
- EXPECT_EQ(TypeOf(uniform)->As<sem::Reference>()->Access(), ast::Access::kRead);
- EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kRead);
- EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
-}
-
-TEST_F(ResolverVarLetTest, ExplicitVarStorageClass) {
- // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
-
- auto* buf = Structure("S", {Member("m", ty.i32())});
- auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
-
- EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
-}
-
-TEST_F(ResolverVarLetTest, LetInheritsAccessFromOriginatingVariable) {
- // struct Inner {
- // arr: array<i32, 4>;
- // }
- // struct S {
- // inner: Inner;
- // }
- // @group(0) @binding(0) var<storage, read_write> s : S;
- // fn f() {
- // let p = &s.inner.arr[4];
- // }
- auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
- auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
- auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
-
- auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 4_i);
- auto* ptr = Let("p", nullptr, AddressOf(expr));
-
- WrapInFunction(ptr);
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
- ASSERT_TRUE(TypeOf(ptr)->Is<sem::Pointer>());
-
- EXPECT_EQ(TypeOf(expr)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
- EXPECT_EQ(TypeOf(ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsAlias) {
- // type a = i32;
- //
- // fn X() {
- // var a = false;
- // }
- //
- // fn Y() {
- // let a = true;
- // }
-
- auto* t = Alias("a", ty.i32());
- auto* v = Var("a", nullptr, Expr(false));
- auto* l = Let("a", nullptr, Expr(false));
- Func("X", {}, ty.void_(), {Decl(v)});
- Func("Y", {}, ty.void_(), {Decl(l)});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* type_t = Sem().Get(t);
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
-
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), type_t);
- EXPECT_EQ(local_l->Shadows(), type_t);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsStruct) {
- // struct a {
- // m : i32;
- // };
- //
- // fn X() {
- // var a = true;
- // }
- //
- // fn Y() {
- // let a = false;
- // }
-
- auto* t = Structure("a", {Member("m", ty.i32())});
- auto* v = Var("a", nullptr, Expr(false));
- auto* l = Let("a", nullptr, Expr(false));
- Func("X", {}, ty.void_(), {Decl(v)});
- Func("Y", {}, ty.void_(), {Decl(l)});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* type_t = Sem().Get(t);
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
-
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), type_t);
- EXPECT_EQ(local_l->Shadows(), type_t);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsFunction) {
- // fn a() {
- // var a = true;
- // }
- //
- // fn b() {
- // let b = false;
- // }
-
- auto* v = Var("a", nullptr, Expr(false));
- auto* l = Let("b", nullptr, Expr(false));
- auto* fa = Func("a", {}, ty.void_(), {Decl(v)});
- auto* fb = Func("b", {}, ty.void_(), {Decl(l)});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
- auto* func_a = Sem().Get(fa);
- auto* func_b = Sem().Get(fb);
-
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
- ASSERT_NE(func_a, nullptr);
- ASSERT_NE(func_b, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), func_a);
- EXPECT_EQ(local_l->Shadows(), func_b);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsGlobalVar) {
- // var<private> a : i32;
- //
- // fn X() {
- // var a = a;
- // }
- //
- // fn Y() {
- // let a = a;
- // }
-
- auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
- auto* v = Var("a", nullptr, Expr("a"));
- auto* l = Let("a", nullptr, Expr("a"));
- Func("X", {}, ty.void_(), {Decl(v)});
- Func("Y", {}, ty.void_(), {Decl(l)});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* global = Sem().Get(g);
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
-
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), global);
- EXPECT_EQ(local_l->Shadows(), global);
-
- auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
- auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
-
- ASSERT_NE(user_v, nullptr);
- ASSERT_NE(user_l, nullptr);
-
- EXPECT_EQ(user_v->Variable(), global);
- EXPECT_EQ(user_l->Variable(), global);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsGlobalLet) {
- // let a : i32 = 1;
- //
- // fn X() {
- // var a = (a == 123);
- // }
- //
- // fn Y() {
- // let a = (a == 321);
- // }
-
- auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
- auto* v = Var("a", nullptr, Expr("a"));
- auto* l = Let("a", nullptr, Expr("a"));
- Func("X", {}, ty.void_(), {Decl(v)});
- Func("Y", {}, ty.void_(), {Decl(l)});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* global = Sem().Get(g);
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
-
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), global);
- EXPECT_EQ(local_l->Shadows(), global);
-
- auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
- auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
-
- ASSERT_NE(user_v, nullptr);
- ASSERT_NE(user_l, nullptr);
-
- EXPECT_EQ(user_v->Variable(), global);
- EXPECT_EQ(user_l->Variable(), global);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsLocalVar) {
- // fn X() {
- // var a : i32;
- // {
- // var a = a;
- // }
- // {
- // let a = a;
- // }
- // }
-
- auto* s = Var("a", ty.i32(), Expr(1_i));
- auto* v = Var("a", nullptr, Expr("a"));
- auto* l = Let("a", nullptr, Expr("a"));
- Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* local_s = Sem().Get<sem::LocalVariable>(s);
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
-
- ASSERT_NE(local_s, nullptr);
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), local_s);
- EXPECT_EQ(local_l->Shadows(), local_s);
-
- auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
- auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
-
- ASSERT_NE(user_v, nullptr);
- ASSERT_NE(user_l, nullptr);
-
- EXPECT_EQ(user_v->Variable(), local_s);
- EXPECT_EQ(user_l->Variable(), local_s);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsLocalLet) {
- // fn X() {
- // let a = 1;
- // {
- // var a = (a == 123);
- // }
- // {
- // let a = (a == 321);
- // }
- // }
-
- auto* s = Let("a", ty.i32(), Expr(1_i));
- auto* v = Var("a", nullptr, Expr("a"));
- auto* l = Let("a", nullptr, Expr("a"));
- Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* local_s = Sem().Get<sem::LocalVariable>(s);
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
-
- ASSERT_NE(local_s, nullptr);
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), local_s);
- EXPECT_EQ(local_l->Shadows(), local_s);
-
- auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
- auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
-
- ASSERT_NE(user_v, nullptr);
- ASSERT_NE(user_l, nullptr);
-
- EXPECT_EQ(user_v->Variable(), local_s);
- EXPECT_EQ(user_l->Variable(), local_s);
-}
-
-TEST_F(ResolverVarLetTest, LocalShadowsParam) {
- // fn F(a : i32) {
- // {
- // var a = a;
- // }
- // {
- // let a = a;
- // }
- // }
-
- auto* p = Param("a", ty.i32());
- auto* v = Var("a", nullptr, Expr("a"));
- auto* l = Let("a", nullptr, Expr("a"));
- Func("X", {p}, ty.void_(), {Block(Decl(v)), Block(Decl(l))});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* param = Sem().Get<sem::Parameter>(p);
- auto* local_v = Sem().Get<sem::LocalVariable>(v);
- auto* local_l = Sem().Get<sem::LocalVariable>(l);
-
- ASSERT_NE(param, nullptr);
- ASSERT_NE(local_v, nullptr);
- ASSERT_NE(local_l, nullptr);
-
- EXPECT_EQ(local_v->Shadows(), param);
- EXPECT_EQ(local_l->Shadows(), param);
-
- auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
- auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
-
- ASSERT_NE(user_v, nullptr);
- ASSERT_NE(user_l, nullptr);
-
- EXPECT_EQ(user_v->Variable(), param);
- EXPECT_EQ(user_l->Variable(), param);
-}
-
-TEST_F(ResolverVarLetTest, ParamShadowsFunction) {
- // fn a(a : bool) {
- // }
-
- auto* p = Param("a", ty.bool_());
- auto* f = Func("a", {p}, ty.void_(), {});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* func = Sem().Get(f);
- auto* param = Sem().Get<sem::Parameter>(p);
-
- ASSERT_NE(func, nullptr);
- ASSERT_NE(param, nullptr);
-
- EXPECT_EQ(param->Shadows(), func);
-}
-
-TEST_F(ResolverVarLetTest, ParamShadowsGlobalVar) {
- // var<private> a : i32;
- //
- // fn F(a : bool) {
- // }
-
- auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
- auto* p = Param("a", ty.bool_());
- Func("F", {p}, ty.void_(), {});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* global = Sem().Get(g);
- auto* param = Sem().Get<sem::Parameter>(p);
-
- ASSERT_NE(global, nullptr);
- ASSERT_NE(param, nullptr);
-
- EXPECT_EQ(param->Shadows(), global);
-}
-
-TEST_F(ResolverVarLetTest, ParamShadowsGlobalLet) {
- // let a : i32 = 1;
- //
- // fn F(a : bool) {
- // }
-
- auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
- auto* p = Param("a", ty.bool_());
- Func("F", {p}, ty.void_(), {});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* global = Sem().Get(g);
- auto* param = Sem().Get<sem::Parameter>(p);
-
- ASSERT_NE(global, nullptr);
- ASSERT_NE(param, nullptr);
-
- EXPECT_EQ(param->Shadows(), global);
-}
-
-TEST_F(ResolverVarLetTest, ParamShadowsAlias) {
- // type a = i32;
- //
- // fn F(a : a) {
- // }
-
- auto* a = Alias("a", ty.i32());
- auto* p = Param("a", ty.type_name("a"));
- Func("F", {p}, ty.void_(), {});
-
- ASSERT_TRUE(r()->Resolve()) << r()->error();
-
- auto* alias = Sem().Get(a);
- auto* param = Sem().Get<sem::Parameter>(p);
-
- ASSERT_NE(alias, nullptr);
- ASSERT_NE(param, nullptr);
-
- EXPECT_EQ(param->Shadows(), alias);
- EXPECT_EQ(param->Type(), alias);
-}
-
-} // namespace
-} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/var_let_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/var_let_validation_test.cc
deleted file mode 100644
index e1dc3435a4a..00000000000
--- a/chromium/third_party/dawn/src/tint/resolver/var_let_validation_test.cc
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/resolver/resolver.h"
-#include "src/tint/resolver/resolver_test_helper.h"
-
-#include "gmock/gmock.h"
-
-using namespace tint::number_suffixes; // NOLINT
-
-namespace tint::resolver {
-namespace {
-
-struct ResolverVarLetValidationTest : public resolver::TestHelper, public testing::Test {};
-
-TEST_F(ResolverVarLetValidationTest, LetNoInitializer) {
- // let a : i32;
- WrapInFunction(Let(Source{{12, 34}}, "a", ty.i32(), nullptr));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: let declaration must have an initializer");
-}
-
-TEST_F(ResolverVarLetValidationTest, GlobalLetNoInitializer) {
- // let a : i32;
- GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: let declaration must have an initializer");
-}
-
-TEST_F(ResolverVarLetValidationTest, VarNoInitializerNoType) {
- // var a;
- WrapInFunction(Var(Source{{12, 34}}, "a", nullptr));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: function scope var declaration requires a type or "
- "initializer");
-}
-
-TEST_F(ResolverVarLetValidationTest, GlobalVarNoInitializerNoType) {
- // var a;
- Global(Source{{12, 34}}, "a", nullptr);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: module scope var declaration requires a type and "
- "initializer");
-}
-
-TEST_F(ResolverVarLetValidationTest, VarTypeNotStorable) {
- // var i : i32;
- // var p : pointer<function, i32> = &v;
- auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
- auto* p = Var(Source{{56, 78}}, "a", ty.pointer<i32>(ast::StorageClass::kFunction),
- ast::StorageClass::kNone, AddressOf(Source{{12, 34}}, "i"));
- WrapInFunction(i, p);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "56:78 error: ptr<function, i32, read_write> cannot be used as the "
- "type of a var");
-}
-
-TEST_F(ResolverVarLetValidationTest, LetTypeNotConstructible) {
- // @group(0) @binding(0) var t1 : texture_2d<f32>;
- // let t2 : t1;
- auto* t1 = Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
- GroupAndBinding(0, 0));
- auto* t2 = Let(Source{{56, 78}}, "t2", nullptr, Expr(t1));
- WrapInFunction(t2);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "56:78 error: texture_2d<f32> cannot be used as the type of a let");
-}
-
-TEST_F(ResolverVarLetValidationTest, LetConstructorWrongType) {
- // var v : i32 = 2u
- WrapInFunction(Let(Source{{3, 3}}, "v", ty.i32(), Expr(2_u)));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
-}
-
-TEST_F(ResolverVarLetValidationTest, VarConstructorWrongType) {
- // var v : i32 = 2u
- WrapInFunction(Var(Source{{3, 3}}, "v", ty.i32(), ast::StorageClass::kNone, Expr(2_u)));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
-}
-
-TEST_F(ResolverVarLetValidationTest, LetConstructorWrongTypeViaAlias) {
- auto* a = Alias("I32", ty.i32());
- WrapInFunction(Let(Source{{3, 3}}, "v", ty.Of(a), Expr(2_u)));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
-}
-
-TEST_F(ResolverVarLetValidationTest, VarConstructorWrongTypeViaAlias) {
- auto* a = Alias("I32", ty.i32());
- WrapInFunction(Var(Source{{3, 3}}, "v", ty.Of(a), ast::StorageClass::kNone, Expr(2_u)));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
-}
-
-TEST_F(ResolverVarLetValidationTest, LetOfPtrConstructedWithRef) {
- // var a : f32;
- // let b : ptr<function,f32> = a;
- const auto priv = ast::StorageClass::kFunction;
- auto* var_a = Var("a", ty.f32(), priv);
- auto* var_b = Let(Source{{12, 34}}, "b", ty.pointer<f32>(priv), Expr("a"), {});
- WrapInFunction(var_a, var_b);
-
- ASSERT_FALSE(r()->Resolve());
-
- EXPECT_EQ(
- r()->error(),
- R"(12:34 error: cannot initialize let of type 'ptr<function, f32, read_write>' with value of type 'f32')");
-}
-
-TEST_F(ResolverVarLetValidationTest, LocalLetRedeclared) {
- // let l : f32 = 1.;
- // let l : i32 = 0;
- auto* l1 = Let("l", ty.f32(), Expr(1_f));
- auto* l2 = Let(Source{{12, 34}}, "l", ty.i32(), Expr(0_i));
- WrapInFunction(l1, l2);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: redeclaration of 'l'\nnote: 'l' previously declared here");
-}
-
-TEST_F(ResolverVarLetValidationTest, GlobalVarRedeclaredAsLocal) {
- // var v : f32 = 2.1;
- // fn my_func() {
- // var v : f32 = 2.0;
- // return 0;
- // }
-
- Global("v", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
-
- WrapInFunction(Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone, Expr(2_f)));
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
-TEST_F(ResolverVarLetValidationTest, VarRedeclaredInInnerBlock) {
- // {
- // var v : f32;
- // { var v : f32; }
- // }
- auto* var_outer = Var("v", ty.f32(), ast::StorageClass::kNone);
- auto* var_inner = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone);
- auto* inner = Block(Decl(var_inner));
- auto* outer_body = Block(Decl(var_outer), inner);
-
- WrapInFunction(outer_body);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
-TEST_F(ResolverVarLetValidationTest, VarRedeclaredInIfBlock) {
- // {
- // var v : f32 = 3.14;
- // if (true) { var v : f32 = 2.0; }
- // }
- auto* var_a_float = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(3.1_f));
-
- auto* var = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone, Expr(2_f));
-
- auto* cond = Expr(true);
- auto* body = Block(Decl(var));
-
- auto* outer_body = Block(Decl(var_a_float), If(cond, body));
-
- WrapInFunction(outer_body);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
-TEST_F(ResolverVarLetValidationTest, InferredPtrStorageAccessMismatch) {
- // struct Inner {
- // arr: array<i32, 4>;
- // }
- // struct S {
- // inner: Inner;
- // }
- // @group(0) @binding(0) var<storage> s : S;
- // fn f() {
- // let p : pointer<storage, i32, read_write> = &s.inner.arr[2i];
- // }
- auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
- auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
- auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
-
- auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
- auto* ptr =
- Let(Source{{12, 34}}, "p",
- ty.pointer<i32>(ast::StorageClass::kStorage, ast::Access::kReadWrite), AddressOf(expr));
-
- WrapInFunction(ptr);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: cannot initialize let of type "
- "'ptr<storage, i32, read_write>' with value of type "
- "'ptr<storage, i32, read>'");
-}
-
-TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Atomic) {
- auto* v = Var("v", ty.atomic(Source{{12, 34}}, ty.i32()));
- WrapInFunction(v);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: function variable must have a constructible type");
-}
-
-TEST_F(ResolverVarLetValidationTest, NonConstructibleType_RuntimeArray) {
- auto* s = Structure("S", {Member(Source{{56, 78}}, "m", ty.array(ty.i32()))});
- auto* v = Var(Source{{12, 34}}, "v", ty.Of(s));
- WrapInFunction(v);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
-56:78 note: while analysing structure member S.m
-12:34 note: while instantiating variable v)");
-}
-
-TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Struct_WithAtomic) {
- auto* s = Structure("S", {Member("m", ty.atomic(ty.i32()))});
- auto* v = Var("v", ty.Of(s));
- WrapInFunction(v);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: function variable must have a constructible type");
-}
-
-TEST_F(ResolverVarLetValidationTest, NonConstructibleType_InferredType) {
- // @group(0) @binding(0) var s : sampler;
- // fn foo() {
- // var v = s;
- // }
- Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 0));
- auto* v = Var(Source{{12, 34}}, "v", nullptr, Expr("s"));
- WrapInFunction(v);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: function variable must have a constructible type");
-}
-
-TEST_F(ResolverVarLetValidationTest, InvalidStorageClassForInitializer) {
- // var<workgroup> v : f32 = 1.23;
- Global(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kWorkgroup, Expr(1.23_f));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: var of storage class 'workgroup' cannot have "
- "an initializer. var initializers are only supported for the "
- "storage classes 'private' and 'function'");
-}
-
-TEST_F(ResolverVarLetValidationTest, VectorLetNoType) {
- // let a : mat3x3 = mat3x3<f32>();
- WrapInFunction(Let("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3), vec3<f32>()));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
-}
-
-TEST_F(ResolverVarLetValidationTest, VectorVarNoType) {
- // var a : mat3x3;
- WrapInFunction(Var("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3)));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
-}
-
-TEST_F(ResolverVarLetValidationTest, MatrixLetNoType) {
- // let a : mat3x3 = mat3x3<f32>();
- WrapInFunction(Let("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3), mat3x3<f32>()));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
-}
-
-TEST_F(ResolverVarLetValidationTest, MatrixVarNoType) {
- // var a : mat3x3;
- WrapInFunction(Var("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3)));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
-}
-
-} // namespace
-} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/variable_test.cc b/chromium/third_party/dawn/src/tint/resolver/variable_test.cc
new file mode 100644
index 00000000000..cc4bd6593c5
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/resolver/variable_test.cc
@@ -0,0 +1,1300 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/resolver/resolver.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/reference.h"
+
+#include "gmock/gmock.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+struct ResolverVariableTest : public resolver::TestHelper, public testing::Test {};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Function-scope 'var'
+////////////////////////////////////////////////////////////////////////////////////////////////////
+TEST_F(ResolverVariableTest, LocalVar_NoConstructor) {
+ // struct S { i : i32; }
+ // alias A = S;
+ // fn F(){
+ // var i : i32;
+ // var u : u32;
+ // var f : f32;
+ // var h : f16;
+ // var b : bool;
+ // var s : S;
+ // var a : A;
+ // }
+
+ Enable(ast::Extension::kF16);
+
+ auto* S = Structure("S", utils::Vector{Member("i", ty.i32())});
+ auto* A = Alias("A", ty.Of(S));
+
+ auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
+ auto* u = Var("u", ty.u32(), ast::StorageClass::kNone);
+ auto* f = Var("f", ty.f32(), ast::StorageClass::kNone);
+ auto* h = Var("h", ty.f16(), ast::StorageClass::kNone);
+ auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone);
+ auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone);
+ auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone);
+
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(i),
+ Decl(u),
+ Decl(f),
+ Decl(h),
+ Decl(b),
+ Decl(s),
+ Decl(a),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ // `var` declarations are always of reference type
+ ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(h)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
+
+ EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(h)->As<sem::Reference>()->StoreType()->Is<sem::F16>());
+ EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+ EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+
+ EXPECT_EQ(Sem().Get(i)->Constructor(), nullptr);
+ EXPECT_EQ(Sem().Get(u)->Constructor(), nullptr);
+ EXPECT_EQ(Sem().Get(f)->Constructor(), nullptr);
+ EXPECT_EQ(Sem().Get(h)->Constructor(), nullptr);
+ EXPECT_EQ(Sem().Get(b)->Constructor(), nullptr);
+ EXPECT_EQ(Sem().Get(s)->Constructor(), nullptr);
+ EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_WithConstructor) {
+ // struct S { i : i32; }
+ // alias A = S;
+ // fn F(){
+ // var i : i32 = 1i;
+ // var u : u32 = 1u;
+ // var f : f32 = 1.f;
+ // var h : f16 = 1.h;
+ // var b : bool = true;
+ // var s : S = S(1);
+ // var a : A = A(1);
+ // }
+
+ Enable(ast::Extension::kF16);
+
+ auto* S = Structure("S", utils::Vector{Member("i", ty.i32())});
+ auto* A = Alias("A", ty.Of(S));
+
+ auto* i_c = Expr(1_i);
+ auto* u_c = Expr(1_u);
+ auto* f_c = Expr(1_f);
+ auto* h_c = Expr(1_h);
+ auto* b_c = Expr(true);
+ auto* s_c = Construct(ty.Of(S), Expr(1_i));
+ auto* a_c = Construct(ty.Of(A), Expr(1_i));
+
+ auto* i = Var("i", ty.i32(), ast::StorageClass::kNone, i_c);
+ auto* u = Var("u", ty.u32(), ast::StorageClass::kNone, u_c);
+ auto* f = Var("f", ty.f32(), ast::StorageClass::kNone, f_c);
+ auto* h = Var("h", ty.f16(), ast::StorageClass::kNone, h_c);
+ auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone, b_c);
+ auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone, s_c);
+ auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone, a_c);
+
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(i),
+ Decl(u),
+ Decl(f),
+ Decl(h),
+ Decl(b),
+ Decl(s),
+ Decl(a),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ // `var` declarations are always of reference type
+ ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(h)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
+
+ EXPECT_EQ(TypeOf(i)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(u)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(f)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(b)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(s)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(a)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+
+ EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(h)->As<sem::Reference>()->StoreType()->Is<sem::F16>());
+ EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+ EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+
+ EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
+ EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
+ EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
+ EXPECT_EQ(Sem().Get(h)->Constructor()->Declaration(), h_c);
+ EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
+ EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
+ EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsAlias) {
+ // type a = i32;
+ //
+ // fn F() {
+ // var a = false;
+ // }
+
+ auto* t = Alias("a", ty.i32());
+ auto* v = Var("a", nullptr, Expr(false));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* type_t = Sem().Get(t);
+ auto* local = Sem().Get<sem::LocalVariable>(v);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), type_t);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsStruct) {
+ // struct a {
+ // m : i32;
+ // };
+ //
+ // fn F() {
+ // var a = true;
+ // }
+
+ auto* t = Structure("a", utils::Vector{Member("m", ty.i32())});
+ auto* v = Var("a", nullptr, Expr(false));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* type_t = Sem().Get(t);
+ auto* local = Sem().Get<sem::LocalVariable>(v);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), type_t);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsFunction) {
+ // fn a() {
+ // var a = true;
+ // }
+
+ auto* v = Var("a", nullptr, Expr(false));
+ auto* f = Func("a", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* func = Sem().Get(f);
+ ASSERT_NE(func, nullptr);
+
+ auto* local = Sem().Get<sem::LocalVariable>(v);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), func);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsGlobalVar) {
+ // var<private> a : i32;
+ //
+ // fn F() {
+ // var a = a;
+ // }
+
+ auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* v = Var("a", nullptr, Expr("a"));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* local = Sem().Get<sem::LocalVariable>(v);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), global);
+
+ auto* user_v = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
+ ASSERT_NE(user_v, nullptr);
+ EXPECT_EQ(user_v->Variable(), global);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsGlobalConst) {
+ // const a : i32 = 1i;
+ //
+ // fn X() {
+ // var a = (a == 123);
+ // }
+
+ auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
+ auto* v = Var("a", nullptr, Expr("a"));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* local = Sem().Get<sem::LocalVariable>(v);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), global);
+
+ auto* user_v = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
+ ASSERT_NE(user_v, nullptr);
+ EXPECT_EQ(user_v->Variable(), global);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsLocalVar) {
+ // fn F() {
+ // var a : i32 = 1i; // x
+ // {
+ // var a = a; // y
+ // }
+ // }
+
+ auto* x = Var("a", ty.i32(), Expr(1_i));
+ auto* y = Var("a", nullptr, Expr("a"));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(x), Block(Decl(y))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_x = Sem().Get<sem::LocalVariable>(x);
+ auto* local_y = Sem().Get<sem::LocalVariable>(y);
+
+ ASSERT_NE(local_x, nullptr);
+ ASSERT_NE(local_y, nullptr);
+ EXPECT_EQ(local_y->Shadows(), local_x);
+
+ auto* user_y = Sem().Get<sem::VariableUser>(local_y->Declaration()->constructor);
+ ASSERT_NE(user_y, nullptr);
+ EXPECT_EQ(user_y->Variable(), local_x);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsLocalConst) {
+ // fn F() {
+ // const a : i32 = 1i;
+ // {
+ // var a = (a == 123);
+ // }
+ // }
+
+ auto* c = Const("a", ty.i32(), Expr(1_i));
+ auto* v = Var("a", nullptr, Expr("a"));
+ Func("X", utils::Empty, ty.void_(), utils::Vector{Decl(c), Block(Decl(v))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_c = Sem().Get<sem::LocalVariable>(c);
+ auto* local_v = Sem().Get<sem::LocalVariable>(v);
+
+ ASSERT_NE(local_c, nullptr);
+ ASSERT_NE(local_v, nullptr);
+ EXPECT_EQ(local_v->Shadows(), local_c);
+
+ auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
+ ASSERT_NE(user_v, nullptr);
+ EXPECT_EQ(user_v->Variable(), local_c);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsLocalLet) {
+ // fn F() {
+ // let a : i32 = 1i;
+ // {
+ // var a = (a == 123);
+ // }
+ // }
+
+ auto* l = Let("a", ty.i32(), Expr(1_i));
+ auto* v = Var("a", nullptr, Expr("a"));
+ Func("X", utils::Empty, ty.void_(), utils::Vector{Decl(l), Block(Decl(v))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_l = Sem().Get<sem::LocalVariable>(l);
+ auto* local_v = Sem().Get<sem::LocalVariable>(v);
+
+ ASSERT_NE(local_l, nullptr);
+ ASSERT_NE(local_v, nullptr);
+ EXPECT_EQ(local_v->Shadows(), local_l);
+
+ auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
+ ASSERT_NE(user_v, nullptr);
+ EXPECT_EQ(user_v->Variable(), local_l);
+}
+
+TEST_F(ResolverVariableTest, LocalVar_ShadowsParam) {
+ // fn F(a : i32) {
+ // {
+ // var a = a;
+ // }
+ // }
+
+ auto* p = Param("a", ty.i32());
+ auto* v = Var("a", nullptr, Expr("a"));
+ Func("X", utils::Vector{p}, ty.void_(), utils::Vector{Block(Decl(v))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* param = Sem().Get<sem::Parameter>(p);
+ auto* local = Sem().Get<sem::LocalVariable>(v);
+
+ ASSERT_NE(param, nullptr);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), param);
+
+ auto* user_v = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
+ ASSERT_NE(user_v, nullptr);
+ EXPECT_EQ(user_v->Variable(), param);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Function-scope 'let'
+////////////////////////////////////////////////////////////////////////////////////////////////////
+TEST_F(ResolverVariableTest, LocalLet) {
+ // struct S { i : i32; }
+ // fn F(){
+ // var v : i32;
+ // let i : i32 = 1i;
+ // let u : u32 = 1u;
+ // let f : f32 = 1.f;
+ // let h : h32 = 1.h;
+ // let b : bool = true;
+ // let s : S = S(1);
+ // let a : A = A(1);
+ // let p : pointer<function, i32> = &v;
+ // }
+
+ Enable(ast::Extension::kF16);
+
+ auto* S = Structure("S", utils::Vector{Member("i", ty.i32())});
+ auto* A = Alias("A", ty.Of(S));
+ auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
+
+ auto* i_c = Expr(1_i);
+ auto* u_c = Expr(1_u);
+ auto* f_c = Expr(1_f);
+ auto* h_c = Expr(1_h);
+ auto* b_c = Expr(true);
+ auto* s_c = Construct(ty.Of(S), Expr(1_i));
+ auto* a_c = Construct(ty.Of(A), Expr(1_i));
+ auto* p_c = AddressOf(v);
+
+ auto* i = Let("i", ty.i32(), i_c);
+ auto* u = Let("u", ty.u32(), u_c);
+ auto* f = Let("f", ty.f32(), f_c);
+ auto* h = Let("h", ty.f16(), h_c);
+ auto* b = Let("b", ty.bool_(), b_c);
+ auto* s = Let("s", ty.Of(S), s_c);
+ auto* a = Let("a", ty.Of(A), a_c);
+ auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), p_c);
+
+ Func("F", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(v),
+ Decl(i),
+ Decl(u),
+ Decl(f),
+ Decl(h),
+ Decl(b),
+ Decl(s),
+ Decl(a),
+ Decl(p),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ // `let` declarations are always of the storage type
+ ASSERT_TRUE(TypeOf(i)->Is<sem::I32>());
+ ASSERT_TRUE(TypeOf(u)->Is<sem::U32>());
+ ASSERT_TRUE(TypeOf(f)->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(h)->Is<sem::F16>());
+ ASSERT_TRUE(TypeOf(b)->Is<sem::Bool>());
+ ASSERT_TRUE(TypeOf(s)->Is<sem::Struct>());
+ ASSERT_TRUE(TypeOf(a)->Is<sem::Struct>());
+ ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(p)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
+
+ EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
+ EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
+ EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
+ EXPECT_EQ(Sem().Get(h)->Constructor()->Declaration(), h_c);
+ EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
+ EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
+ EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
+ EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_InheritsAccessFromOriginatingVariable) {
+ // struct Inner {
+ // arr: array<i32, 4>;
+ // }
+ // struct S {
+ // inner: Inner;
+ // }
+ // @group(0) @binding(0) var<storage, read_write> s : S;
+ // fn f() {
+ // let p = &s.inner.arr[4];
+ // }
+ auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
+ auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
+ auto* storage = GlobalVar("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 4_i);
+ auto* ptr = Let("p", nullptr, AddressOf(expr));
+
+ WrapInFunction(ptr);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(ptr)->Is<sem::Pointer>());
+
+ EXPECT_EQ(TypeOf(expr)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsAlias) {
+ // type a = i32;
+ //
+ // fn F() {
+ // let a = true;
+ // }
+
+ auto* t = Alias("a", ty.i32());
+ auto* l = Let("a", nullptr, Expr(false));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* type_t = Sem().Get(t);
+ auto* local = Sem().Get<sem::LocalVariable>(l);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), type_t);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsStruct) {
+ // struct a {
+ // m : i32;
+ // };
+ //
+ // fn F() {
+ // let a = false;
+ // }
+
+ auto* t = Structure("a", utils::Vector{Member("m", ty.i32())});
+ auto* l = Let("a", nullptr, Expr(false));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* type_t = Sem().Get(t);
+ auto* local = Sem().Get<sem::LocalVariable>(l);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), type_t);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsFunction) {
+ // fn a() {
+ // let a = false;
+ // }
+
+ auto* l = Let("a", nullptr, Expr(false));
+ auto* fb = Func("a", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* func = Sem().Get(fb);
+ ASSERT_NE(func, nullptr);
+
+ auto* local = Sem().Get<sem::LocalVariable>(l);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), func);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsGlobalVar) {
+ // var<private> a : i32;
+ //
+ // fn F() {
+ // let a = a;
+ // }
+
+ auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* l = Let("a", nullptr, Expr("a"));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* local = Sem().Get<sem::LocalVariable>(l);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), global);
+
+ auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), global);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsGlobalConst) {
+ // const a : i32 = 1i;
+ //
+ // fn F() {
+ // let a = a;
+ // }
+
+ auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
+ auto* l = Let("a", nullptr, Expr("a"));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* local = Sem().Get<sem::LocalVariable>(l);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), global);
+
+ auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), global);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsLocalVar) {
+ // fn F() {
+ // var a : i32 = 1i;
+ // {
+ // let a = a;
+ // }
+ // }
+
+ auto* v = Var("a", ty.i32(), Expr(1_i));
+ auto* l = Let("a", nullptr, Expr("a"));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v), Block(Decl(l))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_v = Sem().Get<sem::LocalVariable>(v);
+ auto* local_l = Sem().Get<sem::LocalVariable>(l);
+
+ ASSERT_NE(local_v, nullptr);
+ ASSERT_NE(local_l, nullptr);
+ EXPECT_EQ(local_l->Shadows(), local_v);
+
+ auto* user = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), local_v);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsLocalConst) {
+ // fn X() {
+ // const a : i32 = 1i; // x
+ // {
+ // let a = a; // y
+ // }
+ // }
+
+ auto* x = Const("a", ty.i32(), Expr(1_i));
+ auto* y = Let("a", nullptr, Expr("a"));
+ Func("X", utils::Empty, ty.void_(), utils::Vector{Decl(x), Block(Decl(y))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_x = Sem().Get<sem::LocalVariable>(x);
+ auto* local_y = Sem().Get<sem::LocalVariable>(y);
+
+ ASSERT_NE(local_x, nullptr);
+ ASSERT_NE(local_y, nullptr);
+ EXPECT_EQ(local_y->Shadows(), local_x);
+
+ auto* user = Sem().Get<sem::VariableUser>(local_y->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), local_x);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsLocalLet) {
+ // fn X() {
+ // let a : i32 = 1i; // x
+ // {
+ // let a = a; // y
+ // }
+ // }
+
+ auto* x = Let("a", ty.i32(), Expr(1_i));
+ auto* y = Let("a", nullptr, Expr("a"));
+ Func("X", utils::Empty, ty.void_(), utils::Vector{Decl(x), Block(Decl(y))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_x = Sem().Get<sem::LocalVariable>(x);
+ auto* local_y = Sem().Get<sem::LocalVariable>(y);
+
+ ASSERT_NE(local_x, nullptr);
+ ASSERT_NE(local_y, nullptr);
+ EXPECT_EQ(local_y->Shadows(), local_x);
+
+ auto* user = Sem().Get<sem::VariableUser>(local_y->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), local_x);
+}
+
+TEST_F(ResolverVariableTest, LocalLet_ShadowsParam) {
+ // fn F(a : i32) {
+ // {
+ // let a = a;
+ // }
+ // }
+
+ auto* p = Param("a", ty.i32());
+ auto* l = Let("a", nullptr, Expr("a"));
+ Func("X", utils::Vector{p}, ty.void_(), utils::Vector{Block(Decl(l))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* param = Sem().Get<sem::Parameter>(p);
+ auto* local = Sem().Get<sem::LocalVariable>(l);
+
+ ASSERT_NE(param, nullptr);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), param);
+
+ auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), param);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Function-scope const
+////////////////////////////////////////////////////////////////////////////////////////////////////
+TEST_F(ResolverVariableTest, LocalConst_ShadowsAlias) {
+ // type a = i32;
+ //
+ // fn F() {
+ // const a = true;
+ // }
+
+ auto* t = Alias("a", ty.i32());
+ auto* c = Const("a", nullptr, Expr(false));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* type_t = Sem().Get(t);
+ auto* local = Sem().Get<sem::LocalVariable>(c);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), type_t);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsStruct) {
+ // struct a {
+ // m : i32;
+ // };
+ //
+ // fn F() {
+ // const a = false;
+ // }
+
+ auto* t = Structure("a", utils::Vector{Member("m", ty.i32())});
+ auto* c = Const("a", nullptr, Expr(false));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* type_t = Sem().Get(t);
+ auto* local = Sem().Get<sem::LocalVariable>(c);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), type_t);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsFunction) {
+ // fn a() {
+ // const a = false;
+ // }
+
+ auto* c = Const("a", nullptr, Expr(false));
+ auto* fb = Func("a", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* func = Sem().Get(fb);
+ ASSERT_NE(func, nullptr);
+
+ auto* local = Sem().Get<sem::LocalVariable>(c);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), func);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsGlobalVar) {
+ // var<private> a : i32;
+ //
+ // fn F() {
+ // const a = 1i;
+ // }
+
+ auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* c = Const("a", nullptr, Expr(1_i));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* local = Sem().Get<sem::LocalVariable>(c);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), global);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsGlobalConst) {
+ // const a : i32 = 1i;
+ //
+ // fn F() {
+ // const a = a;
+ // }
+
+ auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
+ auto* c = Const("a", nullptr, Expr("a"));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* local = Sem().Get<sem::LocalVariable>(c);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), global);
+
+ auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), global);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsLocalVar) {
+ // fn F() {
+ // var a = 1i;
+ // {
+ // const a = 1i;
+ // }
+ // }
+
+ auto* v = Var("a", ty.i32(), Expr(1_i));
+ auto* c = Const("a", nullptr, Expr(1_i));
+ Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v), Block(Decl(c))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_v = Sem().Get<sem::LocalVariable>(v);
+ auto* local_c = Sem().Get<sem::LocalVariable>(c);
+
+ ASSERT_NE(local_v, nullptr);
+ ASSERT_NE(local_c, nullptr);
+ EXPECT_EQ(local_c->Shadows(), local_v);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsLocalConst) {
+ // fn X() {
+ // const a = 1i; // x
+ // {
+ // const a = a; // y
+ // }
+ // }
+
+ auto* x = Const("a", ty.i32(), Expr(1_i));
+ auto* y = Const("a", nullptr, Expr("a"));
+ Func("X", utils::Empty, ty.void_(), utils::Vector{Decl(x), Block(Decl(y))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_x = Sem().Get<sem::LocalVariable>(x);
+ auto* local_y = Sem().Get<sem::LocalVariable>(y);
+
+ ASSERT_NE(local_x, nullptr);
+ ASSERT_NE(local_y, nullptr);
+ EXPECT_EQ(local_y->Shadows(), local_x);
+
+ auto* user = Sem().Get<sem::VariableUser>(local_y->Declaration()->constructor);
+ ASSERT_NE(user, nullptr);
+ EXPECT_EQ(user->Variable(), local_x);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsLocalLet) {
+ // fn X() {
+ // let a = 1i; // x
+ // {
+ // const a = 1i; // y
+ // }
+ // }
+
+ auto* l = Let("a", ty.i32(), Expr(1_i));
+ auto* c = Const("a", nullptr, Expr(1_i));
+ Func("X", utils::Empty, ty.void_(), utils::Vector{Decl(l), Block(Decl(c))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* local_l = Sem().Get<sem::LocalVariable>(l);
+ auto* local_c = Sem().Get<sem::LocalVariable>(c);
+
+ ASSERT_NE(local_l, nullptr);
+ ASSERT_NE(local_c, nullptr);
+ EXPECT_EQ(local_c->Shadows(), local_l);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ShadowsParam) {
+ // fn F(a : i32) {
+ // {
+ // const a = 1i;
+ // }
+ // }
+
+ auto* p = Param("a", ty.i32());
+ auto* c = Const("a", nullptr, Expr(1_i));
+ Func("X", utils::Vector{p}, ty.void_(), utils::Vector{Block(Decl(c))});
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* param = Sem().Get<sem::Parameter>(p);
+ auto* local = Sem().Get<sem::LocalVariable>(c);
+
+ ASSERT_NE(param, nullptr);
+ ASSERT_NE(local, nullptr);
+ EXPECT_EQ(local->Shadows(), param);
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ExplicitType_Decls) {
+ Structure("S", utils::Vector{Member("m", ty.u32())});
+
+ auto* c_i32 = Const("a", ty.i32(), Expr(0_i));
+ auto* c_u32 = Const("b", ty.u32(), Expr(0_u));
+ auto* c_f32 = Const("c", ty.f32(), Expr(0_f));
+ auto* c_vi32 = Const("d", ty.vec3<i32>(), vec3<i32>());
+ auto* c_vu32 = Const("e", ty.vec3<u32>(), vec3<u32>());
+ auto* c_vf32 = Const("f", ty.vec3<f32>(), vec3<f32>());
+ auto* c_mf32 = Const("g", ty.mat3x3<f32>(), mat3x3<f32>());
+ auto* c_s = Const("h", ty.type_name("S"), Construct(ty.type_name("S")));
+
+ WrapInFunction(c_i32, c_u32, c_f32, c_vi32, c_vu32, c_vf32, c_mf32, c_s);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ EXPECT_EQ(Sem().Get(c_i32)->Declaration(), c_i32);
+ EXPECT_EQ(Sem().Get(c_u32)->Declaration(), c_u32);
+ EXPECT_EQ(Sem().Get(c_f32)->Declaration(), c_f32);
+ EXPECT_EQ(Sem().Get(c_vi32)->Declaration(), c_vi32);
+ EXPECT_EQ(Sem().Get(c_vu32)->Declaration(), c_vu32);
+ EXPECT_EQ(Sem().Get(c_vf32)->Declaration(), c_vf32);
+ EXPECT_EQ(Sem().Get(c_mf32)->Declaration(), c_mf32);
+ EXPECT_EQ(Sem().Get(c_s)->Declaration(), c_s);
+
+ ASSERT_TRUE(TypeOf(c_i32)->Is<sem::I32>());
+ ASSERT_TRUE(TypeOf(c_u32)->Is<sem::U32>());
+ ASSERT_TRUE(TypeOf(c_f32)->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(c_vi32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vu32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vf32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
+ ASSERT_TRUE(TypeOf(c_s)->Is<sem::Struct>());
+
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_s)->ConstantValue()->AllZero());
+}
+
+TEST_F(ResolverVariableTest, LocalConst_ImplicitType_Decls) {
+ Structure("S", utils::Vector{Member("m", ty.u32())});
+
+ auto* c_i32 = Const("a", nullptr, Expr(0_i));
+ auto* c_u32 = Const("b", nullptr, Expr(0_u));
+ auto* c_f32 = Const("c", nullptr, Expr(0_f));
+ auto* c_ai = Const("d", nullptr, Expr(0_a));
+ auto* c_af = Const("e", nullptr, Expr(0._a));
+ auto* c_vi32 = Const("f", nullptr, vec3<i32>());
+ auto* c_vu32 = Const("g", nullptr, vec3<u32>());
+ auto* c_vf32 = Const("h", nullptr, vec3<f32>());
+ auto* c_vai = Const("i", nullptr, Construct(ty.vec(nullptr, 3), Expr(0_a)));
+ auto* c_vaf = Const("j", nullptr, Construct(ty.vec(nullptr, 3), Expr(0._a)));
+ auto* c_mf32 = Const("k", nullptr, mat3x3<f32>());
+ auto* c_maf32 = Const("l", nullptr,
+ Construct(ty.mat(nullptr, 3, 3), //
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a))));
+ auto* c_s = Const("m", nullptr, Construct(ty.type_name("S")));
+
+ WrapInFunction(c_i32, c_u32, c_f32, c_ai, c_af, c_vi32, c_vu32, c_vf32, c_vai, c_vaf, c_mf32,
+ c_maf32, c_s);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ EXPECT_EQ(Sem().Get(c_i32)->Declaration(), c_i32);
+ EXPECT_EQ(Sem().Get(c_u32)->Declaration(), c_u32);
+ EXPECT_EQ(Sem().Get(c_f32)->Declaration(), c_f32);
+ EXPECT_EQ(Sem().Get(c_ai)->Declaration(), c_ai);
+ EXPECT_EQ(Sem().Get(c_af)->Declaration(), c_af);
+ EXPECT_EQ(Sem().Get(c_vi32)->Declaration(), c_vi32);
+ EXPECT_EQ(Sem().Get(c_vu32)->Declaration(), c_vu32);
+ EXPECT_EQ(Sem().Get(c_vf32)->Declaration(), c_vf32);
+ EXPECT_EQ(Sem().Get(c_vai)->Declaration(), c_vai);
+ EXPECT_EQ(Sem().Get(c_vaf)->Declaration(), c_vaf);
+ EXPECT_EQ(Sem().Get(c_mf32)->Declaration(), c_mf32);
+ EXPECT_EQ(Sem().Get(c_maf32)->Declaration(), c_maf32);
+ EXPECT_EQ(Sem().Get(c_s)->Declaration(), c_s);
+
+ ASSERT_TRUE(TypeOf(c_i32)->Is<sem::I32>());
+ ASSERT_TRUE(TypeOf(c_u32)->Is<sem::U32>());
+ ASSERT_TRUE(TypeOf(c_f32)->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(c_ai)->Is<sem::AbstractInt>());
+ ASSERT_TRUE(TypeOf(c_af)->Is<sem::AbstractFloat>());
+ ASSERT_TRUE(TypeOf(c_vi32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vu32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vf32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vai)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vaf)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
+ ASSERT_TRUE(TypeOf(c_maf32)->Is<sem::Matrix>());
+ ASSERT_TRUE(TypeOf(c_s)->Is<sem::Struct>());
+
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_ai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_af)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vaf)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_maf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_s)->ConstantValue()->AllZero());
+}
+
+TEST_F(ResolverVariableTest, LocalConst_PropagateConstValue) {
+ auto* a = Const("a", nullptr, Expr(42_i));
+ auto* b = Const("b", nullptr, Expr("a"));
+ auto* c = Const("c", nullptr, Expr("b"));
+
+ WrapInFunction(a, b, c);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
+
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 42_i);
+}
+
+// Enable when we have @const operators implemented
+TEST_F(ResolverVariableTest, DISABLED_LocalConst_ConstEval) {
+ auto* c = Const("c", nullptr, Div(Mul(Add(1_i, 2_i), 3_i), 2_i));
+
+ WrapInFunction(c);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
+
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 3_i);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Module-scope 'var'
+////////////////////////////////////////////////////////////////////////////////////////////////////
+TEST_F(ResolverVariableTest, GlobalVar_StorageClass) {
+ // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
+
+ auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
+ auto* private_ = GlobalVar("p", ty.i32(), ast::StorageClass::kPrivate);
+ auto* workgroup = GlobalVar("w", ty.i32(), ast::StorageClass::kWorkgroup);
+ auto* uniform = GlobalVar("ub", ty.Of(buf), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+ auto* storage = GlobalVar("sb", ty.Of(buf), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
+ auto* handle = GlobalVar("h", ty.depth_texture(ast::TextureDimension::k2d),
+ utils::Vector{
+ create<ast::BindingAttribute>(2u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(private_)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(workgroup)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(uniform)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(handle)->Is<sem::Reference>());
+
+ EXPECT_EQ(TypeOf(private_)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(workgroup)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+ EXPECT_EQ(TypeOf(uniform)->As<sem::Reference>()->Access(), ast::Access::kRead);
+ EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kRead);
+ EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
+}
+
+TEST_F(ResolverVariableTest, GlobalVar_ExplicitStorageClass) {
+ // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
+
+ auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
+ auto* storage =
+ GlobalVar("sb", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
+
+ EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Module-scope const
+////////////////////////////////////////////////////////////////////////////////////////////////////
+TEST_F(ResolverVariableTest, GlobalConst_ExplicitType_Decls) {
+ auto* c_i32 = GlobalConst("a", ty.i32(), Expr(0_i));
+ auto* c_u32 = GlobalConst("b", ty.u32(), Expr(0_u));
+ auto* c_f32 = GlobalConst("c", ty.f32(), Expr(0_f));
+ auto* c_vi32 = GlobalConst("d", ty.vec3<i32>(), vec3<i32>());
+ auto* c_vu32 = GlobalConst("e", ty.vec3<u32>(), vec3<u32>());
+ auto* c_vf32 = GlobalConst("f", ty.vec3<f32>(), vec3<f32>());
+ auto* c_mf32 = GlobalConst("g", ty.mat3x3<f32>(), mat3x3<f32>());
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ EXPECT_EQ(Sem().Get(c_i32)->Declaration(), c_i32);
+ EXPECT_EQ(Sem().Get(c_u32)->Declaration(), c_u32);
+ EXPECT_EQ(Sem().Get(c_f32)->Declaration(), c_f32);
+ EXPECT_EQ(Sem().Get(c_vi32)->Declaration(), c_vi32);
+ EXPECT_EQ(Sem().Get(c_vu32)->Declaration(), c_vu32);
+ EXPECT_EQ(Sem().Get(c_vf32)->Declaration(), c_vf32);
+ EXPECT_EQ(Sem().Get(c_mf32)->Declaration(), c_mf32);
+
+ ASSERT_TRUE(TypeOf(c_i32)->Is<sem::I32>());
+ ASSERT_TRUE(TypeOf(c_u32)->Is<sem::U32>());
+ ASSERT_TRUE(TypeOf(c_f32)->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(c_vi32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vu32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vf32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
+
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
+}
+
+TEST_F(ResolverVariableTest, GlobalConst_ImplicitType_Decls) {
+ auto* c_i32 = GlobalConst("a", nullptr, Expr(0_i));
+ auto* c_u32 = GlobalConst("b", nullptr, Expr(0_u));
+ auto* c_f32 = GlobalConst("c", nullptr, Expr(0_f));
+ auto* c_ai = GlobalConst("d", nullptr, Expr(0_a));
+ auto* c_af = GlobalConst("e", nullptr, Expr(0._a));
+ auto* c_vi32 = GlobalConst("f", nullptr, vec3<i32>());
+ auto* c_vu32 = GlobalConst("g", nullptr, vec3<u32>());
+ auto* c_vf32 = GlobalConst("h", nullptr, vec3<f32>());
+ auto* c_vai = GlobalConst("i", nullptr, Construct(ty.vec(nullptr, 3), Expr(0_a)));
+ auto* c_vaf = GlobalConst("j", nullptr, Construct(ty.vec(nullptr, 3), Expr(0._a)));
+ auto* c_mf32 = GlobalConst("k", nullptr, mat3x3<f32>());
+ auto* c_maf32 = GlobalConst("l", nullptr,
+ Construct(ty.mat(nullptr, 3, 3), //
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a))));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ EXPECT_EQ(Sem().Get(c_i32)->Declaration(), c_i32);
+ EXPECT_EQ(Sem().Get(c_u32)->Declaration(), c_u32);
+ EXPECT_EQ(Sem().Get(c_f32)->Declaration(), c_f32);
+ EXPECT_EQ(Sem().Get(c_ai)->Declaration(), c_ai);
+ EXPECT_EQ(Sem().Get(c_af)->Declaration(), c_af);
+ EXPECT_EQ(Sem().Get(c_vi32)->Declaration(), c_vi32);
+ EXPECT_EQ(Sem().Get(c_vu32)->Declaration(), c_vu32);
+ EXPECT_EQ(Sem().Get(c_vf32)->Declaration(), c_vf32);
+ EXPECT_EQ(Sem().Get(c_vai)->Declaration(), c_vai);
+ EXPECT_EQ(Sem().Get(c_vaf)->Declaration(), c_vaf);
+ EXPECT_EQ(Sem().Get(c_mf32)->Declaration(), c_mf32);
+ EXPECT_EQ(Sem().Get(c_maf32)->Declaration(), c_maf32);
+
+ ASSERT_TRUE(TypeOf(c_i32)->Is<sem::I32>());
+ ASSERT_TRUE(TypeOf(c_u32)->Is<sem::U32>());
+ ASSERT_TRUE(TypeOf(c_f32)->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(c_ai)->Is<sem::AbstractInt>());
+ ASSERT_TRUE(TypeOf(c_af)->Is<sem::AbstractFloat>());
+ ASSERT_TRUE(TypeOf(c_vi32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vu32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vf32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vai)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_vaf)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
+ ASSERT_TRUE(TypeOf(c_maf32)->Is<sem::Matrix>());
+
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_ai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_af)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vaf)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_maf32)->ConstantValue()->AllZero());
+}
+
+TEST_F(ResolverVariableTest, GlobalConst_PropagateConstValue) {
+ GlobalConst("b", nullptr, Expr("a"));
+ auto* c = GlobalConst("c", nullptr, Expr("b"));
+ GlobalConst("a", nullptr, Expr(42_i));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
+
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 42_i);
+}
+
+// Enable when we have @const operators implemented
+TEST_F(ResolverVariableTest, DISABLED_GlobalConst_ConstEval) {
+ auto* c = GlobalConst("c", nullptr, Div(Mul(Add(1_i, 2_i), 3_i), 2_i));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
+
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 3_i);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Function parameter
+////////////////////////////////////////////////////////////////////////////////////////////////////
+TEST_F(ResolverVariableTest, Param_ShadowsFunction) {
+ // fn a(a : bool) {
+ // }
+
+ auto* p = Param("a", ty.bool_());
+ auto* f = Func("a", utils::Vector{p}, ty.void_(), utils::Empty);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* func = Sem().Get(f);
+ auto* param = Sem().Get<sem::Parameter>(p);
+
+ ASSERT_NE(func, nullptr);
+ ASSERT_NE(param, nullptr);
+
+ EXPECT_EQ(param->Shadows(), func);
+}
+
+TEST_F(ResolverVariableTest, Param_ShadowsGlobalVar) {
+ // var<private> a : i32;
+ //
+ // fn F(a : bool) {
+ // }
+
+ auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* p = Param("a", ty.bool_());
+ Func("F", utils::Vector{p}, ty.void_(), utils::Empty);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* param = Sem().Get<sem::Parameter>(p);
+
+ ASSERT_NE(global, nullptr);
+ ASSERT_NE(param, nullptr);
+
+ EXPECT_EQ(param->Shadows(), global);
+}
+
+TEST_F(ResolverVariableTest, Param_ShadowsGlobalConst) {
+ // const a : i32 = 1i;
+ //
+ // fn F(a : bool) {
+ // }
+
+ auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
+ auto* p = Param("a", ty.bool_());
+ Func("F", utils::Vector{p}, ty.void_(), utils::Empty);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* global = Sem().Get(g);
+ auto* param = Sem().Get<sem::Parameter>(p);
+
+ ASSERT_NE(global, nullptr);
+ ASSERT_NE(param, nullptr);
+
+ EXPECT_EQ(param->Shadows(), global);
+}
+
+TEST_F(ResolverVariableTest, Param_ShadowsAlias) {
+ // type a = i32;
+ //
+ // fn F(a : a) {
+ // }
+
+ auto* a = Alias("a", ty.i32());
+ auto* p = Param("a", ty.type_name("a"));
+ Func("F", utils::Vector{p}, ty.void_(), utils::Empty);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* alias = Sem().Get(a);
+ auto* param = Sem().Get<sem::Parameter>(p);
+
+ ASSERT_NE(alias, nullptr);
+ ASSERT_NE(param, nullptr);
+
+ EXPECT_EQ(param->Shadows(), alias);
+ EXPECT_EQ(param->Type(), alias);
+}
+
+} // namespace
+} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/resolver/variable_validation_test.cc b/chromium/third_party/dawn/src/tint/resolver/variable_validation_test.cc
new file mode 100644
index 00000000000..97b177ec8dc
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/resolver/variable_validation_test.cc
@@ -0,0 +1,454 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/resolver/resolver.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+
+#include "gmock/gmock.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+struct ResolverVariableValidationTest : public resolver::TestHelper, public testing::Test {};
+
+TEST_F(ResolverVariableValidationTest, VarNoInitializerNoType) {
+ // var a;
+ WrapInFunction(Var(Source{{12, 34}}, "a", nullptr));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: var declaration requires a type or initializer");
+}
+
+TEST_F(ResolverVariableValidationTest, GlobalVarNoInitializerNoType) {
+ // var a;
+ GlobalVar(Source{{12, 34}}, "a", nullptr);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: var declaration requires a type or initializer");
+}
+
+TEST_F(ResolverVariableValidationTest, VarInitializerNoReturnValueBuiltin) {
+ // fn f() { var a = storageBarrier(); }
+ auto* NoReturnValueBuiltin = Call(Source{{12, 34}}, "storageBarrier");
+ WrapInFunction(Var("a", nullptr, ast::StorageClass::kNone, NoReturnValueBuiltin));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: builtin 'storageBarrier' does not return a value");
+}
+
+TEST_F(ResolverVariableValidationTest, GlobalVarInitializerNoReturnValueBuiltin) {
+ // var a = storageBarrier();
+ auto* NoReturnValueBuiltin = Call(Source{{12, 34}}, "storageBarrier");
+ GlobalVar("a", nullptr, ast::StorageClass::kNone, NoReturnValueBuiltin);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: builtin 'storageBarrier' does not return a value");
+}
+
+TEST_F(ResolverVariableValidationTest, GlobalVarUsedAtModuleScope) {
+ // var<private> a : i32;
+ // var<private> b : i32 = a;
+ GlobalVar(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kPrivate, nullptr);
+ GlobalVar("b", ty.i32(), ast::StorageClass::kPrivate, Expr(Source{{56, 78}}, "a"));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(56:78 error: var 'a' cannot not be referenced at module-scope
+12:34 note: var 'a' declared here)");
+}
+
+TEST_F(ResolverVariableValidationTest, OverrideNoInitializerNoType) {
+ // override a;
+ Override(Source{{12, 34}}, "a", nullptr, nullptr);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: override declaration requires a type or initializer");
+}
+
+TEST_F(ResolverVariableValidationTest, OverrideExceedsIDLimit_LastUnreserved) {
+ // override o0 : i32;
+ // override o1 : i32;
+ // ...
+ // override bang : i32;
+ constexpr size_t kLimit = std::numeric_limits<decltype(OverrideId::value)>::max();
+ for (size_t i = 0; i <= kLimit; i++) {
+ Override("o" + std::to_string(i), ty.i32(), nullptr);
+ }
+ Override(Source{{12, 34}}, "bang", ty.i32(), nullptr);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: number of 'override' variables exceeded limit of 65535");
+}
+
+TEST_F(ResolverVariableValidationTest, OverrideExceedsIDLimit_LastReserved) {
+ // override o0 : i32;
+ // override o1 : i32;
+ // ...
+ // @id(N) override oN : i32;
+ constexpr size_t kLimit = std::numeric_limits<decltype(OverrideId::value)>::max();
+ Override("reserved", ty.i32(), nullptr,
+ utils::Vector{
+ Id(kLimit),
+ });
+ for (size_t i = 0; i < kLimit; i++) {
+ Override("o" + std::to_string(i), ty.i32(), nullptr);
+ }
+ Override(Source{{12, 34}}, "bang", ty.i32(), nullptr);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: number of 'override' variables exceeded limit of 65535");
+}
+
+TEST_F(ResolverVariableValidationTest, VarTypeNotConstructible) {
+ // var i : i32;
+ // var p : pointer<function, i32> = &v;
+ auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
+ auto* p = Var("a", ty.pointer<i32>(Source{{56, 78}}, ast::StorageClass::kFunction),
+ ast::StorageClass::kNone, AddressOf(Source{{12, 34}}, "i"));
+ WrapInFunction(i, p);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "56:78 error: function-scope 'var' must have a constructible type");
+}
+
+TEST_F(ResolverVariableValidationTest, LetTypeNotConstructible) {
+ // @group(0) @binding(0) var t1 : texture_2d<f32>;
+ // let t2 : t1;
+ auto* t1 = GlobalVar("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+ GroupAndBinding(0, 0));
+ auto* t2 = Let(Source{{56, 78}}, "t2", nullptr, Expr(t1));
+ WrapInFunction(t2);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "56:78 error: texture_2d<f32> cannot be used as the type of a 'let'");
+}
+
+TEST_F(ResolverVariableValidationTest, OverrideExplicitTypeNotScalar) {
+ // override o : vec3<f32>;
+ Override(Source{{56, 78}}, "o", ty.vec3<f32>(), nullptr);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "56:78 error: vec3<f32> cannot be used as the type of a 'override'");
+}
+
+TEST_F(ResolverVariableValidationTest, OverrideInferedTypeNotScalar) {
+ // override o = vec3(1.0f);
+ Override(Source{{56, 78}}, "o", nullptr, vec3<f32>(1.0_f));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "56:78 error: vec3<f32> cannot be used as the type of a 'override'");
+}
+
+TEST_F(ResolverVariableValidationTest, ConstConstructorWrongType) {
+ // const c : i32 = 2u
+ WrapInFunction(Const(Source{{3, 3}}, "c", ty.i32(), Expr(2_u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(3:3 error: cannot initialize const of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVariableValidationTest, LetConstructorWrongType) {
+ // var v : i32 = 2u
+ WrapInFunction(Let(Source{{3, 3}}, "v", ty.i32(), Expr(2_u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVariableValidationTest, VarConstructorWrongType) {
+ // var v : i32 = 2u
+ WrapInFunction(Var(Source{{3, 3}}, "v", ty.i32(), ast::StorageClass::kNone, Expr(2_u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVariableValidationTest, ConstConstructorWrongTypeViaAlias) {
+ auto* a = Alias("I32", ty.i32());
+ WrapInFunction(Const(Source{{3, 3}}, "v", ty.Of(a), Expr(2_u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(3:3 error: cannot initialize const of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVariableValidationTest, LetConstructorWrongTypeViaAlias) {
+ auto* a = Alias("I32", ty.i32());
+ WrapInFunction(Let(Source{{3, 3}}, "v", ty.Of(a), Expr(2_u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVariableValidationTest, VarConstructorWrongTypeViaAlias) {
+ auto* a = Alias("I32", ty.i32());
+ WrapInFunction(Var(Source{{3, 3}}, "v", ty.Of(a), ast::StorageClass::kNone, Expr(2_u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVariableValidationTest, LetOfPtrConstructedWithRef) {
+ // var a : f32;
+ // let b : ptr<function,f32> = a;
+ const auto priv = ast::StorageClass::kFunction;
+ auto* var_a = Var("a", ty.f32(), priv);
+ auto* var_b = Let(Source{{12, 34}}, "b", ty.pointer<f32>(priv), Expr("a"), {});
+ WrapInFunction(var_a, var_b);
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: cannot initialize let of type 'ptr<function, f32, read_write>' with value of type 'f32')");
+}
+
+TEST_F(ResolverVariableValidationTest, LocalLetRedeclared) {
+ // let l : f32 = 1.;
+ // let l : i32 = 0;
+ auto* l1 = Let("l", ty.f32(), Expr(1_f));
+ auto* l2 = Let(Source{{12, 34}}, "l", ty.i32(), Expr(0_i));
+ WrapInFunction(l1, l2);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: redeclaration of 'l'\nnote: 'l' previously declared here");
+}
+
+TEST_F(ResolverVariableValidationTest, GlobalVarRedeclaredAsLocal) {
+ // var v : f32 = 2.1;
+ // fn my_func() {
+ // var v : f32 = 2.0;
+ // return 0;
+ // }
+
+ GlobalVar("v", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
+
+ WrapInFunction(Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone, Expr(2_f)));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverVariableValidationTest, VarRedeclaredInInnerBlock) {
+ // {
+ // var v : f32;
+ // { var v : f32; }
+ // }
+ auto* var_outer = Var("v", ty.f32(), ast::StorageClass::kNone);
+ auto* var_inner = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone);
+ auto* inner = Block(Decl(var_inner));
+ auto* outer_body = Block(Decl(var_outer), inner);
+
+ WrapInFunction(outer_body);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverVariableValidationTest, VarRedeclaredInIfBlock) {
+ // {
+ // var v : f32 = 3.14;
+ // if (true) { var v : f32 = 2.0; }
+ // }
+ auto* var_a_float = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(3.1_f));
+
+ auto* var = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone, Expr(2_f));
+
+ auto* cond = Expr(true);
+ auto* body = Block(Decl(var));
+
+ auto* outer_body = Block(Decl(var_a_float), If(cond, body));
+
+ WrapInFunction(outer_body);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverVariableValidationTest, InferredPtrStorageAccessMismatch) {
+ // struct Inner {
+ // arr: array<i32, 4>;
+ // }
+ // struct S {
+ // inner: Inner;
+ // }
+ // @group(0) @binding(0) var<storage> s : S;
+ // fn f() {
+ // let p : pointer<storage, i32, read_write> = &s.inner.arr[2i];
+ // }
+ auto* inner = Structure("Inner", utils::Vector{
+ Member("arr", ty.array<i32, 4>()),
+ });
+ auto* buf = Structure("S", utils::Vector{
+ Member("inner", ty.Of(inner)),
+ });
+ auto* storage = GlobalVar("s", ty.Of(buf), ast::StorageClass::kStorage,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
+ auto* ptr =
+ Let(Source{{12, 34}}, "p",
+ ty.pointer<i32>(ast::StorageClass::kStorage, ast::Access::kReadWrite), AddressOf(expr));
+
+ WrapInFunction(ptr);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: cannot initialize let of type "
+ "'ptr<storage, i32, read_write>' with value of type "
+ "'ptr<storage, i32, read>'");
+}
+
+TEST_F(ResolverVariableValidationTest, NonConstructibleType_Atomic) {
+ auto* v = Var("v", ty.atomic(Source{{12, 34}}, ty.i32()));
+ WrapInFunction(v);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: function-scope 'var' must have a constructible type");
+}
+
+TEST_F(ResolverVariableValidationTest, NonConstructibleType_RuntimeArray) {
+ auto* s = Structure("S", utils::Vector{
+ Member(Source{{56, 78}}, "m", ty.array(ty.i32())),
+ });
+ auto* v = Var(Source{{12, 34}}, "v", ty.Of(s));
+ WrapInFunction(v);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+56:78 note: while analysing structure member S.m
+12:34 note: while instantiating 'var' v)");
+}
+
+TEST_F(ResolverVariableValidationTest, NonConstructibleType_Struct_WithAtomic) {
+ auto* s = Structure("S", utils::Vector{
+ Member("m", ty.atomic(ty.i32())),
+ });
+ auto* v = Var("v", ty.Of(s));
+ WrapInFunction(v);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "error: function-scope 'var' must have a constructible type");
+}
+
+TEST_F(ResolverVariableValidationTest, NonConstructibleType_InferredType) {
+ // @group(0) @binding(0) var s : sampler;
+ // fn foo() {
+ // var v = s;
+ // }
+ GlobalVar("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 0));
+ auto* v = Var(Source{{12, 34}}, "v", nullptr, Expr("s"));
+ WrapInFunction(v);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: function-scope 'var' must have a constructible type");
+}
+
+TEST_F(ResolverVariableValidationTest, InvalidStorageClassForInitializer) {
+ // var<workgroup> v : f32 = 1.23;
+ GlobalVar(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kWorkgroup, Expr(1.23_f));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: var of storage class 'workgroup' cannot have "
+ "an initializer. var initializers are only supported for the "
+ "storage classes 'private' and 'function'");
+}
+
+TEST_F(ResolverVariableValidationTest, VectorConstNoType) {
+ // const a : mat3x3 = mat3x3<f32>();
+ WrapInFunction(Const("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3u), vec3<f32>()));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverVariableValidationTest, VectorLetNoType) {
+ // let a : mat3x3 = mat3x3<f32>();
+ WrapInFunction(Let("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3u), vec3<f32>()));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverVariableValidationTest, VectorVarNoType) {
+ // var a : mat3x3;
+ WrapInFunction(Var("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverVariableValidationTest, MatrixConstNoType) {
+ // const a : mat3x3 = mat3x3<f32>();
+ WrapInFunction(
+ Const("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3u, 3u), mat3x3<f32>()));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+}
+
+TEST_F(ResolverVariableValidationTest, MatrixLetNoType) {
+ // let a : mat3x3 = mat3x3<f32>();
+ WrapInFunction(Let("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3u, 3u), mat3x3<f32>()));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+}
+
+TEST_F(ResolverVariableValidationTest, MatrixVarNoType) {
+ // var a : mat3x3;
+ WrapInFunction(Var("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3u, 3u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+}
+
+TEST_F(ResolverVariableValidationTest, ConstInitWithVar) {
+ auto* v = Var("v", nullptr, Expr(1_i));
+ auto* c = Const("c", nullptr, Expr(Source{{12, 34}}, v));
+ WrapInFunction(v, c);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'const' initializer must be constant expression)");
+}
+
+TEST_F(ResolverVariableValidationTest, ConstInitWithOverride) {
+ auto* o = Override("v", nullptr, Expr(1_i));
+ auto* c = Const("c", nullptr, Expr(Source{{12, 34}}, o));
+ WrapInFunction(c);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'const' initializer must be constant expression)");
+}
+
+TEST_F(ResolverVariableValidationTest, ConstInitWithLet) {
+ auto* l = Let("v", nullptr, Expr(1_i));
+ auto* c = Const("c", nullptr, Expr(Source{{12, 34}}, l));
+ WrapInFunction(l, c);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'const' initializer must be constant expression)");
+}
+
+} // namespace
+} // namespace tint::resolver
diff --git a/chromium/third_party/dawn/src/tint/sem/abstract_numeric.cc b/chromium/third_party/dawn/src/tint/sem/abstract_numeric.cc
index 6481a433ae2..e7d184652d8 100644
--- a/chromium/third_party/dawn/src/tint/sem/abstract_numeric.cc
+++ b/chromium/third_party/dawn/src/tint/sem/abstract_numeric.cc
@@ -31,7 +31,7 @@ uint32_t AbstractNumeric::Align() const {
}
bool AbstractNumeric::IsConstructible() const {
- return false;
+ return true;
}
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/abstract_numeric.h b/chromium/third_party/dawn/src/tint/sem/abstract_numeric.h
index 0b38448e055..620c5281e2b 100644
--- a/chromium/third_party/dawn/src/tint/sem/abstract_numeric.h
+++ b/chromium/third_party/dawn/src/tint/sem/abstract_numeric.h
@@ -38,7 +38,7 @@ class AbstractNumeric : public Castable<AbstractNumeric, Type> {
/// @returns 0, as the type is abstract.
uint32_t Align() const override;
- /// @returns 0, as the type is abstract.
+ /// @returns true.
bool IsConstructible() const override;
};
diff --git a/chromium/third_party/dawn/src/tint/sem/builtin.cc b/chromium/third_party/dawn/src/tint/sem/builtin.cc
index bb2878be3a5..ecb23319f03 100644
--- a/chromium/third_party/dawn/src/tint/sem/builtin.cc
+++ b/chromium/third_party/dawn/src/tint/sem/builtin.cc
@@ -17,13 +17,25 @@
#include "src/tint/sem/builtin.h"
+#include <utility>
#include <vector>
-#include "src/tint/utils/to_const_ptr_vec.h"
+#include "src/tint/utils/transform.h"
TINT_INSTANTIATE_TYPEINFO(tint::sem::Builtin);
namespace tint::sem {
+namespace {
+
+utils::VectorRef<const Parameter*> SetOwner(utils::VectorRef<Parameter*> parameters,
+ const tint::sem::CallTarget* owner) {
+ for (auto* parameter : parameters) {
+ parameter->SetOwner(owner);
+ }
+ return parameters;
+}
+
+} // namespace
const char* Builtin::str() const {
return sem::str(type_);
@@ -89,17 +101,14 @@ bool IsDP4aBuiltin(BuiltinType i) {
Builtin::Builtin(BuiltinType type,
const sem::Type* return_type,
- std::vector<Parameter*> parameters,
+ utils::VectorRef<Parameter*> parameters,
+ EvaluationStage eval_stage,
PipelineStageSet supported_stages,
bool is_deprecated)
- : Base(return_type, utils::ToConstPtrVec(parameters)),
+ : Base(return_type, SetOwner(std::move(parameters), this), eval_stage),
type_(type),
supported_stages_(supported_stages),
- is_deprecated_(is_deprecated) {
- for (auto* parameter : parameters) {
- parameter->SetOwner(this);
- }
-}
+ is_deprecated_(is_deprecated) {}
Builtin::~Builtin() = default;
@@ -144,20 +153,30 @@ bool Builtin::IsDP4a() const {
}
bool Builtin::HasSideEffects() const {
- if (IsAtomic() && type_ != sem::BuiltinType::kAtomicLoad) {
- return true;
- }
- if (type_ == sem::BuiltinType::kTextureStore) {
- return true;
+ switch (type_) {
+ case sem::BuiltinType::kAtomicAdd:
+ case sem::BuiltinType::kAtomicAnd:
+ case sem::BuiltinType::kAtomicCompareExchangeWeak:
+ case sem::BuiltinType::kAtomicExchange:
+ case sem::BuiltinType::kAtomicMax:
+ case sem::BuiltinType::kAtomicMin:
+ case sem::BuiltinType::kAtomicOr:
+ case sem::BuiltinType::kAtomicStore:
+ case sem::BuiltinType::kAtomicSub:
+ case sem::BuiltinType::kAtomicXor:
+ case sem::BuiltinType::kTextureStore:
+ return true;
+ default:
+ break;
}
return false;
}
ast::Extension Builtin::RequiredExtension() const {
if (IsDP4a()) {
- return ast::Extension::kChromiumExperimentalDP4a;
+ return ast::Extension::kChromiumExperimentalDp4A;
}
- return ast::Extension::kNone;
+ return ast::Extension::kInvalid;
}
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/builtin.h b/chromium/third_party/dawn/src/tint/sem/builtin.h
index 1dc61ad9d58..b63bece9115 100644
--- a/chromium/third_party/dawn/src/tint/sem/builtin.h
+++ b/chromium/third_party/dawn/src/tint/sem/builtin.h
@@ -83,13 +83,15 @@ class Builtin final : public Castable<Builtin, CallTarget> {
/// @param type the builtin type
/// @param return_type the return type for the builtin call
/// @param parameters the parameters for the builtin overload
+ /// @param eval_stage the earliest evaluation stage for a call to the builtin
/// @param supported_stages the pipeline stages that this builtin can be
/// used in
/// @param is_deprecated true if the particular overload is considered
/// deprecated
Builtin(BuiltinType type,
const sem::Type* return_type,
- std::vector<Parameter*> parameters,
+ utils::VectorRef<Parameter*> parameters,
+ EvaluationStage eval_stage,
PipelineStageSet supported_stages,
bool is_deprecated);
diff --git a/chromium/third_party/dawn/src/tint/sem/builtin_test.cc b/chromium/third_party/dawn/src/tint/sem/builtin_test.cc
index cf14565c07d..96f8ebe8b7a 100644
--- a/chromium/third_party/dawn/src/tint/sem/builtin_test.cc
+++ b/chromium/third_party/dawn/src/tint/sem/builtin_test.cc
@@ -93,7 +93,6 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{"sin", BuiltinType::kSin},
BuiltinData{"sinh", BuiltinType::kSinh},
BuiltinData{"smoothstep", BuiltinType::kSmoothstep},
- BuiltinData{"smoothStep", BuiltinType::kSmoothStep},
BuiltinData{"sqrt", BuiltinType::kSqrt},
BuiltinData{"step", BuiltinType::kStep},
BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
diff --git a/chromium/third_party/dawn/src/tint/sem/builtin_type.cc b/chromium/third_party/dawn/src/tint/sem/builtin_type.cc
index 870736953e3..af4f1eb1644 100644
--- a/chromium/third_party/dawn/src/tint/sem/builtin_type.cc
+++ b/chromium/third_party/dawn/src/tint/sem/builtin_type.cc
@@ -13,11 +13,9 @@
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/intrinsic-gen
+// File generated by tools/src/cmd/gen
// using the template:
// src/tint/sem/builtin_type.cc.tmpl
-// and the intrinsic defintion file:
-// src/tint/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
@@ -35,6 +33,9 @@ BuiltinType ParseBuiltinType(const std::string& name) {
if (name == "acos") {
return BuiltinType::kAcos;
}
+ if (name == "acosh") {
+ return BuiltinType::kAcosh;
+ }
if (name == "all") {
return BuiltinType::kAll;
}
@@ -47,12 +48,18 @@ BuiltinType ParseBuiltinType(const std::string& name) {
if (name == "asin") {
return BuiltinType::kAsin;
}
+ if (name == "asinh") {
+ return BuiltinType::kAsinh;
+ }
if (name == "atan") {
return BuiltinType::kAtan;
}
if (name == "atan2") {
return BuiltinType::kAtan2;
}
+ if (name == "atanh") {
+ return BuiltinType::kAtanh;
+ }
if (name == "ceil") {
return BuiltinType::kCeil;
}
@@ -233,9 +240,6 @@ BuiltinType ParseBuiltinType(const std::string& name) {
if (name == "smoothstep") {
return BuiltinType::kSmoothstep;
}
- if (name == "smoothStep") {
- return BuiltinType::kSmoothStep;
- }
if (name == "sqrt") {
return BuiltinType::kSqrt;
}
@@ -361,6 +365,8 @@ const char* str(BuiltinType i) {
return "abs";
case BuiltinType::kAcos:
return "acos";
+ case BuiltinType::kAcosh:
+ return "acosh";
case BuiltinType::kAll:
return "all";
case BuiltinType::kAny:
@@ -369,10 +375,14 @@ const char* str(BuiltinType i) {
return "arrayLength";
case BuiltinType::kAsin:
return "asin";
+ case BuiltinType::kAsinh:
+ return "asinh";
case BuiltinType::kAtan:
return "atan";
case BuiltinType::kAtan2:
return "atan2";
+ case BuiltinType::kAtanh:
+ return "atanh";
case BuiltinType::kCeil:
return "ceil";
case BuiltinType::kClamp:
@@ -493,8 +503,6 @@ const char* str(BuiltinType i) {
return "sinh";
case BuiltinType::kSmoothstep:
return "smoothstep";
- case BuiltinType::kSmoothStep:
- return "smoothStep";
case BuiltinType::kSqrt:
return "sqrt";
case BuiltinType::kStep:
diff --git a/chromium/third_party/dawn/src/tint/sem/builtin_type.cc.tmpl b/chromium/third_party/dawn/src/tint/sem/builtin_type.cc.tmpl
index 4e830dac957..5737d8d05a7 100644
--- a/chromium/third_party/dawn/src/tint/sem/builtin_type.cc.tmpl
+++ b/chromium/third_party/dawn/src/tint/sem/builtin_type.cc.tmpl
@@ -1,9 +1,12 @@
{{- /*
--------------------------------------------------------------------------------
-Template file for use with tools/builtin-gen to generate builtin_type.cc
+Template file for use with tools/src/cmd/gen to generate builtin_type.cc
+
+To update the generated file, run:
+ ./tools/run gen
See:
-* tools/cmd/intrinsic-gen/gen for structures used by this template
+* tools/src/cmd/gen for structures used by this template
* https://golang.org/pkg/text/template/ for documentation on the template syntax
--------------------------------------------------------------------------------
*/ -}}
@@ -15,7 +18,7 @@ See:
namespace tint::sem {
BuiltinType ParseBuiltinType(const std::string& name) {
-{{- range .Sem.Builtins }}
+{{- range Sem.Builtins }}
if (name == "{{.Name}}") {
return BuiltinType::k{{Title .Name}};
}
@@ -27,7 +30,7 @@ const char* str(BuiltinType i) {
switch (i) {
case BuiltinType::kNone:
return "<none>";
-{{- range .Sem.Builtins }}
+{{- range Sem.Builtins }}
case BuiltinType::k{{Title .Name}}:
return "{{.Name}}";
{{- end }}
diff --git a/chromium/third_party/dawn/src/tint/sem/builtin_type.h b/chromium/third_party/dawn/src/tint/sem/builtin_type.h
index 96d3c30e942..0a29fca841d 100644
--- a/chromium/third_party/dawn/src/tint/sem/builtin_type.h
+++ b/chromium/third_party/dawn/src/tint/sem/builtin_type.h
@@ -13,11 +13,9 @@
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/intrinsic-gen
+// File generated by tools/src/cmd/gen
// using the template:
// src/tint/sem/builtin_type.h.tmpl
-// and the intrinsic defintion file:
-// src/tint/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
@@ -35,12 +33,15 @@ enum class BuiltinType {
kNone = -1,
kAbs,
kAcos,
+ kAcosh,
kAll,
kAny,
kArrayLength,
kAsin,
+ kAsinh,
kAtan,
kAtan2,
+ kAtanh,
kCeil,
kClamp,
kCos,
@@ -101,7 +102,6 @@ enum class BuiltinType {
kSin,
kSinh,
kSmoothstep,
- kSmoothStep,
kSqrt,
kStep,
kStorageBarrier,
diff --git a/chromium/third_party/dawn/src/tint/sem/builtin_type.h.tmpl b/chromium/third_party/dawn/src/tint/sem/builtin_type.h.tmpl
index 258ac87f729..84ceffcff76 100644
--- a/chromium/third_party/dawn/src/tint/sem/builtin_type.h.tmpl
+++ b/chromium/third_party/dawn/src/tint/sem/builtin_type.h.tmpl
@@ -1,9 +1,12 @@
{{- /*
--------------------------------------------------------------------------------
-Template file for use with tools/builtin-gen to generate builtin_type.h
+Template file for use with tools/src/cmd/gen to generate builtin_type.h
+
+To update the generated file, run:
+ ./tools/run gen
See:
-* tools/cmd/intrinsic-gen/gen for structures used by this template
+* tools/src/cmd/gen for structures used by this template
* https://golang.org/pkg/text/template/ for documentation on the template syntax
--------------------------------------------------------------------------------
*/ -}}
@@ -19,7 +22,7 @@ namespace tint::sem {
/// Enumerator of all builtin functions
enum class BuiltinType {
kNone = -1,
-{{- range .Sem.Builtins }}
+{{- range Sem.Builtins }}
k{{Title .Name}},
{{- end }}
};
diff --git a/chromium/third_party/dawn/src/tint/sem/call.cc b/chromium/third_party/dawn/src/tint/sem/call.cc
index f688cce22f6..1fb7de4a4ba 100644
--- a/chromium/third_party/dawn/src/tint/sem/call.cc
+++ b/chromium/third_party/dawn/src/tint/sem/call.cc
@@ -23,13 +23,17 @@ namespace tint::sem {
Call::Call(const ast::CallExpression* declaration,
const CallTarget* target,
- std::vector<const sem::Expression*> arguments,
+ EvaluationStage stage,
+ utils::VectorRef<const sem::Expression*> arguments,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects)
- : Base(declaration, target->ReturnType(), statement, std::move(constant), has_side_effects),
+ : Base(declaration, target->ReturnType(), stage, statement, constant, has_side_effects),
target_(target),
- arguments_(std::move(arguments)) {}
+ arguments_(std::move(arguments)) {
+ // Check that the stage is no earlier than the target supports
+ TINT_ASSERT(Semantic, target->Stage() <= stage);
+}
Call::~Call() = default;
diff --git a/chromium/third_party/dawn/src/tint/sem/call.h b/chromium/third_party/dawn/src/tint/sem/call.h
index c96179daa43..1213c6d81d9 100644
--- a/chromium/third_party/dawn/src/tint/sem/call.h
+++ b/chromium/third_party/dawn/src/tint/sem/call.h
@@ -17,8 +17,10 @@
#include <vector>
+#include "src/tint/ast/call_expression.h"
#include "src/tint/sem/builtin.h"
#include "src/tint/sem/expression.h"
+#include "src/tint/utils/vector.h"
namespace tint::sem {
@@ -29,15 +31,17 @@ class Call final : public Castable<Call, Expression> {
/// Constructor
/// @param declaration the AST node
/// @param target the call target
+ /// @param stage the earliest evaluation stage for the expression
/// @param arguments the call arguments
/// @param statement the statement that owns this expression
/// @param constant the constant value of this expression
/// @param has_side_effects whether this expression may have side effects
Call(const ast::CallExpression* declaration,
const CallTarget* target,
- std::vector<const sem::Expression*> arguments,
+ EvaluationStage stage,
+ utils::VectorRef<const sem::Expression*> arguments,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects);
/// Destructor
@@ -47,7 +51,7 @@ class Call final : public Castable<Call, Expression> {
const CallTarget* Target() const { return target_; }
/// @return the call arguments
- const std::vector<const sem::Expression*>& Arguments() const { return arguments_; }
+ const auto& Arguments() const { return arguments_; }
/// @returns the AST node
const ast::CallExpression* Declaration() const {
@@ -56,7 +60,7 @@ class Call final : public Castable<Call, Expression> {
private:
CallTarget const* const target_;
- std::vector<const sem::Expression*> arguments_;
+ utils::Vector<const sem::Expression*, 8> arguments_;
};
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/call_target.cc b/chromium/third_party/dawn/src/tint/sem/call_target.cc
index 67bde0e144c..362482c0cee 100644
--- a/chromium/third_party/dawn/src/tint/sem/call_target.cc
+++ b/chromium/third_party/dawn/src/tint/sem/call_target.cc
@@ -14,6 +14,8 @@
#include "src/tint/sem/call_target.h"
+#include <utility>
+
#include "src/tint/symbol_table.h"
#include "src/tint/utils/hash.h"
@@ -21,21 +23,24 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::CallTarget);
namespace tint::sem {
-CallTarget::CallTarget(const sem::Type* return_type, const ParameterList& parameters)
- : signature_{return_type, parameters} {
+CallTarget::CallTarget(const sem::Type* return_type,
+ utils::VectorRef<const Parameter*> parameters,
+ EvaluationStage stage)
+ : signature_{return_type, std::move(parameters)}, stage_(stage) {
TINT_ASSERT(Semantic, return_type);
}
CallTarget::CallTarget(const CallTarget&) = default;
CallTarget::~CallTarget() = default;
-CallTargetSignature::CallTargetSignature(const sem::Type* ret_ty, const ParameterList& params)
- : return_type(ret_ty), parameters(params) {}
+CallTargetSignature::CallTargetSignature(const sem::Type* ret_ty,
+ utils::VectorRef<const Parameter*> params)
+ : return_type(ret_ty), parameters(std::move(params)) {}
CallTargetSignature::CallTargetSignature(const CallTargetSignature&) = default;
CallTargetSignature::~CallTargetSignature() = default;
int CallTargetSignature::IndexOf(ParameterUsage usage) const {
- for (size_t i = 0; i < parameters.size(); i++) {
+ for (size_t i = 0; i < parameters.Length(); i++) {
if (parameters[i]->Usage() == usage) {
return static_cast<int>(i);
}
@@ -44,10 +49,10 @@ int CallTargetSignature::IndexOf(ParameterUsage usage) const {
}
bool CallTargetSignature::operator==(const CallTargetSignature& other) const {
- if (return_type != other.return_type || parameters.size() != other.parameters.size()) {
+ if (return_type != other.return_type || parameters.Length() != other.parameters.Length()) {
return false;
}
- for (size_t i = 0; i < parameters.size(); i++) {
+ for (size_t i = 0; i < parameters.Length(); i++) {
auto* a = parameters[i];
auto* b = other.parameters[i];
if (a->Type() != b->Type() || a->Usage() != b->Usage()) {
@@ -63,7 +68,7 @@ namespace std {
std::size_t hash<tint::sem::CallTargetSignature>::operator()(
const tint::sem::CallTargetSignature& sig) const {
- size_t hash = tint::utils::Hash(sig.parameters.size());
+ size_t hash = tint::utils::Hash(sig.parameters.Length());
for (auto* p : sig.parameters) {
tint::utils::HashCombine(&hash, p->Type(), p->Usage());
}
diff --git a/chromium/third_party/dawn/src/tint/sem/call_target.h b/chromium/third_party/dawn/src/tint/sem/call_target.h
index 64716b2913b..3f7fec1ce65 100644
--- a/chromium/third_party/dawn/src/tint/sem/call_target.h
+++ b/chromium/third_party/dawn/src/tint/sem/call_target.h
@@ -21,6 +21,7 @@
#include "src/tint/sem/sampler.h"
#include "src/tint/sem/variable.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint::sem {
@@ -34,7 +35,7 @@ struct CallTargetSignature {
/// Constructor
/// @param ret_ty the call target return type
/// @param params the call target parameters
- CallTargetSignature(const sem::Type* ret_ty, const ParameterList& params);
+ CallTargetSignature(const sem::Type* ret_ty, utils::VectorRef<const Parameter*> params);
/// Copy constructor
CallTargetSignature(const CallTargetSignature&);
@@ -45,7 +46,7 @@ struct CallTargetSignature {
/// The type of the call target return value
const sem::Type* const return_type = nullptr;
/// The parameters of the call target
- const ParameterList parameters;
+ const utils::Vector<const sem::Parameter*, 8> parameters;
/// Equality operator
/// @param other the signature to compare this to
@@ -63,9 +64,12 @@ struct CallTargetSignature {
class CallTarget : public Castable<CallTarget, Node> {
public:
/// Constructor
+ /// @param stage the earliest evaluation stage for a call to this target
/// @param return_type the return type of the call target
/// @param parameters the parameters for the call target
- CallTarget(const sem::Type* return_type, const ParameterList& parameters);
+ CallTarget(const sem::Type* return_type,
+ utils::VectorRef<const Parameter*> parameters,
+ EvaluationStage stage);
/// Copy constructor
CallTarget(const CallTarget&);
@@ -77,13 +81,17 @@ class CallTarget : public Castable<CallTarget, Node> {
const sem::Type* ReturnType() const { return signature_.return_type; }
/// @return the parameters of the call target
- const ParameterList& Parameters() const { return signature_.parameters; }
+ auto& Parameters() const { return signature_.parameters; }
/// @return the signature of the call target
const CallTargetSignature& Signature() const { return signature_; }
+ /// @return the earliest evaluation stage for a call to this target
+ EvaluationStage Stage() const { return stage_; }
+
private:
CallTargetSignature signature_;
+ EvaluationStage stage_;
};
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/constant.cc b/chromium/third_party/dawn/src/tint/sem/constant.cc
index 80869920ccb..70bb08c5b5b 100644
--- a/chromium/third_party/dawn/src/tint/sem/constant.cc
+++ b/chromium/third_party/dawn/src/tint/sem/constant.cc
@@ -14,100 +14,10 @@
#include "src/tint/sem/constant.h"
-#include <cmath>
-#include <utility>
-
-#include "src/tint/debug.h"
-#include "src/tint/program_builder.h"
-#include "src/tint/sem/type.h"
-
namespace tint::sem {
-namespace {
-size_t CountElements(const Constant::Elements& elements) {
- return std::visit([](auto&& vec) { return vec.size(); }, elements);
-}
-
-template <typename T>
-bool IsNegativeFloat(T value) {
- (void)value;
- if constexpr (IsFloatingPoint<T>) {
- return std::signbit(value);
- } else {
- return false;
- }
-}
-
-} // namespace
-
-Constant::Constant() {}
-
-Constant::Constant(const sem::Type* ty, Elements els)
- : type_(ty), elem_type_(CheckElemType(ty, CountElements(els))), elems_(std::move(els)) {}
-
-Constant::Constant(const sem::Type* ty, AInts vec) : Constant(ty, Elements{std::move(vec)}) {}
-
-Constant::Constant(const sem::Type* ty, AFloats vec) : Constant(ty, Elements{std::move(vec)}) {}
-
-Constant::Constant(const Constant&) = default;
+Constant::Constant() = default;
Constant::~Constant() = default;
-Constant& Constant::operator=(const Constant& rhs) = default;
-
-bool Constant::AnyZero() const {
- return WithElements([&](auto&& vec) {
- using T = typename std::decay_t<decltype(vec)>::value_type;
- for (auto el : vec) {
- if (el == T(0) && !IsNegativeFloat(el.value)) {
- return true;
- }
- }
- return false;
- });
-}
-
-bool Constant::AllZero() const {
- return WithElements([&](auto&& vec) {
- using T = typename std::decay_t<decltype(vec)>::value_type;
- for (auto el : vec) {
- if (el != T(0) || IsNegativeFloat(el.value)) {
- return false;
- }
- }
- return true;
- });
-}
-
-bool Constant::AllEqual(size_t start, size_t end) const {
- return WithElements([&](auto&& vec) {
- if (!vec.empty()) {
- auto value = vec[start];
- bool float_sign = IsNegativeFloat(vec[start].value);
- for (size_t i = start + 1; i < end; i++) {
- if (vec[i] != value || float_sign != IsNegativeFloat(vec[i].value)) {
- return false;
- }
- }
- }
- return true;
- });
-}
-
-const Type* Constant::CheckElemType(const sem::Type* ty, size_t num_elements) {
- diag::List diag;
- if (ty->is_abstract_or_scalar() || ty->IsAnyOf<Vector, Matrix>()) {
- uint32_t count = 0;
- auto* el_ty = Type::ElementOf(ty, &count);
- if (num_elements != count) {
- TINT_ICE(Semantic, diag) << "sem::Constant() type <-> element mismatch. type: '"
- << ty->TypeInfo().name << "' element: " << num_elements;
- }
- TINT_ASSERT(Semantic, el_ty->is_abstract_or_scalar());
- return el_ty;
- }
- TINT_UNREACHABLE(Semantic, diag) << "Unsupported sem::Constant type: " << ty->TypeInfo().name;
- return nullptr;
-}
-
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/constant.h b/chromium/third_party/dawn/src/tint/sem/constant.h
index c0ba9e6b5ca..875864fdc53 100644
--- a/chromium/third_party/dawn/src/tint/sem/constant.h
+++ b/chromium/third_party/dawn/src/tint/sem/constant.h
@@ -15,172 +15,67 @@
#ifndef SRC_TINT_SEM_CONSTANT_H_
#define SRC_TINT_SEM_CONSTANT_H_
-#include <ostream>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <utility>
-#include <variant> // NOLINT(build/include_order)
-#include <vector>
+#include <variant>
-#include "src/tint/program_builder.h"
-#include "src/tint/sem/type.h"
+#include "src/tint/number.h"
+
+// Forward declarations
+namespace tint::sem {
+class Type;
+}
namespace tint::sem {
-/// A Constant holds a compile-time evaluated expression value, expressed as a flattened list of
-/// element values. The expression type may be of an abstract-numeric, scalar, vector or matrix
-/// type. Constant holds the element values in either a vector of abstract-integer (AInt) or
-/// abstract-float (AFloat), depending on the element type.
+/// Constant is the interface to a compile-time evaluated expression value.
class Constant {
public:
- /// AInts is a vector of AInt, used to hold elements of the WGSL types:
- /// * abstract-integer
- /// * i32
- /// * u32
- /// * bool (0 or 1)
- using AInts = std::vector<AInt>;
-
- /// AFloats is a vector of AFloat, used to hold elements of the WGSL types:
- /// * abstract-float
- /// * f32
- /// * f16
- using AFloats = std::vector<AFloat>;
-
- /// Elements is either a vector of AInts or AFloats
- using Elements = std::variant<AInts, AFloats>;
-
- /// Helper that resolves to either AInt or AFloat based on the element type T.
- template <typename T>
- using ElementFor = std::conditional_t<IsFloatingPoint<UnwrapNumber<T>>, AFloat, AInt>;
-
- /// Helper that resolves to either AInts or AFloats based on the element type T.
- template <typename T>
- using ElementVectorFor = std::conditional_t<IsFloatingPoint<UnwrapNumber<T>>, AFloats, AInts>;
-
- /// Constructs an invalid Constant
+ /// Constructor
Constant();
- /// Constructs a Constant of the given type and element values
- /// @param ty the Constant type
- /// @param els the Constant element values
- Constant(const sem::Type* ty, Elements els);
-
- /// Constructs a Constant of the given type and element values
- /// @param ty the Constant type
- /// @param vec the Constant element values
- Constant(const sem::Type* ty, AInts vec);
-
- /// Constructs a Constant of the given type and element values
- /// @param ty the Constant type
- /// @param vec the Constant element values
- Constant(const sem::Type* ty, AFloats vec);
-
- /// Constructs a Constant of the given type and element values
- /// @param ty the Constant type
- /// @param els the Constant element values
- template <typename T>
- Constant(const sem::Type* ty, std::initializer_list<T> els);
-
- /// Copy constructor
- Constant(const Constant&);
-
/// Destructor
- ~Constant();
+ virtual ~Constant();
- /// Copy assignment
- /// @param other the Constant to copy
- /// @returns this Constant
- Constant& operator=(const Constant& other);
+ /// @returns the type of the constant
+ virtual const sem::Type* Type() const = 0;
- /// @returns true if the Constant has been initialized
- bool IsValid() const { return type_ != nullptr; }
+ /// @returns the value of this Constant, if this constant is of a scalar value or abstract
+ /// numeric, otherwise std::monostate.
+ virtual std::variant<std::monostate, AInt, AFloat> Value() const = 0;
- /// @return true if the Constant has been initialized
- operator bool() const { return IsValid(); }
+ /// @returns the child constant element with the given index, or nullptr if the constant has no
+ /// children, or the index is out of bounds.
+ /// For arrays, this returns the i'th element of the array.
+ /// For vectors, this returns the i'th element of the vector.
+ /// For matrices, this returns the i'th column vector of the matrix.
+ /// For structures, this returns the i'th member field of the structure.
+ virtual const Constant* Index(size_t) const = 0;
- /// @returns the type of the Constant
- const sem::Type* Type() const { return type_; }
+ /// @returns true if child elements of this constant are positive-zero valued.
+ virtual bool AllZero() const = 0;
- /// @returns the number of elements
- size_t ElementCount() const {
- return std::visit([](auto&& v) { return v.size(); }, elems_);
- }
-
- /// @returns the element type of the Constant
- const sem::Type* ElementType() const { return elem_type_; }
+ /// @returns true if any child elements of this constant are positive-zero valued.
+ virtual bool AnyZero() const = 0;
- /// @returns the constant's elements
- const Elements& GetElements() const { return elems_; }
+ /// @returns true if all child elements of this constant have the same value and type.
+ virtual bool AllEqual() const = 0;
- /// WithElements calls the function `f` with the vector of elements as either AFloats or AInts
- /// @param f a function-like with the signature `R(auto&&)`.
- /// @returns the result of calling `f`.
- template <typename F>
- auto WithElements(F&& f) const {
- return std::visit(std::forward<F>(f), elems_);
- }
+ /// @returns a hash of the constant.
+ virtual size_t Hash() const = 0;
- /// WithElements calls the function `f` with the element vector as either AFloats or AInts
- /// @param f a function-like with the signature `R(auto&&)`.
- /// @returns the result of calling `f`.
- template <typename F>
- auto WithElements(F&& f) {
- return std::visit(std::forward<F>(f), elems_);
- }
-
- /// @returns the elements as a vector of AInt
- inline const AInts& IElements() const { return std::get<AInts>(elems_); }
-
- /// @returns the elements as a vector of AFloat
- inline const AFloats& FElements() const { return std::get<AFloats>(elems_); }
-
- /// @returns true if any element is positive zero
- bool AnyZero() const;
-
- /// @returns true if all elements are positive zero
- bool AllZero() const;
-
- /// @returns true if all elements are the same value, with the same sign-bit.
- bool AllEqual() const { return AllEqual(0, ElementCount()); }
-
- /// @param start the first element index
- /// @param end one past the last element index
- /// @returns true if all elements between `[start, end)` are the same value
- bool AllEqual(size_t start, size_t end) const;
-
- /// @param index the index of the element
- /// @return the element at `index`, which must be of type `T`.
+ /// @returns the value of the constant as the given scalar or abstract value.
template <typename T>
- T Element(size_t index) const;
-
- private:
- /// Checks that the provided type matches the number of expected elements.
- /// @returns the element type of `ty`.
- const sem::Type* CheckElemType(const sem::Type* ty, size_t num_elements);
-
- const sem::Type* type_ = nullptr;
- const sem::Type* elem_type_ = nullptr;
- Elements elems_;
-};
-
-template <typename T>
-Constant::Constant(const sem::Type* ty, std::initializer_list<T> els)
- : type_(ty), elem_type_(CheckElemType(type_, els.size())) {
- ElementVectorFor<T> elements;
- elements.reserve(els.size());
- for (auto el : els) {
- elements.emplace_back(ElementFor<T>(el));
- }
- elems_ = Elements{std::move(elements)};
-}
-
-template <typename T>
-T Constant::Element(size_t index) const {
- if constexpr (std::is_same_v<ElementVectorFor<T>, AFloats>) {
- return static_cast<T>(FElements()[index].value);
- } else {
- return static_cast<T>(IElements()[index].value);
+ T As() const {
+ return std::visit(
+ [](auto v) {
+ if constexpr (std::is_same_v<decltype(v), std::monostate>) {
+ return T(0);
+ } else {
+ return static_cast<T>(v);
+ }
+ },
+ Value());
}
-}
+};
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/constant_test.cc b/chromium/third_party/dawn/src/tint/sem/constant_test.cc
deleted file mode 100644
index ed9fef8bf07..00000000000
--- a/chromium/third_party/dawn/src/tint/sem/constant_test.cc
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2022 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/sem/constant.h"
-
-#include <gmock/gmock.h>
-
-#include "src/tint/sem/abstract_float.h"
-#include "src/tint/sem/abstract_int.h"
-#include "src/tint/sem/test_helper.h"
-
-using namespace tint::number_suffixes; // NOLINT
-
-namespace tint::sem {
-namespace {
-
-using ConstantTest = TestHelper;
-
-TEST_F(ConstantTest, ConstructorInitializerList) {
- {
- auto i = AInt(AInt::kHighest);
- Constant c(create<AbstractInt>(), {i});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(i)); });
- }
- {
- auto i = i32(i32::kHighest);
- Constant c(create<I32>(), {i});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(i)); });
- }
- {
- auto i = u32(u32::kHighest);
- Constant c(create<U32>(), {i});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(i)); });
- }
- {
- Constant c(create<Bool>(), {false});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(0_a)); });
- }
- {
- Constant c(create<Bool>(), {true});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1_a)); });
- }
- {
- auto f = AFloat(AFloat::kHighest);
- Constant c(create<AbstractFloat>(), {f});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(f)); });
- }
- {
- auto f = f32(f32::kHighest);
- Constant c(create<F32>(), {f});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(f)); });
- }
- {
- auto f = f16(f16::kHighest);
- Constant c(create<F16>(), {f});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(f)); });
- }
-}
-
-TEST_F(ConstantTest, Element_ai) {
- Constant c(create<AbstractInt>(), {1_a});
- EXPECT_EQ(c.Element<AInt>(0), 1_a);
- EXPECT_EQ(c.ElementCount(), 1u);
-}
-
-TEST_F(ConstantTest, Element_i32) {
- Constant c(create<I32>(), {1_a});
- EXPECT_EQ(c.Element<i32>(0), 1_i);
- EXPECT_EQ(c.ElementCount(), 1u);
-}
-
-TEST_F(ConstantTest, Element_u32) {
- Constant c(create<U32>(), {1_a});
- EXPECT_EQ(c.Element<u32>(0), 1_u);
- EXPECT_EQ(c.ElementCount(), 1u);
-}
-
-TEST_F(ConstantTest, Element_bool) {
- Constant c(create<Bool>(), {true});
- EXPECT_EQ(c.Element<bool>(0), true);
- EXPECT_EQ(c.ElementCount(), 1u);
-}
-
-TEST_F(ConstantTest, Element_af) {
- Constant c(create<AbstractFloat>(), {1.0_a});
- EXPECT_EQ(c.Element<AFloat>(0), 1.0_a);
- EXPECT_EQ(c.ElementCount(), 1u);
-}
-
-TEST_F(ConstantTest, Element_f32) {
- Constant c(create<F32>(), {1.0_a});
- EXPECT_EQ(c.Element<f32>(0), 1.0_f);
- EXPECT_EQ(c.ElementCount(), 1u);
-}
-
-TEST_F(ConstantTest, Element_f16) {
- Constant c(create<F16>(), {1.0_a});
- EXPECT_EQ(c.Element<f16>(0), 1.0_h);
- EXPECT_EQ(c.ElementCount(), 1u);
-}
-
-TEST_F(ConstantTest, Element_vec3_ai) {
- Constant c(create<Vector>(create<AbstractInt>(), 3u), {1_a, 2_a, 3_a});
- EXPECT_EQ(c.Element<AInt>(0), 1_a);
- EXPECT_EQ(c.Element<AInt>(1), 2_a);
- EXPECT_EQ(c.Element<AInt>(2), 3_a);
- EXPECT_EQ(c.ElementCount(), 3u);
-}
-
-TEST_F(ConstantTest, Element_vec3_i32) {
- Constant c(create<Vector>(create<I32>(), 3u), {1_a, 2_a, 3_a});
- EXPECT_EQ(c.Element<i32>(0), 1_i);
- EXPECT_EQ(c.Element<i32>(1), 2_i);
- EXPECT_EQ(c.Element<i32>(2), 3_i);
- EXPECT_EQ(c.ElementCount(), 3u);
-}
-
-TEST_F(ConstantTest, Element_vec3_u32) {
- Constant c(create<Vector>(create<U32>(), 3u), {1_a, 2_a, 3_a});
- EXPECT_EQ(c.Element<u32>(0), 1_u);
- EXPECT_EQ(c.Element<u32>(1), 2_u);
- EXPECT_EQ(c.Element<u32>(2), 3_u);
- EXPECT_EQ(c.ElementCount(), 3u);
-}
-
-TEST_F(ConstantTest, Element_vec3_bool) {
- Constant c(create<Vector>(create<Bool>(), 2u), {true, false});
- EXPECT_EQ(c.Element<bool>(0), true);
- EXPECT_EQ(c.Element<bool>(1), false);
- EXPECT_EQ(c.ElementCount(), 2u);
-}
-
-TEST_F(ConstantTest, Element_vec3_af) {
- Constant c(create<Vector>(create<AbstractFloat>(), 3u), {1.0_a, 2.0_a, 3.0_a});
- EXPECT_EQ(c.Element<AFloat>(0), 1.0_a);
- EXPECT_EQ(c.Element<AFloat>(1), 2.0_a);
- EXPECT_EQ(c.Element<AFloat>(2), 3.0_a);
- EXPECT_EQ(c.ElementCount(), 3u);
-}
-
-TEST_F(ConstantTest, Element_vec3_f32) {
- Constant c(create<Vector>(create<F32>(), 3u), {1.0_a, 2.0_a, 3.0_a});
- EXPECT_EQ(c.Element<f32>(0), 1.0_f);
- EXPECT_EQ(c.Element<f32>(1), 2.0_f);
- EXPECT_EQ(c.Element<f32>(2), 3.0_f);
- EXPECT_EQ(c.ElementCount(), 3u);
-}
-
-TEST_F(ConstantTest, Element_vec3_f16) {
- Constant c(create<Vector>(create<F16>(), 3u), {1.0_a, 2.0_a, 3.0_a});
- EXPECT_EQ(c.Element<f16>(0), 1.0_h);
- EXPECT_EQ(c.Element<f16>(1), 2.0_h);
- EXPECT_EQ(c.Element<f16>(2), 3.0_h);
- EXPECT_EQ(c.ElementCount(), 3u);
-}
-
-TEST_F(ConstantTest, Element_mat2x3_af) {
- Constant c(create<Matrix>(create<Vector>(create<AbstractFloat>(), 3u), 2u),
- {1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a});
- EXPECT_EQ(c.Element<AFloat>(0), 1.0_a);
- EXPECT_EQ(c.Element<AFloat>(1), 2.0_a);
- EXPECT_EQ(c.Element<AFloat>(2), 3.0_a);
- EXPECT_EQ(c.Element<AFloat>(3), 4.0_a);
- EXPECT_EQ(c.Element<AFloat>(4), 5.0_a);
- EXPECT_EQ(c.Element<AFloat>(5), 6.0_a);
- EXPECT_EQ(c.ElementCount(), 6u);
-}
-
-TEST_F(ConstantTest, Element_mat2x3_f32) {
- Constant c(create<Matrix>(create<Vector>(create<F32>(), 3u), 2u),
- {1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a});
- EXPECT_EQ(c.Element<f32>(0), 1.0_f);
- EXPECT_EQ(c.Element<f32>(1), 2.0_f);
- EXPECT_EQ(c.Element<f32>(2), 3.0_f);
- EXPECT_EQ(c.Element<f32>(3), 4.0_f);
- EXPECT_EQ(c.Element<f32>(4), 5.0_f);
- EXPECT_EQ(c.Element<f32>(5), 6.0_f);
- EXPECT_EQ(c.ElementCount(), 6u);
-}
-
-TEST_F(ConstantTest, Element_mat2x3_f16) {
- Constant c(create<Matrix>(create<Vector>(create<F16>(), 3u), 2u),
- {1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a});
- EXPECT_EQ(c.Element<f16>(0), 1.0_h);
- EXPECT_EQ(c.Element<f16>(1), 2.0_h);
- EXPECT_EQ(c.Element<f16>(2), 3.0_h);
- EXPECT_EQ(c.Element<f16>(3), 4.0_h);
- EXPECT_EQ(c.Element<f16>(4), 5.0_h);
- EXPECT_EQ(c.Element<f16>(5), 6.0_h);
- EXPECT_EQ(c.ElementCount(), 6u);
-}
-
-TEST_F(ConstantTest, AnyZero) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 3_a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 3_a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AnyZero(), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 3._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AnyZero(), true);
-
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 3._a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -2._a, 3._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 3._a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 0._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AnyZero(), false);
-}
-
-TEST_F(ConstantTest, AllZero) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 3_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 3_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllZero(), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllZero(), true);
-
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 0._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AllZero(), false);
-}
-
-TEST_F(ConstantTest, AllEqual) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 3_a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 3_a, 3_a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 1_a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 2_a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_ai, {3_a, 3_a, 3_a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllEqual(), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 3._a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 3._a, 3._a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 1._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 2._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {3._a, 3._a, 3._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllEqual(), false);
-}
-
-TEST_F(ConstantTest, AllEqualRange) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 3_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 3_a, 3_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 1_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 2_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 3_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 0_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 1_a, 0_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 1_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllEqual(1, 3), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 3._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 3._a, 3._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 1._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 2._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 3._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 0._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, 1._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 1._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -1._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 1._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, -0._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AllEqual(1, 3), true);
-}
-
-} // namespace
-} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/evaluation_stage.h b/chromium/third_party/dawn/src/tint/sem/evaluation_stage.h
new file mode 100644
index 00000000000..b5e554d8736
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/sem/evaluation_stage.h
@@ -0,0 +1,60 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_SEM_EVALUATION_STAGE_H_
+#define SRC_TINT_SEM_EVALUATION_STAGE_H_
+
+#include <algorithm>
+#include <initializer_list>
+
+namespace tint::sem {
+
+/// The earliest point in time that an expression can be evaluated
+enum class EvaluationStage {
+ /// Expression can be evaluated at shader creation time
+ kConstant,
+ /// Expression can be evaluated at pipeline creation time
+ kOverride,
+ /// Expression can be evaluated at runtime
+ kRuntime,
+};
+
+/// @returns true if stage `a` comes earlier than stage `b`
+inline bool operator<(EvaluationStage a, EvaluationStage b) {
+ return static_cast<int>(a) < static_cast<int>(b);
+}
+
+/// @returns true if stage `a` comes later than stage `b`
+inline bool operator>(EvaluationStage a, EvaluationStage b) {
+ return static_cast<int>(a) > static_cast<int>(b);
+}
+
+/// @param stages a list of EvaluationStage.
+/// @returns the earliest stage supported by all the provided stages
+inline EvaluationStage EarliestStage(std::initializer_list<EvaluationStage> stages) {
+ auto earliest = EvaluationStage::kConstant;
+ for (auto stage : stages) {
+ earliest = std::max(stage, earliest);
+ }
+ return static_cast<EvaluationStage>(earliest);
+}
+
+template <typename... ARGS>
+inline EvaluationStage EarliestStage(ARGS... args) {
+ return EarliestStage({args...});
+}
+
+} // namespace tint::sem
+
+#endif // SRC_TINT_SEM_EVALUATION_STAGE_H_
diff --git a/chromium/third_party/dawn/src/tint/sem/expression.cc b/chromium/third_party/dawn/src/tint/sem/expression.cc
index 57ec68bf213..cdaa2bca3dc 100644
--- a/chromium/third_party/dawn/src/tint/sem/expression.cc
+++ b/chromium/third_party/dawn/src/tint/sem/expression.cc
@@ -24,17 +24,20 @@ namespace tint::sem {
Expression::Expression(const ast::Expression* declaration,
const sem::Type* type,
+ EvaluationStage stage,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects,
const Variable* source_var /* = nullptr */)
: declaration_(declaration),
source_variable_(source_var),
type_(type),
+ stage_(stage),
statement_(statement),
constant_(std::move(constant)),
has_side_effects_(has_side_effects) {
TINT_ASSERT(Semantic, type_);
+ TINT_ASSERT(Semantic, (constant != nullptr) == (stage == EvaluationStage::kConstant));
}
Expression::~Expression() = default;
diff --git a/chromium/third_party/dawn/src/tint/sem/expression.h b/chromium/third_party/dawn/src/tint/sem/expression.h
index a7838516bb8..5942a711085 100644
--- a/chromium/third_party/dawn/src/tint/sem/expression.h
+++ b/chromium/third_party/dawn/src/tint/sem/expression.h
@@ -18,6 +18,7 @@
#include "src/tint/ast/expression.h"
#include "src/tint/sem/behavior.h"
#include "src/tint/sem/constant.h"
+#include "src/tint/sem/evaluation_stage.h"
#include "src/tint/sem/node.h"
// Forward declarations
@@ -28,20 +29,23 @@ class Variable;
} // namespace tint::sem
namespace tint::sem {
+
/// Expression holds the semantic information for expression nodes.
class Expression : public Castable<Expression, Node> {
public:
/// Constructor
/// @param declaration the AST node
/// @param type the resolved type of the expression
+ /// @param stage the earliest evaluation stage for the expression
/// @param statement the statement that owns this expression
- /// @param constant the constant value of the expression. May be invalid
+ /// @param constant the constant value of the expression. May be null
/// @param has_side_effects true if this expression may have side-effects
/// @param source_var the (optional) source variable for this expression
Expression(const ast::Expression* declaration,
const sem::Type* type,
+ EvaluationStage stage,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects,
const Variable* source_var = nullptr);
@@ -54,11 +58,14 @@ class Expression : public Castable<Expression, Node> {
/// @return the resolved type of the expression
const sem::Type* Type() const { return type_; }
+ /// @return the earliest evaluation stage for the expression
+ EvaluationStage Stage() const { return stage_; }
+
/// @return the statement that owns this expression
const Statement* Stmt() const { return statement_; }
/// @return the constant value of this expression
- const Constant& ConstantValue() const { return constant_; }
+ const Constant* ConstantValue() const { return constant_; }
/// Returns the variable or parameter that this expression derives from.
/// For reference and pointer expressions, this will either be the originating
@@ -87,8 +94,9 @@ class Expression : public Castable<Expression, Node> {
private:
const sem::Type* const type_;
+ const EvaluationStage stage_;
const Statement* const statement_;
- const Constant constant_;
+ const Constant* const constant_;
sem::Behaviors behaviors_{sem::Behavior::kNext};
const bool has_side_effects_;
};
diff --git a/chromium/third_party/dawn/src/tint/sem/expression_test.cc b/chromium/third_party/dawn/src/tint/sem/expression_test.cc
index fc1adeb88d4..63e01fbce07 100644
--- a/chromium/third_party/dawn/src/tint/sem/expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/sem/expression_test.cc
@@ -23,13 +23,31 @@ using namespace tint::number_suffixes; // NOLINT
namespace tint::sem {
namespace {
+class MockConstant : public sem::Constant {
+ public:
+ explicit MockConstant(const sem::Type* ty) : type(ty) {}
+ ~MockConstant() override {}
+ const sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override { return {}; }
+ const Constant* Index(size_t) const override { return {}; }
+ bool AllZero() const override { return {}; }
+ bool AnyZero() const override { return {}; }
+ bool AllEqual() const override { return {}; }
+ size_t Hash() const override { return 0; }
+
+ private:
+ const sem::Type* type;
+};
+
using ExpressionTest = TestHelper;
TEST_F(ExpressionTest, UnwrapMaterialize) {
- auto* a = create<Expression>(/* declaration */ nullptr, create<I32>(), /* statement */ nullptr,
- Constant{},
+ MockConstant c(create<I32>());
+ auto* a = create<Expression>(/* declaration */ nullptr, create<I32>(),
+ sem::EvaluationStage::kRuntime, /* statement */ nullptr,
+ /* constant_value */ nullptr,
/* has_side_effects */ false, /* source_var */ nullptr);
- auto* b = create<Materialize>(a, /* statement */ nullptr, Constant{create<I32>(), {1_a}});
+ auto* b = create<Materialize>(a, /* statement */ nullptr, &c);
EXPECT_EQ(a, a->UnwrapMaterialize());
EXPECT_EQ(a, b->UnwrapMaterialize());
diff --git a/chromium/third_party/dawn/src/tint/sem/f16.h b/chromium/third_party/dawn/src/tint/sem/f16.h
index 72984c13e7f..87543ed0e4b 100644
--- a/chromium/third_party/dawn/src/tint/sem/f16.h
+++ b/chromium/third_party/dawn/src/tint/sem/f16.h
@@ -22,7 +22,7 @@
namespace tint::sem {
/// A float 16 type
-class F16 : public Castable<F16, Type> {
+class F16 final : public Castable<F16, Type> {
public:
/// Constructor
F16();
diff --git a/chromium/third_party/dawn/src/tint/sem/function.cc b/chromium/third_party/dawn/src/tint/sem/function.cc
index 790933b94a6..ff3a2a7085b 100644
--- a/chromium/third_party/dawn/src/tint/sem/function.cc
+++ b/chromium/third_party/dawn/src/tint/sem/function.cc
@@ -21,33 +21,40 @@
#include "src/tint/sem/sampled_texture.h"
#include "src/tint/sem/storage_texture.h"
#include "src/tint/sem/variable.h"
-#include "src/tint/utils/to_const_ptr_vec.h"
+#include "src/tint/utils/transform.h"
TINT_INSTANTIATE_TYPEINFO(tint::sem::Function);
namespace tint::sem {
+namespace {
-Function::Function(const ast::Function* declaration,
- Type* return_type,
- std::vector<Parameter*> parameters)
- : Base(return_type, utils::ToConstPtrVec(parameters)),
- declaration_(declaration),
- workgroup_size_{WorkgroupDimension{1}, WorkgroupDimension{1}, WorkgroupDimension{1}} {
+utils::VectorRef<const Parameter*> SetOwner(utils::VectorRef<Parameter*> parameters,
+ const tint::sem::CallTarget* owner) {
for (auto* parameter : parameters) {
- parameter->SetOwner(this);
+ parameter->SetOwner(owner);
}
+ return parameters;
}
+} // namespace
+
+Function::Function(const ast::Function* declaration,
+ Type* return_type,
+ utils::VectorRef<Parameter*> parameters)
+ : Base(return_type, SetOwner(std::move(parameters), this), EvaluationStage::kRuntime),
+ declaration_(declaration),
+ workgroup_size_{WorkgroupDimension{1}, WorkgroupDimension{1}, WorkgroupDimension{1}} {}
+
Function::~Function() = default;
std::vector<std::pair<const Variable*, const ast::LocationAttribute*>>
Function::TransitivelyReferencedLocationVariables() const {
std::vector<std::pair<const Variable*, const ast::LocationAttribute*>> ret;
- for (auto* var : TransitivelyReferencedGlobals()) {
- for (auto* attr : var->Declaration()->attributes) {
+ for (auto* global : TransitivelyReferencedGlobals()) {
+ for (auto* attr : global->Declaration()->attributes) {
if (auto* location = attr->As<ast::LocationAttribute>()) {
- ret.push_back({var, location});
+ ret.push_back({global, location});
break;
}
}
@@ -58,13 +65,13 @@ Function::TransitivelyReferencedLocationVariables() const {
Function::VariableBindings Function::TransitivelyReferencedUniformVariables() const {
VariableBindings ret;
- for (auto* var : TransitivelyReferencedGlobals()) {
- if (var->StorageClass() != ast::StorageClass::kUniform) {
+ for (auto* global : TransitivelyReferencedGlobals()) {
+ if (global->StorageClass() != ast::StorageClass::kUniform) {
continue;
}
- if (auto binding_point = var->Declaration()->BindingPoint()) {
- ret.push_back({var, binding_point});
+ if (auto binding_point = global->Declaration()->BindingPoint()) {
+ ret.push_back({global, binding_point});
}
}
return ret;
@@ -73,13 +80,13 @@ Function::VariableBindings Function::TransitivelyReferencedUniformVariables() co
Function::VariableBindings Function::TransitivelyReferencedStorageBufferVariables() const {
VariableBindings ret;
- for (auto* var : TransitivelyReferencedGlobals()) {
- if (var->StorageClass() != ast::StorageClass::kStorage) {
+ for (auto* global : TransitivelyReferencedGlobals()) {
+ if (global->StorageClass() != ast::StorageClass::kStorage) {
continue;
}
- if (auto binding_point = var->Declaration()->BindingPoint()) {
- ret.push_back({var, binding_point});
+ if (auto binding_point = global->Declaration()->BindingPoint()) {
+ ret.push_back({global, binding_point});
}
}
return ret;
@@ -89,10 +96,10 @@ std::vector<std::pair<const Variable*, const ast::BuiltinAttribute*>>
Function::TransitivelyReferencedBuiltinVariables() const {
std::vector<std::pair<const Variable*, const ast::BuiltinAttribute*>> ret;
- for (auto* var : TransitivelyReferencedGlobals()) {
- for (auto* attr : var->Declaration()->attributes) {
+ for (auto* global : TransitivelyReferencedGlobals()) {
+ for (auto* attr : global->Declaration()->attributes) {
if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
- ret.push_back({var, builtin});
+ ret.push_back({global, builtin});
break;
}
}
@@ -119,11 +126,11 @@ Function::VariableBindings Function::TransitivelyReferencedMultisampledTextureVa
Function::VariableBindings Function::TransitivelyReferencedVariablesOfType(
const tint::TypeInfo* type) const {
VariableBindings ret;
- for (auto* var : TransitivelyReferencedGlobals()) {
- auto* unwrapped_type = var->Type()->UnwrapRef();
+ for (auto* global : TransitivelyReferencedGlobals()) {
+ auto* unwrapped_type = global->Type()->UnwrapRef();
if (unwrapped_type->TypeInfo().Is(type)) {
- if (auto binding_point = var->Declaration()->BindingPoint()) {
- ret.push_back({var, binding_point});
+ if (auto binding_point = global->Declaration()->BindingPoint()) {
+ ret.push_back({global, binding_point});
}
}
}
@@ -143,15 +150,15 @@ Function::VariableBindings Function::TransitivelyReferencedSamplerVariablesImpl(
ast::SamplerKind kind) const {
VariableBindings ret;
- for (auto* var : TransitivelyReferencedGlobals()) {
- auto* unwrapped_type = var->Type()->UnwrapRef();
+ for (auto* global : TransitivelyReferencedGlobals()) {
+ auto* unwrapped_type = global->Type()->UnwrapRef();
auto* sampler = unwrapped_type->As<sem::Sampler>();
if (sampler == nullptr || sampler->kind() != kind) {
continue;
}
- if (auto binding_point = var->Declaration()->BindingPoint()) {
- ret.push_back({var, binding_point});
+ if (auto binding_point = global->Declaration()->BindingPoint()) {
+ ret.push_back({global, binding_point});
}
}
return ret;
@@ -161,8 +168,8 @@ Function::VariableBindings Function::TransitivelyReferencedSampledTextureVariabl
bool multisampled) const {
VariableBindings ret;
- for (auto* var : TransitivelyReferencedGlobals()) {
- auto* unwrapped_type = var->Type()->UnwrapRef();
+ for (auto* global : TransitivelyReferencedGlobals()) {
+ auto* unwrapped_type = global->Type()->UnwrapRef();
auto* texture = unwrapped_type->As<sem::Texture>();
if (texture == nullptr) {
continue;
@@ -175,8 +182,8 @@ Function::VariableBindings Function::TransitivelyReferencedSampledTextureVariabl
continue;
}
- if (auto binding_point = var->Declaration()->BindingPoint()) {
- ret.push_back({var, binding_point});
+ if (auto binding_point = global->Declaration()->BindingPoint()) {
+ ret.push_back({global, binding_point});
}
}
diff --git a/chromium/third_party/dawn/src/tint/sem/function.h b/chromium/third_party/dawn/src/tint/sem/function.h
index f95920a6bf8..a09f81c7569 100644
--- a/chromium/third_party/dawn/src/tint/sem/function.h
+++ b/chromium/third_party/dawn/src/tint/sem/function.h
@@ -22,6 +22,7 @@
#include "src/tint/ast/variable.h"
#include "src/tint/sem/call.h"
#include "src/tint/utils/unique_vector.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint::ast {
@@ -62,7 +63,7 @@ class Function final : public Castable<Function, CallTarget> {
/// @param parameters the parameters to the function
Function(const ast::Function* declaration,
Type* return_type,
- std::vector<Parameter*> parameters);
+ utils::VectorRef<Parameter*> parameters);
/// Destructor
~Function() override;
@@ -80,7 +81,7 @@ class Function final : public Castable<Function, CallTarget> {
}
/// @returns all directly referenced global variables
- const utils::UniqueVector<const GlobalVariable*>& DirectlyReferencedGlobals() const {
+ const utils::UniqueVector<const GlobalVariable*, 4>& DirectlyReferencedGlobals() const {
return directly_referenced_globals_;
}
@@ -88,12 +89,12 @@ class Function final : public Castable<Function, CallTarget> {
/// Note: Implicitly adds this global to the transtively-called globals.
/// @param global the module-scope variable
void AddDirectlyReferencedGlobal(const sem::GlobalVariable* global) {
- directly_referenced_globals_.add(global);
- transitively_referenced_globals_.add(global);
+ directly_referenced_globals_.Add(global);
+ transitively_referenced_globals_.Add(global);
}
/// @returns all transitively referenced global variables
- const utils::UniqueVector<const GlobalVariable*>& TransitivelyReferencedGlobals() const {
+ const utils::UniqueVector<const GlobalVariable*, 8>& TransitivelyReferencedGlobals() const {
return transitively_referenced_globals_;
}
@@ -101,29 +102,29 @@ class Function final : public Castable<Function, CallTarget> {
/// variable.
/// @param global the module-scoped variable
void AddTransitivelyReferencedGlobal(const sem::GlobalVariable* global) {
- transitively_referenced_globals_.add(global);
+ transitively_referenced_globals_.Add(global);
}
/// @returns the list of functions that this function transitively calls.
- const utils::UniqueVector<const Function*>& TransitivelyCalledFunctions() const {
+ const utils::UniqueVector<const Function*, 8>& TransitivelyCalledFunctions() const {
return transitively_called_functions_;
}
/// Records that this function transitively calls `function`.
/// @param function the function this function transitively calls
void AddTransitivelyCalledFunction(const Function* function) {
- transitively_called_functions_.add(function);
+ transitively_called_functions_.Add(function);
}
/// @returns the list of builtins that this function directly calls.
- const utils::UniqueVector<const Builtin*>& DirectlyCalledBuiltins() const {
+ const utils::UniqueVector<const Builtin*, 4>& DirectlyCalledBuiltins() const {
return directly_called_builtins_;
}
/// Records that this function transitively calls `builtin`.
/// @param builtin the builtin this function directly calls
void AddDirectlyCalledBuiltin(const Builtin* builtin) {
- directly_called_builtins_.add(builtin);
+ directly_called_builtins_.Add(builtin);
}
/// Adds the given texture/sampler pair to the list of unique pairs
@@ -133,12 +134,14 @@ class Function final : public Castable<Function, CallTarget> {
/// @param texture the texture (must be non-null)
/// @param sampler the sampler (null indicates a texture-only reference)
void AddTextureSamplerPair(const sem::Variable* texture, const sem::Variable* sampler) {
- texture_sampler_pairs_.add(VariablePair(texture, sampler));
+ texture_sampler_pairs_.Add(VariablePair(texture, sampler));
}
/// @returns the list of texture/sampler pairs that this function uses
/// (directly or indirectly).
- const std::vector<VariablePair>& TextureSamplerPairs() const { return texture_sampler_pairs_; }
+ const utils::Vector<VariablePair, 8>& TextureSamplerPairs() const {
+ return texture_sampler_pairs_;
+ }
/// @returns the list of direct calls to functions / builtins made by this
/// function
@@ -252,17 +255,20 @@ class Function final : public Castable<Function, CallTarget> {
sem::Behaviors& Behaviors() { return behaviors_; }
private:
+ Function(const Function&) = delete;
+ Function(Function&&) = delete;
+
VariableBindings TransitivelyReferencedSamplerVariablesImpl(ast::SamplerKind kind) const;
VariableBindings TransitivelyReferencedSampledTextureVariablesImpl(bool multisampled) const;
const ast::Function* const declaration_;
sem::WorkgroupSize workgroup_size_;
- utils::UniqueVector<const GlobalVariable*> directly_referenced_globals_;
- utils::UniqueVector<const GlobalVariable*> transitively_referenced_globals_;
- utils::UniqueVector<const Function*> transitively_called_functions_;
- utils::UniqueVector<const Builtin*> directly_called_builtins_;
- utils::UniqueVector<VariablePair> texture_sampler_pairs_;
+ utils::UniqueVector<const GlobalVariable*, 4> directly_referenced_globals_;
+ utils::UniqueVector<const GlobalVariable*, 8> transitively_referenced_globals_;
+ utils::UniqueVector<const Function*, 8> transitively_called_functions_;
+ utils::UniqueVector<const Builtin*, 4> directly_called_builtins_;
+ utils::UniqueVector<VariablePair, 8> texture_sampler_pairs_;
std::vector<const Call*> direct_calls_;
std::vector<const Call*> callsites_;
std::vector<const Function*> ancestor_entry_points_;
diff --git a/chromium/third_party/dawn/src/tint/sem/index_accessor_expression.cc b/chromium/third_party/dawn/src/tint/sem/index_accessor_expression.cc
new file mode 100644
index 00000000000..70d1d5f89c7
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/sem/index_accessor_expression.cc
@@ -0,0 +1,40 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/index_accessor_expression.h"
+
+#include "src/tint/ast/index_accessor_expression.h"
+
+#include <utility>
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::IndexAccessorExpression);
+
+namespace tint::sem {
+
+IndexAccessorExpression::IndexAccessorExpression(const ast::IndexAccessorExpression* declaration,
+ const sem::Type* type,
+ EvaluationStage stage,
+ const Expression* object,
+ const Expression* index,
+ const Statement* statement,
+ const Constant* constant,
+ bool has_side_effects,
+ const Variable* source_var /* = nullptr */)
+ : Base(declaration, type, stage, statement, constant, has_side_effects, source_var),
+ object_(object),
+ index_(index) {}
+
+IndexAccessorExpression::~IndexAccessorExpression() = default;
+
+} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/index_accessor_expression.h b/chromium/third_party/dawn/src/tint/sem/index_accessor_expression.h
new file mode 100644
index 00000000000..ea93df72ed8
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/sem/index_accessor_expression.h
@@ -0,0 +1,68 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_SEM_INDEX_ACCESSOR_EXPRESSION_H_
+#define SRC_TINT_SEM_INDEX_ACCESSOR_EXPRESSION_H_
+
+#include <vector>
+
+#include "src/tint/sem/expression.h"
+
+// Forward declarations
+namespace tint::ast {
+class IndexAccessorExpression;
+} // namespace tint::ast
+
+namespace tint::sem {
+
+/// IndexAccessorExpression holds the semantic information for a ast::IndexAccessorExpression node.
+class IndexAccessorExpression final : public Castable<IndexAccessorExpression, Expression> {
+ public:
+ /// Constructor
+ /// @param declaration the AST node
+ /// @param type the resolved type of the expression
+ /// @param stage the earliest evaluation stage for the expression
+ /// @param object the object expression that is being indexed
+ /// @param index the index expression
+ /// @param statement the statement that owns this expression
+ /// @param constant the constant value of the expression. May be null
+ /// @param has_side_effects whether this expression may have side effects
+ /// @param source_var the (optional) source variable for this expression
+ IndexAccessorExpression(const ast::IndexAccessorExpression* declaration,
+ const sem::Type* type,
+ EvaluationStage stage,
+ const Expression* object,
+ const Expression* index,
+ const Statement* statement,
+ const Constant* constant,
+ bool has_side_effects,
+ const Variable* source_var = nullptr);
+
+ /// Destructor
+ ~IndexAccessorExpression() override;
+
+ /// @returns the object expression that is being indexed
+ Expression const* Object() const { return object_; }
+
+ /// @returns the index expression
+ Expression const* Index() const { return index_; }
+
+ private:
+ Expression const* const object_;
+ Expression const* const index_;
+};
+
+} // namespace tint::sem
+
+#endif // SRC_TINT_SEM_INDEX_ACCESSOR_EXPRESSION_H_
diff --git a/chromium/third_party/dawn/src/tint/sem/info.h b/chromium/third_party/dawn/src/tint/sem/info.h
index 41321cff57b..894b408fe0a 100644
--- a/chromium/third_party/dawn/src/tint/sem/info.h
+++ b/chromium/third_party/dawn/src/tint/sem/info.h
@@ -15,9 +15,12 @@
#ifndef SRC_TINT_SEM_INFO_H_
#define SRC_TINT_SEM_INFO_H_
+#include <algorithm>
#include <type_traits>
#include <unordered_map>
+#include <vector>
+#include "src/tint/ast/node.h"
#include "src/tint/debug.h"
#include "src/tint/sem/node.h"
#include "src/tint/sem/type_mappings.h"
@@ -35,12 +38,11 @@ class Info {
/// Placeholder type used by Get() to provide a default value for EXPLICIT_SEM
using InferFromAST = std::nullptr_t;
- /// Resolves to the return type of the Get() method given the desired sementic
+ /// Resolves to the return type of the Get() method given the desired semantic
/// type and AST type.
- template <typename SEM, typename AST_OR_TYPE>
- using GetResultType = std::conditional_t<std::is_same<SEM, InferFromAST>::value,
- SemanticNodeTypeFor<AST_OR_TYPE>,
- SEM>;
+ template <typename SEM, typename AST>
+ using GetResultType =
+ std::conditional_t<std::is_same<SEM, InferFromAST>::value, SemanticNodeTypeFor<AST>, SEM>;
/// Constructor
Info();
@@ -56,36 +58,42 @@ class Info {
/// @return this Program
Info& operator=(Info&& rhs);
- /// Get looks up the semantic information for the AST or type node `node`.
- /// @param node the AST or type node
+ /// @param highest_node_id the last allocated (numerically highest) AST node identifier.
+ void Reserve(ast::NodeID highest_node_id) {
+ nodes_.resize(std::max(highest_node_id.value + 1, nodes_.size()));
+ }
+
+ /// Get looks up the semantic information for the AST node `ast_node`.
+ /// @param ast_node the AST node
/// @returns a pointer to the semantic node if found, otherwise nullptr
template <typename SEM = InferFromAST,
- typename AST_OR_TYPE = CastableBase,
- typename RESULT = GetResultType<SEM, AST_OR_TYPE>>
- const RESULT* Get(const AST_OR_TYPE* node) const {
- auto it = map_.find(node);
- if (it == map_.end()) {
- return nullptr;
+ typename AST = CastableBase,
+ typename RESULT = GetResultType<SEM, AST>>
+ const RESULT* Get(const AST* ast_node) const {
+ if (ast_node && ast_node->node_id.value < nodes_.size()) {
+ return As<RESULT>(nodes_[ast_node->node_id.value]);
}
- return As<RESULT>(it->second);
+ return nullptr;
}
- /// Add registers the semantic node `sem_node` for the AST or type node `node`.
- /// @param node the AST or type node
+ /// Add registers the semantic node `sem_node` for the AST node `ast_node`.
+ /// @param ast_node the AST node
/// @param sem_node the semantic node
- template <typename AST_OR_TYPE>
- void Add(const AST_OR_TYPE* node, const SemanticNodeTypeFor<AST_OR_TYPE>* sem_node) {
- // Check there's no semantic info already existing for the node
- TINT_ASSERT(Semantic, Get(node) == nullptr);
- map_.emplace(node, sem_node);
+ template <typename AST>
+ void Add(const AST* ast_node, const SemanticNodeTypeFor<AST>* sem_node) {
+ Reserve(ast_node->node_id);
+ // Check there's no semantic info already existing for the AST node
+ TINT_ASSERT(Semantic, nodes_[ast_node->node_id.value] == nullptr);
+ nodes_[ast_node->node_id.value] = sem_node;
}
- /// Replace replaces any existing semantic node `sem_node` for the AST or type node `node`.
- /// @param node the AST or type node
+ /// Replace replaces any existing semantic node `sem_node` for the AST node `ast_node`.
+ /// @param ast_node the AST node
/// @param sem_node the new semantic node
- template <typename AST_OR_TYPE>
- void Replace(const AST_OR_TYPE* node, const SemanticNodeTypeFor<AST_OR_TYPE>* sem_node) {
- map_[node] = sem_node;
+ template <typename AST>
+ void Replace(const AST* ast_node, const SemanticNodeTypeFor<AST>* sem_node) {
+ Reserve(ast_node->node_id);
+ nodes_[ast_node->node_id.value] = sem_node;
}
/// Wrap returns a new Info created with the contents of `inner`.
@@ -97,7 +105,7 @@ class Info {
/// @return the Info that wraps `inner`
static Info Wrap(const Info& inner) {
Info out;
- out.map_ = inner.map_;
+ out.nodes_ = inner.nodes_;
out.module_ = inner.module_;
return out;
}
@@ -110,9 +118,8 @@ class Info {
const sem::Module* Module() const { return module_; }
private:
- // TODO(crbug.com/tint/724): Once finished, this map should be:
- // std::unordered_map<const ast::Node*, const sem::Node*>
- std::unordered_map<const CastableBase*, const CastableBase*> map_;
+ // AST node index to semantic node
+ std::vector<const sem::Node*> nodes_;
// The semantic module
sem::Module* module_ = nullptr;
};
diff --git a/chromium/third_party/dawn/src/tint/sem/materialize.cc b/chromium/third_party/dawn/src/tint/sem/materialize.cc
index 76dd9d44055..15c31ae08c4 100644
--- a/chromium/third_party/dawn/src/tint/sem/materialize.cc
+++ b/chromium/third_party/dawn/src/tint/sem/materialize.cc
@@ -17,19 +17,17 @@
TINT_INSTANTIATE_TYPEINFO(tint::sem::Materialize);
namespace tint::sem {
-
-Materialize::Materialize(const Expression* expr, const Statement* statement, Constant constant)
+Materialize::Materialize(const Expression* expr,
+ const Statement* statement,
+ const Constant* constant)
: Base(/* declaration */ expr->Declaration(),
- /* type */ constant.Type(),
+ /* type */ constant->Type(),
+ /* stage */ EvaluationStage::kConstant, // Abstract can only be const-expr
/* statement */ statement,
/* constant */ constant,
/* has_side_effects */ false,
/* source_var */ expr->SourceVariable()),
- expr_(expr) {
- // Materialize nodes only wrap compile-time expressions, and so the Materialize expression must
- // have a constant value.
- TINT_ASSERT(Semantic, constant.IsValid());
-}
+ expr_(expr) {}
Materialize::~Materialize() = default;
diff --git a/chromium/third_party/dawn/src/tint/sem/materialize.h b/chromium/third_party/dawn/src/tint/sem/materialize.h
index a7c0e3af5eb..0cbac29ef60 100644
--- a/chromium/third_party/dawn/src/tint/sem/materialize.h
+++ b/chromium/third_party/dawn/src/tint/sem/materialize.h
@@ -31,7 +31,7 @@ class Materialize final : public Castable<Materialize, Expression> {
/// @param expr the inner expression, being materialized
/// @param statement the statement that owns this expression
/// @param constant the constant value of this expression
- Materialize(const Expression* expr, const Statement* statement, Constant constant);
+ Materialize(const Expression* expr, const Statement* statement, const Constant* constant);
/// Destructor
~Materialize() override;
diff --git a/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.cc b/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.cc
index 9dcca76ef0c..4d194a9d9ec 100644
--- a/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.cc
+++ b/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.cc
@@ -25,30 +25,53 @@ namespace tint::sem {
MemberAccessorExpression::MemberAccessorExpression(const ast::MemberAccessorExpression* declaration,
const sem::Type* type,
+ EvaluationStage stage,
const Statement* statement,
+ const Constant* constant,
+ const Expression* object,
bool has_side_effects,
const Variable* source_var /* = nullptr */)
- : Base(declaration, type, statement, Constant{}, has_side_effects, source_var) {}
+ : Base(declaration, type, stage, statement, constant, has_side_effects, source_var),
+ object_(object) {}
MemberAccessorExpression::~MemberAccessorExpression() = default;
StructMemberAccess::StructMemberAccess(const ast::MemberAccessorExpression* declaration,
const sem::Type* type,
const Statement* statement,
+ const Constant* constant,
+ const Expression* object,
const StructMember* member,
bool has_side_effects,
const Variable* source_var /* = nullptr */)
- : Base(declaration, type, statement, has_side_effects, source_var), member_(member) {}
+ : Base(declaration,
+ type,
+ object->Stage(),
+ statement,
+ constant,
+ object,
+ has_side_effects,
+ source_var),
+ member_(member) {}
StructMemberAccess::~StructMemberAccess() = default;
Swizzle::Swizzle(const ast::MemberAccessorExpression* declaration,
const sem::Type* type,
const Statement* statement,
- std::vector<uint32_t> indices,
+ const Constant* constant,
+ const Expression* object,
+ utils::VectorRef<uint32_t> indices,
bool has_side_effects,
const Variable* source_var /* = nullptr */)
- : Base(declaration, type, statement, has_side_effects, source_var),
+ : Base(declaration,
+ type,
+ object->Stage(),
+ statement,
+ constant,
+ object,
+ has_side_effects,
+ source_var),
indices_(std::move(indices)) {}
Swizzle::~Swizzle() = default;
diff --git a/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.h b/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.h
index 0233541e318..b8144f1ca2a 100644
--- a/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.h
+++ b/chromium/third_party/dawn/src/tint/sem/member_accessor_expression.h
@@ -15,9 +15,8 @@
#ifndef SRC_TINT_SEM_MEMBER_ACCESSOR_EXPRESSION_H_
#define SRC_TINT_SEM_MEMBER_ACCESSOR_EXPRESSION_H_
-#include <vector>
-
#include "src/tint/sem/expression.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint::ast {
@@ -37,17 +36,29 @@ class MemberAccessorExpression : public Castable<MemberAccessorExpression, Expre
/// Constructor
/// @param declaration the AST node
/// @param type the resolved type of the expression
+ /// @param stage the earliest evaluation stage for the expression
/// @param statement the statement that owns this expression
+ /// @param constant the constant value of the expression. May be null.
+ /// @param object the object that holds the member being accessed
/// @param has_side_effects whether this expression may have side effects
/// @param source_var the (optional) source variable for this expression
MemberAccessorExpression(const ast::MemberAccessorExpression* declaration,
const sem::Type* type,
+ EvaluationStage stage,
const Statement* statement,
+ const Constant* constant,
+ const Expression* object,
bool has_side_effects,
const Variable* source_var = nullptr);
/// Destructor
~MemberAccessorExpression() override;
+
+ /// @returns the object that holds the member being accessed
+ const Expression* Object() const { return object_; }
+
+ private:
+ Expression const* const object_;
};
/// StructMemberAccess holds the semantic information for a
@@ -59,12 +70,16 @@ class StructMemberAccess final : public Castable<StructMemberAccess, MemberAcces
/// @param declaration the AST node
/// @param type the resolved type of the expression
/// @param statement the statement that owns this expression
+ /// @param constant the constant value of the expression. May be null
+ /// @param object the object that holds the member being accessed
/// @param member the structure member
/// @param has_side_effects whether this expression may have side effects
/// @param source_var the (optional) source variable for this expression
StructMemberAccess(const ast::MemberAccessorExpression* declaration,
const sem::Type* type,
const Statement* statement,
+ const Constant* constant,
+ const Expression* object,
const StructMember* member,
bool has_side_effects,
const Variable* source_var = nullptr);
@@ -87,13 +102,17 @@ class Swizzle final : public Castable<Swizzle, MemberAccessorExpression> {
/// @param declaration the AST node
/// @param type the resolved type of the expression
/// @param statement the statement that owns this expression
+ /// @param constant the constant value of the expression. May be null
+ /// @param object the object that holds the member being accessed
/// @param indices the swizzle indices
/// @param has_side_effects whether this expression may have side effects
/// @param source_var the (optional) source variable for this expression
Swizzle(const ast::MemberAccessorExpression* declaration,
const sem::Type* type,
const Statement* statement,
- std::vector<uint32_t> indices,
+ const Constant* constant,
+ const Expression* object,
+ utils::VectorRef<uint32_t> indices,
bool has_side_effects,
const Variable* source_var = nullptr);
@@ -101,10 +120,10 @@ class Swizzle final : public Castable<Swizzle, MemberAccessorExpression> {
~Swizzle() override;
/// @return the swizzle indices, if this is a vector swizzle
- const std::vector<uint32_t>& Indices() const { return indices_; }
+ const auto& Indices() const { return indices_; }
private:
- std::vector<uint32_t> const indices_;
+ utils::Vector<uint32_t, 4> const indices_;
};
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/module.cc b/chromium/third_party/dawn/src/tint/sem/module.cc
index 7c606505728..38f0ec63ce6 100644
--- a/chromium/third_party/dawn/src/tint/sem/module.cc
+++ b/chromium/third_party/dawn/src/tint/sem/module.cc
@@ -21,7 +21,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Module);
namespace tint::sem {
-Module::Module(std::vector<const ast::Node*> dep_ordered_decls, ast::Extensions extensions)
+Module::Module(utils::VectorRef<const ast::Node*> dep_ordered_decls, ast::Extensions extensions)
: dep_ordered_decls_(std::move(dep_ordered_decls)), extensions_(std::move(extensions)) {}
Module::~Module() = default;
diff --git a/chromium/third_party/dawn/src/tint/sem/module.h b/chromium/third_party/dawn/src/tint/sem/module.h
index dffe003590d..b451c5bd529 100644
--- a/chromium/third_party/dawn/src/tint/sem/module.h
+++ b/chromium/third_party/dawn/src/tint/sem/module.h
@@ -15,10 +15,9 @@
#ifndef SRC_TINT_SEM_MODULE_H_
#define SRC_TINT_SEM_MODULE_H_
-#include <vector>
-
#include "src/tint/ast/extension.h"
#include "src/tint/sem/node.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint::ast {
@@ -34,13 +33,13 @@ class Module final : public Castable<Module, Node> {
/// Constructor
/// @param dep_ordered_decls the dependency-ordered module-scope declarations
/// @param extensions the list of enabled extensions in the module
- Module(std::vector<const ast::Node*> dep_ordered_decls, ast::Extensions extensions);
+ Module(utils::VectorRef<const ast::Node*> dep_ordered_decls, ast::Extensions extensions);
/// Destructor
~Module() override;
/// @returns the dependency-ordered global declarations for the module
- const std::vector<const ast::Node*>& DependencyOrderedDeclarations() const {
+ const utils::Vector<const ast::Node*, 64>& DependencyOrderedDeclarations() const {
return dep_ordered_decls_;
}
@@ -48,7 +47,7 @@ class Module final : public Castable<Module, Node> {
const ast::Extensions& Extensions() const { return extensions_; }
private:
- const std::vector<const ast::Node*> dep_ordered_decls_;
+ const utils::Vector<const ast::Node*, 64> dep_ordered_decls_;
ast::Extensions extensions_;
};
diff --git a/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc b/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc
index 010272a0a40..f929ce10fcd 100644
--- a/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc
+++ b/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc
@@ -13,11 +13,9 @@
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/intrinsic-gen
+// File generated by tools/src/cmd/gen
// using the template:
// src/tint/sem/parameter_usage.cc.tmpl
-// and the intrinsic defintion file:
-// src/tint/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc.tmpl b/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc.tmpl
index bc413e103a9..62cb42e6f20 100644
--- a/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc.tmpl
+++ b/chromium/third_party/dawn/src/tint/sem/parameter_usage.cc.tmpl
@@ -1,9 +1,12 @@
{{- /*
--------------------------------------------------------------------------------
-Template file for use with tools/builtin-gen to generate parameter_usage.cc
+Template file for use with tools/src/cmd/gen to generate parameter_usage.cc
+
+To update the generated file, run:
+ ./tools/run gen
See:
-* tools/cmd/intrinsic-gen/gen for structures used by this template
+* tools/src/cmd/gen for structures used by this template
* https://golang.org/pkg/text/template/ for documentation on the template syntax
--------------------------------------------------------------------------------
*/ -}}
@@ -16,7 +19,7 @@ const char* str(ParameterUsage usage) {
switch (usage) {
case ParameterUsage::kNone:
return "none";
-{{- range .Sem.UniqueParameterNames }}
+{{- range Sem.UniqueParameterNames }}
case ParameterUsage::k{{PascalCase .}}:
return "{{.}}";
{{- end }}
diff --git a/chromium/third_party/dawn/src/tint/sem/parameter_usage.h b/chromium/third_party/dawn/src/tint/sem/parameter_usage.h
index b17ae3e502e..b3585340042 100644
--- a/chromium/third_party/dawn/src/tint/sem/parameter_usage.h
+++ b/chromium/third_party/dawn/src/tint/sem/parameter_usage.h
@@ -13,11 +13,9 @@
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/intrinsic-gen
+// File generated by tools/src/cmd/gen
// using the template:
// src/tint/sem/parameter_usage.h.tmpl
-// and the intrinsic defintion file:
-// src/tint/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/third_party/dawn/src/tint/sem/parameter_usage.h.tmpl b/chromium/third_party/dawn/src/tint/sem/parameter_usage.h.tmpl
index b1b57895364..7c09805572c 100644
--- a/chromium/third_party/dawn/src/tint/sem/parameter_usage.h.tmpl
+++ b/chromium/third_party/dawn/src/tint/sem/parameter_usage.h.tmpl
@@ -1,9 +1,12 @@
{{- /*
--------------------------------------------------------------------------------
-Template file for use with tools/builtin-gen to generate parameter_usage.h
+Template file for use with tools/src/cmd/gen to generate parameter_usage.h
+
+To update the generated file, run:
+ ./tools/run gen
See:
-* tools/cmd/intrinsic-gen/gen for structures used by this template
+* tools/src/cmd/gen for structures used by this template
* https://golang.org/pkg/text/template/ for documentation on the template syntax
--------------------------------------------------------------------------------
*/ -}}
@@ -17,7 +20,7 @@ namespace tint::sem {
/// overload position
enum class ParameterUsage {
kNone = -1,
-{{- range .Sem.UniqueParameterNames }}
+{{- range Sem.UniqueParameterNames }}
k{{PascalCase .}},
{{- end }}
};
diff --git a/chromium/third_party/dawn/src/tint/sem/sem_struct_test.cc b/chromium/third_party/dawn/src/tint/sem/sem_struct_test.cc
index 4a6371284d9..3ea14e113d3 100644
--- a/chromium/third_party/dawn/src/tint/sem/sem_struct_test.cc
+++ b/chromium/third_party/dawn/src/tint/sem/sem_struct_test.cc
@@ -23,7 +23,7 @@ using StructTest = TestHelper;
TEST_F(StructTest, Creation) {
auto name = Sym("S");
- auto* impl = create<ast::Struct>(name, ast::StructMemberList{}, ast::AttributeList{});
+ auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty);
auto* ptr = impl;
auto* s = create<sem::Struct>(impl, impl->name, StructMemberList{}, 4u /* align */,
8u /* size */, 16u /* size_no_padding */);
@@ -34,10 +34,10 @@ TEST_F(StructTest, Creation) {
}
TEST_F(StructTest, Hash) {
- auto* a_impl = create<ast::Struct>(Sym("a"), ast::StructMemberList{}, ast::AttributeList{});
+ auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
auto* a = create<sem::Struct>(a_impl, a_impl->name, StructMemberList{}, 4u /* align */,
4u /* size */, 4u /* size_no_padding */);
- auto* b_impl = create<ast::Struct>(Sym("b"), ast::StructMemberList{}, ast::AttributeList{});
+ auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty);
auto* b = create<sem::Struct>(b_impl, b_impl->name, StructMemberList{}, 4u /* align */,
4u /* size */, 4u /* size_no_padding */);
@@ -45,10 +45,10 @@ TEST_F(StructTest, Hash) {
}
TEST_F(StructTest, Equals) {
- auto* a_impl = create<ast::Struct>(Sym("a"), ast::StructMemberList{}, ast::AttributeList{});
+ auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
auto* a = create<sem::Struct>(a_impl, a_impl->name, StructMemberList{}, 4u /* align */,
4u /* size */, 4u /* size_no_padding */);
- auto* b_impl = create<ast::Struct>(Sym("b"), ast::StructMemberList{}, ast::AttributeList{});
+ auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty);
auto* b = create<sem::Struct>(b_impl, b_impl->name, StructMemberList{}, 4u /* align */,
4u /* size */, 4u /* size_no_padding */);
@@ -59,7 +59,7 @@ TEST_F(StructTest, Equals) {
TEST_F(StructTest, FriendlyName) {
auto name = Sym("my_struct");
- auto* impl = create<ast::Struct>(name, ast::StructMemberList{}, ast::AttributeList{});
+ auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty);
auto* s = create<sem::Struct>(impl, impl->name, StructMemberList{}, 4u /* align */,
4u /* size */, 4u /* size_no_padding */);
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
@@ -67,7 +67,7 @@ TEST_F(StructTest, FriendlyName) {
TEST_F(StructTest, Layout) {
auto* inner_st = //
- Structure("Inner", {
+ Structure("Inner", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.u32()),
Member("c", ty.f32()),
@@ -75,7 +75,7 @@ TEST_F(StructTest, Layout) {
Member("e", ty.mat4x2<f32>()),
});
- auto* outer_st = Structure("Outer", {
+ auto* outer_st = Structure("Outer", utils::Vector{
Member("inner", ty.type_name("Inner")),
Member("a", ty.i32()),
});
diff --git a/chromium/third_party/dawn/src/tint/sem/storage_texture.cc b/chromium/third_party/dawn/src/tint/sem/storage_texture.cc
index d8393d77d88..5b743e9054c 100644
--- a/chromium/third_party/dawn/src/tint/sem/storage_texture.cc
+++ b/chromium/third_party/dawn/src/tint/sem/storage_texture.cc
@@ -75,7 +75,7 @@ sem::Type* StorageTexture::SubtypeFor(ast::TexelFormat format, sem::Manager& typ
return type_mgr.Get<sem::F32>();
}
- case ast::TexelFormat::kNone:
+ case ast::TexelFormat::kInvalid:
break;
}
diff --git a/chromium/third_party/dawn/src/tint/sem/struct.cc b/chromium/third_party/dawn/src/tint/sem/struct.cc
index eb0583b03b0..0ace9db55ff 100644
--- a/chromium/third_party/dawn/src/tint/sem/struct.cc
+++ b/chromium/third_party/dawn/src/tint/sem/struct.cc
@@ -157,7 +157,7 @@ bool Struct::IsConstructible() const {
StructMember::StructMember(const ast::StructMember* declaration,
Symbol name,
- sem::Type* type,
+ const sem::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
diff --git a/chromium/third_party/dawn/src/tint/sem/struct.h b/chromium/third_party/dawn/src/tint/sem/struct.h
index fe9169dc12c..62b1008ce38 100644
--- a/chromium/third_party/dawn/src/tint/sem/struct.h
+++ b/chromium/third_party/dawn/src/tint/sem/struct.h
@@ -170,7 +170,7 @@ class Struct final : public Castable<Struct, Type> {
};
/// StructMember holds the semantic information for structure members.
-class StructMember : public Castable<StructMember, Node> {
+class StructMember final : public Castable<StructMember, Node> {
public:
/// Constructor
/// @param declaration the AST declaration node
@@ -182,7 +182,7 @@ class StructMember : public Castable<StructMember, Node> {
/// @param size the byte size of the member
StructMember(const ast::StructMember* declaration,
Symbol name,
- sem::Type* type,
+ const sem::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
@@ -194,11 +194,18 @@ class StructMember : public Castable<StructMember, Node> {
/// @returns the AST declaration node
const ast::StructMember* Declaration() const { return declaration_; }
- /// @returns the name of the structure
+ /// @returns the name of the structure member
Symbol Name() const { return name_; }
+ /// Sets the owning structure to `s`
+ /// @param s the new structure owner
+ void SetStruct(const sem::Struct* s) { struct_ = s; }
+
+ /// @returns the structure that owns this member
+ const sem::Struct* Struct() const { return struct_; }
+
/// @returns the type of the member
- sem::Type* Type() const { return type_; }
+ const sem::Type* Type() const { return type_; }
/// @returns the member index
uint32_t Index() const { return index_; }
@@ -215,7 +222,8 @@ class StructMember : public Castable<StructMember, Node> {
private:
const ast::StructMember* const declaration_;
const Symbol name_;
- sem::Type* const type_;
+ const sem::Struct* struct_;
+ const sem::Type* type_;
const uint32_t index_;
const uint32_t offset_;
const uint32_t align_;
diff --git a/chromium/third_party/dawn/src/tint/sem/type.cc b/chromium/third_party/dawn/src/tint/sem/type.cc
index 40666e33412..b4887dd90e6 100644
--- a/chromium/third_party/dawn/src/tint/sem/type.cc
+++ b/chromium/third_party/dawn/src/tint/sem/type.cc
@@ -68,19 +68,15 @@ bool Type::IsConstructible() const {
}
bool Type::is_scalar() const {
- return IsAnyOf<F16, F32, U32, I32, Bool>();
-}
-
-bool Type::is_abstract_or_scalar() const {
- return IsAnyOf<F16, F32, U32, I32, Bool, AbstractNumeric>();
+ return IsAnyOf<F16, F32, U32, I32, AbstractNumeric, Bool>();
}
bool Type::is_numeric_scalar() const {
- return IsAnyOf<F16, F32, U32, I32>();
+ return IsAnyOf<F16, F32, U32, I32, AbstractNumeric>();
}
bool Type::is_float_scalar() const {
- return IsAnyOf<F16, F32>();
+ return IsAnyOf<F16, F32, AbstractNumeric>();
}
bool Type::is_float_matrix() const {
@@ -117,7 +113,7 @@ bool Type::is_unsigned_integer_scalar() const {
}
bool Type::is_signed_integer_vector() const {
- return Is([](const Vector* v) { return v->type()->Is<I32>(); });
+ return Is([](const Vector* v) { return v->type()->IsAnyOf<I32>(); });
}
bool Type::is_unsigned_integer_vector() const {
@@ -136,6 +132,22 @@ bool Type::is_integer_scalar_or_vector() const {
return is_unsigned_scalar_or_vector() || is_signed_scalar_or_vector();
}
+bool Type::is_abstract_integer_vector() const {
+ return Is([](const Vector* v) { return v->type()->Is<sem::AbstractInt>(); });
+}
+
+bool Type::is_abstract_float_vector() const {
+ return Is([](const Vector* v) { return v->type()->Is<sem::AbstractFloat>(); });
+}
+
+bool Type::is_abstract_integer_scalar_or_vector() const {
+ return Is<sem::AbstractInt>() || is_abstract_integer_vector();
+}
+
+bool Type::is_abstract_float_scalar_or_vector() const {
+ return Is<sem::AbstractFloat>() || is_abstract_float_vector();
+}
+
bool Type::is_bool_vector() const {
return Is([](const Vector* v) { return v->type()->Is<Bool>(); });
}
@@ -200,11 +212,19 @@ uint32_t Type::ConversionRank(const Type* from, const Type* to) {
}
return kNoConversion;
},
+ [&](const Array* from_arr) {
+ if (auto* to_arr = to->As<Array>()) {
+ if (from_arr->Count() == to_arr->Count()) {
+ return ConversionRank(from_arr->ElemType(), to_arr->ElemType());
+ }
+ }
+ return kNoConversion;
+ },
[&](Default) { return kNoConversion; });
}
const Type* Type::ElementOf(const Type* ty, uint32_t* count /* = nullptr */) {
- if (ty->is_abstract_or_scalar()) {
+ if (ty->is_scalar()) {
if (count) {
*count = 1;
}
@@ -220,19 +240,40 @@ const Type* Type::ElementOf(const Type* ty, uint32_t* count /* = nullptr */) {
},
[&](const Matrix* m) {
if (count) {
- *count = m->columns() * m->rows();
+ *count = m->columns();
}
- return m->type();
+ return m->ColumnType();
},
[&](const Array* a) {
if (count) {
*count = a->Count();
}
return a->ElemType();
+ },
+ [&](Default) {
+ if (count) {
+ *count = 0;
+ }
+ return nullptr;
});
}
-const sem::Type* Type::Common(Type const* const* types, size_t count) {
+const Type* Type::DeepestElementOf(const Type* ty, uint32_t* count /* = nullptr */) {
+ auto el_ty = ElementOf(ty, count);
+ while (el_ty && ty != el_ty) {
+ ty = el_ty;
+
+ uint32_t n = 0;
+ el_ty = ElementOf(ty, &n);
+ if (count) {
+ *count *= n;
+ }
+ }
+ return el_ty;
+}
+
+const sem::Type* Type::Common(utils::VectorRef<const Type*> types) {
+ const auto count = types.Length();
if (count == 0) {
return nullptr;
}
diff --git a/chromium/third_party/dawn/src/tint/sem/type.h b/chromium/third_party/dawn/src/tint/sem/type.h
index 99876375f8b..8bac821ca48 100644
--- a/chromium/third_party/dawn/src/tint/sem/type.h
+++ b/chromium/third_party/dawn/src/tint/sem/type.h
@@ -19,6 +19,7 @@
#include <string>
#include "src/tint/sem/node.h"
+#include "src/tint/utils/vector.h"
// Forward declarations
namespace tint {
@@ -71,8 +72,6 @@ class Type : public Castable<Type, Node> {
/// @returns true if this type is a scalar
bool is_scalar() const;
- /// @returns true if this type is a scalar or an abstract numeric
- bool is_abstract_or_scalar() const;
/// @returns true if this type is a numeric scalar
bool is_numeric_scalar() const;
/// @returns true if this type is a float scalar
@@ -103,6 +102,14 @@ class Type : public Castable<Type, Node> {
bool is_signed_scalar_or_vector() const;
/// @returns true if this type is an integer scalar or vector
bool is_integer_scalar_or_vector() const;
+ /// @returns true if this type is an abstract integer vector
+ bool is_abstract_integer_vector() const;
+ /// @returns true if this type is an abstract float vector
+ bool is_abstract_float_vector() const;
+ /// @returns true if this type is an abstract integer scalar or vector
+ bool is_abstract_integer_scalar_or_vector() const;
+ /// @returns true if this type is an abstract float scalar or vector
+ bool is_abstract_float_scalar_or_vector() const;
/// @returns true if this type is a boolean vector
bool is_bool_vector() const;
/// @returns true if this type is boolean scalar or vector
@@ -130,25 +137,31 @@ class Type : public Castable<Type, Node> {
static uint32_t ConversionRank(const Type* from, const Type* to);
/// @param ty the type to obtain the element type from
- /// @param count if not null, then this is assigned the number of elements in the type
- /// @returns `ty` if `ty` is an abstract or scalar, the element type if ty is a vector, matrix
- /// or array, otherwise nullptr.
+ /// @param count if not null, then this is assigned the number of child elements in the type.
+ /// For example, the count of an `array<vec3<f32>, 5>` type would be 5.
+ /// @returns
+ /// * `ty` if `ty` is an abstract or scalar
+ /// * the element type if `ty` is a vector or array
+ /// * the column type if `ty` is a matrix
+ /// * `nullptr` if `ty` is none of the above
static const Type* ElementOf(const Type* ty, uint32_t* count = nullptr);
- /// @param types a pointer to a list of `const Type*`.
- /// @param count the number of types in `types`.
+ /// @param ty the type to obtain the deepest element type from
+ /// @param count if not null, then this is assigned the full number of most deeply nested
+ /// elements in the type. For example, the count of an `array<vec3<f32>, 5>` type would be 15.
+ /// @returns
+ /// * `ty` if `ty` is an abstract or scalar
+ /// * the element type if `ty` is a vector
+ /// * the matrix element type if `ty` is a matrix
+ /// * the deepest element type if `ty` is an array
+ /// * `nullptr` if `ty` is none of the above
+ static const Type* DeepestElementOf(const Type* ty, uint32_t* count = nullptr);
+
+ /// @param types the list of types
/// @returns the lowest-ranking type that all types in `types` can be implicitly converted to,
- /// or nullptr if there is no consistent common type across all types in `types`.
+ /// or nullptr if there is no consistent common type across all types in `types`.
/// @see https://www.w3.org/TR/WGSL/#conversion-rank
- static const sem::Type* Common(Type const* const* types, size_t count);
-
- /// @param types an initializer_list of `const Type*`.
- /// @returns the lowest-ranking type that all types in `types` can be implicitly converted to,
- /// or nullptr if there is no consistent common type across all types in `types`.
- /// @see https://www.w3.org/TR/WGSL/#conversion-rank
- static const sem::Type* Common(std::initializer_list<const Type*> types) {
- return Common(types.begin(), types.size());
- }
+ static const sem::Type* Common(utils::VectorRef<const Type*> types);
protected:
Type();
diff --git a/chromium/third_party/dawn/src/tint/sem/type_constructor.cc b/chromium/third_party/dawn/src/tint/sem/type_constructor.cc
index 34f6e2a71f4..2acf74ff0f7 100644
--- a/chromium/third_party/dawn/src/tint/sem/type_constructor.cc
+++ b/chromium/third_party/dawn/src/tint/sem/type_constructor.cc
@@ -14,12 +14,16 @@
#include "src/tint/sem/type_constructor.h"
+#include <utility>
+
TINT_INSTANTIATE_TYPEINFO(tint::sem::TypeConstructor);
namespace tint::sem {
-TypeConstructor::TypeConstructor(const sem::Type* type, const ParameterList& parameters)
- : Base(type, parameters) {}
+TypeConstructor::TypeConstructor(const sem::Type* type,
+ utils::VectorRef<const Parameter*> parameters,
+ EvaluationStage stage)
+ : Base(type, std::move(parameters), stage) {}
TypeConstructor::~TypeConstructor() = default;
diff --git a/chromium/third_party/dawn/src/tint/sem/type_constructor.h b/chromium/third_party/dawn/src/tint/sem/type_constructor.h
index f3d4221550b..1995db893ca 100644
--- a/chromium/third_party/dawn/src/tint/sem/type_constructor.h
+++ b/chromium/third_party/dawn/src/tint/sem/type_constructor.h
@@ -16,6 +16,7 @@
#define SRC_TINT_SEM_TYPE_CONSTRUCTOR_H_
#include "src/tint/sem/call_target.h"
+#include "src/tint/utils/vector.h"
namespace tint::sem {
@@ -25,7 +26,10 @@ class TypeConstructor final : public Castable<TypeConstructor, CallTarget> {
/// Constructor
/// @param type the type that's being constructed
/// @param parameters the type constructor parameters
- TypeConstructor(const sem::Type* type, const ParameterList& parameters);
+ /// @param stage the earliest evaluation stage for the expression
+ TypeConstructor(const sem::Type* type,
+ utils::VectorRef<const Parameter*> parameters,
+ EvaluationStage stage);
/// Destructor
~TypeConstructor() override;
diff --git a/chromium/third_party/dawn/src/tint/sem/type_conversion.cc b/chromium/third_party/dawn/src/tint/sem/type_conversion.cc
index 5da2928582e..42fa2e05b6c 100644
--- a/chromium/third_party/dawn/src/tint/sem/type_conversion.cc
+++ b/chromium/third_party/dawn/src/tint/sem/type_conversion.cc
@@ -18,8 +18,10 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::TypeConversion);
namespace tint::sem {
-TypeConversion::TypeConversion(const sem::Type* type, const sem::Parameter* parameter)
- : Base(type, ParameterList{parameter}) {}
+TypeConversion::TypeConversion(const sem::Type* type,
+ const sem::Parameter* parameter,
+ EvaluationStage stage)
+ : Base(type, utils::Vector<const sem::Parameter*, 1>{parameter}, stage) {}
TypeConversion::~TypeConversion() = default;
diff --git a/chromium/third_party/dawn/src/tint/sem/type_conversion.h b/chromium/third_party/dawn/src/tint/sem/type_conversion.h
index e40056508e7..5584b36fe35 100644
--- a/chromium/third_party/dawn/src/tint/sem/type_conversion.h
+++ b/chromium/third_party/dawn/src/tint/sem/type_conversion.h
@@ -25,7 +25,8 @@ class TypeConversion final : public Castable<TypeConversion, CallTarget> {
/// Constructor
/// @param type the target type of the cast
/// @param parameter the type cast parameter
- TypeConversion(const sem::Type* type, const sem::Parameter* parameter);
+ /// @param stage the earliest evaluation stage for the expression
+ TypeConversion(const sem::Type* type, const sem::Parameter* parameter, EvaluationStage stage);
/// Destructor
~TypeConversion() override;
diff --git a/chromium/third_party/dawn/src/tint/sem/type_mappings.h b/chromium/third_party/dawn/src/tint/sem/type_mappings.h
index 0e54eed7599..07d32b31dfa 100644
--- a/chromium/third_party/dawn/src/tint/sem/type_mappings.h
+++ b/chromium/third_party/dawn/src/tint/sem/type_mappings.h
@@ -20,13 +20,12 @@
// Forward declarations
namespace tint::ast {
class Array;
-class CallExpression;
class Expression;
class ForLoopStatement;
class Function;
class IfStatement;
-class MemberAccessorExpression;
class Node;
+class Override;
class Statement;
class Struct;
class StructMember;
@@ -34,22 +33,23 @@ class SwitchStatement;
class Type;
class TypeDecl;
class Variable;
+class WhileStatement;
} // namespace tint::ast
namespace tint::sem {
class Array;
-class Call;
class Expression;
class ForLoopStatement;
class Function;
class IfStatement;
-class MemberAccessorExpression;
class Node;
+class GlobalVariable;
class Statement;
class Struct;
class StructMember;
class SwitchStatement;
class Type;
class Variable;
+class WhileStatement;
} // namespace tint::sem
namespace tint::sem {
@@ -65,8 +65,8 @@ struct TypeMappings {
ForLoopStatement* operator()(ast::ForLoopStatement*);
Function* operator()(ast::Function*);
IfStatement* operator()(ast::IfStatement*);
- MemberAccessorExpression* operator()(ast::MemberAccessorExpression*);
Node* operator()(ast::Node*);
+ GlobalVariable* operator()(ast::Override*);
Statement* operator()(ast::Statement*);
Struct* operator()(ast::Struct*);
StructMember* operator()(ast::StructMember*);
@@ -74,6 +74,7 @@ struct TypeMappings {
Type* operator()(ast::Type*);
Type* operator()(ast::TypeDecl*);
Variable* operator()(ast::Variable*);
+ WhileStatement* operator()(ast::WhileStatement*);
//! @endcond
};
diff --git a/chromium/third_party/dawn/src/tint/sem/type_test.cc b/chromium/third_party/dawn/src/tint/sem/type_test.cc
index c11efea9f28..837579ef84a 100644
--- a/chromium/third_party/dawn/src/tint/sem/type_test.cc
+++ b/chromium/third_party/dawn/src/tint/sem/type_test.cc
@@ -14,34 +14,110 @@
#include "src/tint/sem/abstract_float.h"
#include "src/tint/sem/abstract_int.h"
+#include "src/tint/sem/f16.h"
#include "src/tint/sem/reference.h"
#include "src/tint/sem/test_helper.h"
namespace tint::sem {
namespace {
-using TypeTest = TestHelper;
+struct TypeTest : public TestHelper {
+ const sem::AbstractFloat* af = create<AbstractFloat>();
+ const sem::AbstractInt* ai = create<AbstractInt>();
+ const sem::F32* f32 = create<F32>();
+ const sem::F16* f16 = create<F16>();
+ const sem::I32* i32 = create<I32>();
+ const sem::U32* u32 = create<U32>();
+ const sem::Vector* vec2_f32 = create<Vector>(f32, 2u);
+ const sem::Vector* vec3_f32 = create<Vector>(f32, 3u);
+ const sem::Vector* vec3_f16 = create<Vector>(f16, 3u);
+ const sem::Vector* vec4_f32 = create<Vector>(f32, 4u);
+ const sem::Vector* vec3_u32 = create<Vector>(u32, 3u);
+ const sem::Vector* vec3_i32 = create<Vector>(i32, 3u);
+ const sem::Vector* vec3_af = create<Vector>(af, 3u);
+ const sem::Vector* vec3_ai = create<Vector>(ai, 3u);
+ const sem::Matrix* mat2x4_f32 = create<Matrix>(vec4_f32, 2u);
+ const sem::Matrix* mat3x4_f32 = create<Matrix>(vec4_f32, 3u);
+ const sem::Matrix* mat4x2_f32 = create<Matrix>(vec2_f32, 4u);
+ const sem::Matrix* mat4x3_f32 = create<Matrix>(vec3_f32, 4u);
+ const sem::Matrix* mat4x3_f16 = create<Matrix>(vec3_f16, 4u);
+ const sem::Matrix* mat4x3_af = create<Matrix>(vec3_af, 4u);
+ const sem::Reference* ref_u32 =
+ create<Reference>(u32, ast::StorageClass::kPrivate, ast::Access::kReadWrite);
+ const sem::Struct* str = create<Struct>(nullptr,
+ Sym("s"),
+ StructMemberList{
+ create<StructMember>(
+ /* declaration */ nullptr,
+ /* name */ Sym("x"),
+ /* type */ f16,
+ /* index */ 0u,
+ /* offset */ 0u,
+ /* align */ 4u,
+ /* size */ 4u),
+ },
+ /* align*/ 4u,
+ /* size*/ 4u,
+ /* size_no_padding*/ 4u);
+ const sem::Array* arr_i32 = create<Array>(
+ /* element */ i32,
+ /* count */ 5u,
+ /* align */ 4u,
+ /* size */ 5u * 4u,
+ /* stride */ 5u * 4u,
+ /* implicit_stride */ 5u * 4u);
+ const sem::Array* arr_ai = create<Array>(
+ /* element */ ai,
+ /* count */ 5u,
+ /* align */ 4u,
+ /* size */ 5u * 4u,
+ /* stride */ 5u * 4u,
+ /* implicit_stride */ 5u * 4u);
+ const sem::Array* arr_vec3_i32 = create<Array>(
+ /* element */ vec3_i32,
+ /* count */ 5u,
+ /* align */ 16u,
+ /* size */ 5u * 16u,
+ /* stride */ 5u * 16u,
+ /* implicit_stride */ 5u * 16u);
+ const sem::Array* arr_vec3_ai = create<Array>(
+ /* element */ vec3_ai,
+ /* count */ 5u,
+ /* align */ 16u,
+ /* size */ 5u * 16u,
+ /* stride */ 5u * 16u,
+ /* implicit_stride */ 5u * 16u);
+ const sem::Array* arr_mat4x3_f16 = create<Array>(
+ /* element */ mat4x3_f16,
+ /* count */ 5u,
+ /* align */ 32u,
+ /* size */ 5u * 32u,
+ /* stride */ 5u * 32u,
+ /* implicit_stride */ 5u * 32u);
+ const sem::Array* arr_mat4x3_f32 = create<Array>(
+ /* element */ mat4x3_f32,
+ /* count */ 5u,
+ /* align */ 64u,
+ /* size */ 5u * 64u,
+ /* stride */ 5u * 64u,
+ /* implicit_stride */ 5u * 64u);
+ const sem::Array* arr_mat4x3_af = create<Array>(
+ /* element */ mat4x3_af,
+ /* count */ 5u,
+ /* align */ 64u,
+ /* size */ 5u * 64u,
+ /* stride */ 5u * 64u,
+ /* implicit_stride */ 5u * 64u);
+ const sem::Array* arr_str = create<Array>(
+ /* element */ str,
+ /* count */ 5u,
+ /* align */ 4u,
+ /* size */ 5u * 4u,
+ /* stride */ 5u * 4u,
+ /* implicit_stride */ 5u * 4u);
+};
TEST_F(TypeTest, ConversionRank) {
- auto* af = create<AbstractFloat>();
- auto* ai = create<AbstractInt>();
- auto* f32 = create<F32>();
- auto* f16 = create<F16>();
- auto* i32 = create<I32>();
- auto* u32 = create<U32>();
- auto* vec3_f32 = create<Vector>(f32, 3u);
- auto* vec3_f16 = create<Vector>(f16, 3u);
- auto* vec4_f32 = create<Vector>(f32, 4u);
- auto* vec3_u32 = create<Vector>(u32, 3u);
- auto* vec3_i32 = create<Vector>(i32, 3u);
- auto* vec3_af = create<Vector>(af, 3u);
- auto* vec3_ai = create<Vector>(ai, 3u);
- auto* mat3x4_f32 = create<Matrix>(vec4_f32, 3u);
- auto* mat4x3_f32 = create<Matrix>(vec3_f32, 4u);
- auto* mat4x3_f16 = create<Matrix>(vec3_f16, 4u);
- auto* mat4x3_af = create<Matrix>(vec3_af, 4u);
- auto* ref_u32 = create<Reference>(u32, ast::StorageClass::kPrivate, ast::Access::kReadWrite);
-
EXPECT_EQ(Type::ConversionRank(i32, i32), 0u);
EXPECT_EQ(Type::ConversionRank(f32, f32), 0u);
EXPECT_EQ(Type::ConversionRank(u32, u32), 0u);
@@ -55,17 +131,24 @@ TEST_F(TypeTest, ConversionRank) {
EXPECT_EQ(Type::ConversionRank(mat3x4_f32, mat3x4_f32), 0u);
EXPECT_EQ(Type::ConversionRank(mat4x3_f32, mat4x3_f32), 0u);
EXPECT_EQ(Type::ConversionRank(mat4x3_f16, mat4x3_f16), 0u);
+ EXPECT_EQ(Type::ConversionRank(arr_vec3_ai, arr_vec3_ai), 0u);
+ EXPECT_EQ(Type::ConversionRank(arr_mat4x3_f16, arr_mat4x3_f16), 0u);
EXPECT_EQ(Type::ConversionRank(mat4x3_af, mat4x3_af), 0u);
+ EXPECT_EQ(Type::ConversionRank(arr_mat4x3_af, arr_mat4x3_af), 0u);
EXPECT_EQ(Type::ConversionRank(ref_u32, u32), 0u);
EXPECT_EQ(Type::ConversionRank(af, f32), 1u);
EXPECT_EQ(Type::ConversionRank(vec3_af, vec3_f32), 1u);
EXPECT_EQ(Type::ConversionRank(mat4x3_af, mat4x3_f32), 1u);
+ EXPECT_EQ(Type::ConversionRank(arr_mat4x3_af, arr_mat4x3_f32), 1u);
EXPECT_EQ(Type::ConversionRank(af, f16), 2u);
EXPECT_EQ(Type::ConversionRank(vec3_af, vec3_f16), 2u);
EXPECT_EQ(Type::ConversionRank(mat4x3_af, mat4x3_f16), 2u);
+ EXPECT_EQ(Type::ConversionRank(arr_mat4x3_af, arr_mat4x3_f16), 2u);
EXPECT_EQ(Type::ConversionRank(ai, i32), 3u);
EXPECT_EQ(Type::ConversionRank(vec3_ai, vec3_i32), 3u);
+ EXPECT_EQ(Type::ConversionRank(arr_ai, arr_i32), 3u);
+ EXPECT_EQ(Type::ConversionRank(arr_vec3_ai, arr_vec3_i32), 3u);
EXPECT_EQ(Type::ConversionRank(ai, u32), 4u);
EXPECT_EQ(Type::ConversionRank(vec3_ai, vec3_u32), 4u);
EXPECT_EQ(Type::ConversionRank(ai, af), 5u);
@@ -80,6 +163,9 @@ TEST_F(TypeTest, ConversionRank) {
EXPECT_EQ(Type::ConversionRank(mat3x4_f32, mat4x3_f32), Type::kNoConversion);
EXPECT_EQ(Type::ConversionRank(mat4x3_f32, mat3x4_f32), Type::kNoConversion);
EXPECT_EQ(Type::ConversionRank(mat4x3_f32, mat4x3_af), Type::kNoConversion);
+ EXPECT_EQ(Type::ConversionRank(arr_vec3_i32, arr_vec3_ai), Type::kNoConversion);
+ EXPECT_EQ(Type::ConversionRank(arr_mat4x3_f32, arr_mat4x3_af), Type::kNoConversion);
+ EXPECT_EQ(Type::ConversionRank(arr_mat4x3_f16, arr_mat4x3_f32), Type::kNoConversion);
EXPECT_EQ(Type::ConversionRank(f32, af), Type::kNoConversion);
EXPECT_EQ(Type::ConversionRank(f16, af), Type::kNoConversion);
EXPECT_EQ(Type::ConversionRank(vec3_f16, vec3_af), Type::kNoConversion);
@@ -92,26 +178,6 @@ TEST_F(TypeTest, ConversionRank) {
}
TEST_F(TypeTest, ElementOf) {
- auto* f32 = create<F32>();
- auto* f16 = create<F16>();
- auto* i32 = create<I32>();
- auto* u32 = create<U32>();
- auto* vec2_f32 = create<Vector>(f32, 2u);
- auto* vec3_f16 = create<Vector>(f16, 3u);
- auto* vec4_f32 = create<Vector>(f32, 4u);
- auto* vec3_u32 = create<Vector>(u32, 3u);
- auto* vec3_i32 = create<Vector>(i32, 3u);
- auto* mat2x4_f32 = create<Matrix>(vec4_f32, 2u);
- auto* mat4x2_f32 = create<Matrix>(vec2_f32, 4u);
- auto* mat4x3_f16 = create<Matrix>(vec3_f16, 4u);
- auto* arr_i32 = create<Array>(
- /* element */ i32,
- /* count */ 5u,
- /* align */ 4u,
- /* size */ 5u * 4u,
- /* stride */ 5u * 4u,
- /* implicit_stride */ 5u * 4u);
-
// No count
EXPECT_TYPE(Type::ElementOf(f32), f32);
EXPECT_TYPE(Type::ElementOf(f16), f16);
@@ -122,271 +188,340 @@ TEST_F(TypeTest, ElementOf) {
EXPECT_TYPE(Type::ElementOf(vec4_f32), f32);
EXPECT_TYPE(Type::ElementOf(vec3_u32), u32);
EXPECT_TYPE(Type::ElementOf(vec3_i32), i32);
- EXPECT_TYPE(Type::ElementOf(mat2x4_f32), f32);
- EXPECT_TYPE(Type::ElementOf(mat4x2_f32), f32);
- EXPECT_TYPE(Type::ElementOf(mat4x3_f16), f16);
+ EXPECT_TYPE(Type::ElementOf(mat2x4_f32), vec4_f32);
+ EXPECT_TYPE(Type::ElementOf(mat4x2_f32), vec2_f32);
+ EXPECT_TYPE(Type::ElementOf(mat4x3_f16), vec3_f16);
+ EXPECT_TYPE(Type::ElementOf(str), nullptr);
EXPECT_TYPE(Type::ElementOf(arr_i32), i32);
+ EXPECT_TYPE(Type::ElementOf(arr_vec3_i32), vec3_i32);
+ EXPECT_TYPE(Type::ElementOf(arr_mat4x3_f16), mat4x3_f16);
+ EXPECT_TYPE(Type::ElementOf(arr_mat4x3_af), mat4x3_af);
+ EXPECT_TYPE(Type::ElementOf(arr_str), str);
// With count
- uint32_t count = 0;
+ uint32_t count = 42;
EXPECT_TYPE(Type::ElementOf(f32, &count), f32);
EXPECT_EQ(count, 1u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(f16, &count), f16);
EXPECT_EQ(count, 1u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(i32, &count), i32);
EXPECT_EQ(count, 1u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(u32, &count), u32);
EXPECT_EQ(count, 1u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(vec2_f32, &count), f32);
EXPECT_EQ(count, 2u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(vec3_f16, &count), f16);
EXPECT_EQ(count, 3u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(vec4_f32, &count), f32);
EXPECT_EQ(count, 4u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(vec3_u32, &count), u32);
EXPECT_EQ(count, 3u);
- count = 0;
+ count = 42;
EXPECT_TYPE(Type::ElementOf(vec3_i32, &count), i32);
EXPECT_EQ(count, 3u);
- count = 0;
- EXPECT_TYPE(Type::ElementOf(mat2x4_f32, &count), f32);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(mat2x4_f32, &count), vec4_f32);
+ EXPECT_EQ(count, 2u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(mat4x2_f32, &count), vec2_f32);
+ EXPECT_EQ(count, 4u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(mat4x3_f16, &count), vec3_f16);
+ EXPECT_EQ(count, 4u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(str, &count), nullptr);
+ EXPECT_EQ(count, 0u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(arr_i32, &count), i32);
+ EXPECT_EQ(count, 5u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(arr_vec3_i32, &count), vec3_i32);
+ EXPECT_EQ(count, 5u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(arr_mat4x3_f16, &count), mat4x3_f16);
+ EXPECT_EQ(count, 5u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(arr_mat4x3_af, &count), mat4x3_af);
+ EXPECT_EQ(count, 5u);
+ count = 42;
+ EXPECT_TYPE(Type::ElementOf(arr_str, &count), str);
+ EXPECT_EQ(count, 5u);
+}
+
+TEST_F(TypeTest, DeepestElementOf) {
+ // No count
+ EXPECT_TYPE(Type::DeepestElementOf(f32), f32);
+ EXPECT_TYPE(Type::DeepestElementOf(f16), f16);
+ EXPECT_TYPE(Type::DeepestElementOf(i32), i32);
+ EXPECT_TYPE(Type::DeepestElementOf(u32), u32);
+ EXPECT_TYPE(Type::DeepestElementOf(vec2_f32), f32);
+ EXPECT_TYPE(Type::DeepestElementOf(vec3_f16), f16);
+ EXPECT_TYPE(Type::DeepestElementOf(vec4_f32), f32);
+ EXPECT_TYPE(Type::DeepestElementOf(vec3_u32), u32);
+ EXPECT_TYPE(Type::DeepestElementOf(vec3_i32), i32);
+ EXPECT_TYPE(Type::DeepestElementOf(mat2x4_f32), f32);
+ EXPECT_TYPE(Type::DeepestElementOf(mat4x2_f32), f32);
+ EXPECT_TYPE(Type::DeepestElementOf(mat4x3_f16), f16);
+ EXPECT_TYPE(Type::DeepestElementOf(str), nullptr);
+ EXPECT_TYPE(Type::DeepestElementOf(arr_i32), i32);
+ EXPECT_TYPE(Type::DeepestElementOf(arr_vec3_i32), i32);
+ EXPECT_TYPE(Type::DeepestElementOf(arr_mat4x3_f16), f16);
+ EXPECT_TYPE(Type::DeepestElementOf(arr_mat4x3_af), af);
+ EXPECT_TYPE(Type::DeepestElementOf(arr_str), nullptr);
+
+ // With count
+ uint32_t count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(f32, &count), f32);
+ EXPECT_EQ(count, 1u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(f16, &count), f16);
+ EXPECT_EQ(count, 1u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(i32, &count), i32);
+ EXPECT_EQ(count, 1u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(u32, &count), u32);
+ EXPECT_EQ(count, 1u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(vec2_f32, &count), f32);
+ EXPECT_EQ(count, 2u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(vec3_f16, &count), f16);
+ EXPECT_EQ(count, 3u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(vec4_f32, &count), f32);
+ EXPECT_EQ(count, 4u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(vec3_u32, &count), u32);
+ EXPECT_EQ(count, 3u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(vec3_i32, &count), i32);
+ EXPECT_EQ(count, 3u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(mat2x4_f32, &count), f32);
EXPECT_EQ(count, 8u);
- count = 0;
- EXPECT_TYPE(Type::ElementOf(mat4x2_f32, &count), f32);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(mat4x2_f32, &count), f32);
EXPECT_EQ(count, 8u);
- count = 0;
- EXPECT_TYPE(Type::ElementOf(mat4x3_f16, &count), f16);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(mat4x3_f16, &count), f16);
EXPECT_EQ(count, 12u);
- count = 0;
- EXPECT_TYPE(Type::ElementOf(arr_i32, &count), i32);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(str, &count), nullptr);
+ EXPECT_EQ(count, 0u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(arr_i32, &count), i32);
EXPECT_EQ(count, 5u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(arr_vec3_i32, &count), i32);
+ EXPECT_EQ(count, 15u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(arr_mat4x3_f16, &count), f16);
+ EXPECT_EQ(count, 60u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(arr_mat4x3_af, &count), af);
+ EXPECT_EQ(count, 60u);
+ count = 42;
+ EXPECT_TYPE(Type::DeepestElementOf(arr_str, &count), nullptr);
+ EXPECT_EQ(count, 0u);
}
TEST_F(TypeTest, Common2) {
- auto* ai = create<AbstractInt>();
- auto* af = create<AbstractFloat>();
- auto* f32 = create<F32>();
- auto* f16 = create<F16>();
- auto* i32 = create<I32>();
- auto* u32 = create<U32>();
-
- EXPECT_TYPE(Type::Common({ai, ai}), ai);
- EXPECT_TYPE(Type::Common({af, af}), af);
- EXPECT_TYPE(Type::Common({f32, f32}), f32);
- EXPECT_TYPE(Type::Common({f16, f16}), f16);
- EXPECT_TYPE(Type::Common({i32, i32}), i32);
- EXPECT_TYPE(Type::Common({u32, u32}), u32);
-
- EXPECT_TYPE(Type::Common({i32, u32}), nullptr);
- EXPECT_TYPE(Type::Common({u32, f32}), nullptr);
- EXPECT_TYPE(Type::Common({f32, f16}), nullptr);
- EXPECT_TYPE(Type::Common({f16, i32}), nullptr);
-
- EXPECT_TYPE(Type::Common({ai, af}), af);
- EXPECT_TYPE(Type::Common({ai, f32}), f32);
- EXPECT_TYPE(Type::Common({ai, f16}), f16);
- EXPECT_TYPE(Type::Common({ai, i32}), i32);
- EXPECT_TYPE(Type::Common({ai, u32}), u32);
-
- EXPECT_TYPE(Type::Common({af, ai}), af);
- EXPECT_TYPE(Type::Common({f32, ai}), f32);
- EXPECT_TYPE(Type::Common({f16, ai}), f16);
- EXPECT_TYPE(Type::Common({i32, ai}), i32);
- EXPECT_TYPE(Type::Common({u32, ai}), u32);
-
- EXPECT_TYPE(Type::Common({ai, af}), af);
- EXPECT_TYPE(Type::Common({f32, af}), f32);
- EXPECT_TYPE(Type::Common({f16, af}), f16);
- EXPECT_TYPE(Type::Common({i32, af}), nullptr);
- EXPECT_TYPE(Type::Common({u32, af}), nullptr);
-
- EXPECT_TYPE(Type::Common({af, ai}), af);
- EXPECT_TYPE(Type::Common({af, f32}), f32);
- EXPECT_TYPE(Type::Common({af, f16}), f16);
- EXPECT_TYPE(Type::Common({af, i32}), nullptr);
- EXPECT_TYPE(Type::Common({af, u32}), nullptr);
-
- auto* vec3_ai = create<Vector>(ai, 3u);
- auto* vec3_af = create<Vector>(af, 3u);
- auto* vec3_f32 = create<Vector>(f32, 3u);
- auto* vec3_f16 = create<Vector>(f16, 3u);
- auto* vec4_f32 = create<Vector>(f32, 4u);
- auto* vec3_u32 = create<Vector>(u32, 3u);
- auto* vec3_i32 = create<Vector>(i32, 3u);
-
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_ai}), vec3_ai);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_af}), vec3_af);
- EXPECT_TYPE(Type::Common({vec3_f32, vec3_f32}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_f16, vec3_f16}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec4_f32, vec4_f32}), vec4_f32);
- EXPECT_TYPE(Type::Common({vec3_u32, vec3_u32}), vec3_u32);
- EXPECT_TYPE(Type::Common({vec3_i32, vec3_i32}), vec3_i32);
-
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_f32}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_f16}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec3_ai, vec4_f32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_u32}), vec3_u32);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_i32}), vec3_i32);
-
- EXPECT_TYPE(Type::Common({vec3_f32, vec3_ai}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_f16, vec3_ai}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec4_f32, vec3_ai}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_u32, vec3_ai}), vec3_u32);
- EXPECT_TYPE(Type::Common({vec3_i32, vec3_ai}), vec3_i32);
-
- EXPECT_TYPE(Type::Common({vec3_af, vec3_f32}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_f16}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec3_af, vec4_f32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_u32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_i32}), nullptr);
-
- EXPECT_TYPE(Type::Common({vec3_f32, vec3_af}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_f16, vec3_af}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec4_f32, vec3_af}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_u32, vec3_af}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_i32, vec3_af}), nullptr);
-
- auto* mat4x3_af = create<Matrix>(vec3_af, 4u);
- auto* mat3x4_f32 = create<Matrix>(vec4_f32, 3u);
- auto* mat4x3_f32 = create<Matrix>(vec3_f32, 4u);
- auto* mat4x3_f16 = create<Matrix>(vec3_f16, 4u);
-
- EXPECT_TYPE(Type::Common({mat4x3_af, mat4x3_af}), mat4x3_af);
- EXPECT_TYPE(Type::Common({mat3x4_f32, mat3x4_f32}), mat3x4_f32);
- EXPECT_TYPE(Type::Common({mat4x3_f32, mat4x3_f32}), mat4x3_f32);
- EXPECT_TYPE(Type::Common({mat4x3_f16, mat4x3_f16}), mat4x3_f16);
-
- EXPECT_TYPE(Type::Common({mat4x3_af, mat3x4_f32}), nullptr);
- EXPECT_TYPE(Type::Common({mat4x3_af, mat4x3_f32}), mat4x3_f32);
- EXPECT_TYPE(Type::Common({mat4x3_af, mat4x3_f16}), mat4x3_f16);
-
- EXPECT_TYPE(Type::Common({mat3x4_f32, mat4x3_af}), nullptr);
- EXPECT_TYPE(Type::Common({mat4x3_f32, mat4x3_af}), mat4x3_f32);
- EXPECT_TYPE(Type::Common({mat4x3_f16, mat4x3_af}), mat4x3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, ai}), ai);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, af}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, i32}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, u32}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, u32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, f16}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, i32}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, af}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, i32}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, u32}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{af, ai}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, ai}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, ai}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, ai}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, ai}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, af}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, af}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, af}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, af}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{af, ai}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, i32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, u32}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_ai}), vec3_ai);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_af}), vec3_af);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f32, vec3_f32}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f16, vec3_f16}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec4_f32, vec4_f32}), vec4_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_u32, vec3_u32}), vec3_u32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_i32, vec3_i32}), vec3_i32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_f32}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_f16}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec4_f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_u32}), vec3_u32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_i32}), vec3_i32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f32, vec3_ai}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f16, vec3_ai}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec4_f32, vec3_ai}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_u32, vec3_ai}), vec3_u32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_i32, vec3_ai}), vec3_i32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_f32}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_f16}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec4_f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_u32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_i32}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f32, vec3_af}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f16, vec3_af}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec4_f32, vec3_af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_u32, vec3_af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_i32, vec3_af}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat4x3_af}), mat4x3_af);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat3x4_f32, mat3x4_f32}), mat3x4_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f32, mat4x3_f32}), mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f16, mat4x3_f16}), mat4x3_f16);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat3x4_f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat4x3_f32}), mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat4x3_f16}), mat4x3_f16);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{mat3x4_f32, mat4x3_af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f32, mat4x3_af}), mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f16, mat4x3_af}), mat4x3_f16);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{arr_mat4x3_f32, arr_mat4x3_f16}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{arr_mat4x3_f32, arr_mat4x3_af}), arr_mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{arr_mat4x3_f16, arr_mat4x3_af}), arr_mat4x3_f16);
}
TEST_F(TypeTest, Common3) {
- auto* ai = create<AbstractInt>();
- auto* af = create<AbstractFloat>();
- auto* f32 = create<F32>();
- auto* f16 = create<F16>();
- auto* i32 = create<I32>();
- auto* u32 = create<U32>();
-
- EXPECT_TYPE(Type::Common({ai, ai, ai}), ai);
- EXPECT_TYPE(Type::Common({af, af, af}), af);
- EXPECT_TYPE(Type::Common({f32, f32, f32}), f32);
- EXPECT_TYPE(Type::Common({f16, f16, f16}), f16);
- EXPECT_TYPE(Type::Common({i32, i32, i32}), i32);
- EXPECT_TYPE(Type::Common({u32, u32, u32}), u32);
-
- EXPECT_TYPE(Type::Common({ai, af, ai}), af);
- EXPECT_TYPE(Type::Common({ai, f32, ai}), f32);
- EXPECT_TYPE(Type::Common({ai, f16, ai}), f16);
- EXPECT_TYPE(Type::Common({ai, i32, ai}), i32);
- EXPECT_TYPE(Type::Common({ai, u32, ai}), u32);
-
- EXPECT_TYPE(Type::Common({af, ai, af}), af);
- EXPECT_TYPE(Type::Common({f32, ai, f32}), f32);
- EXPECT_TYPE(Type::Common({f16, ai, f16}), f16);
- EXPECT_TYPE(Type::Common({i32, ai, i32}), i32);
- EXPECT_TYPE(Type::Common({u32, ai, u32}), u32);
-
- EXPECT_TYPE(Type::Common({ai, f32, ai}), f32);
- EXPECT_TYPE(Type::Common({ai, f16, ai}), f16);
- EXPECT_TYPE(Type::Common({ai, i32, ai}), i32);
- EXPECT_TYPE(Type::Common({ai, u32, ai}), u32);
-
- EXPECT_TYPE(Type::Common({f32, ai, f32}), f32);
- EXPECT_TYPE(Type::Common({f16, ai, f16}), f16);
- EXPECT_TYPE(Type::Common({i32, ai, i32}), i32);
- EXPECT_TYPE(Type::Common({u32, ai, u32}), u32);
-
- EXPECT_TYPE(Type::Common({af, f32, af}), f32);
- EXPECT_TYPE(Type::Common({af, f16, af}), f16);
- EXPECT_TYPE(Type::Common({af, i32, af}), nullptr);
- EXPECT_TYPE(Type::Common({af, u32, af}), nullptr);
-
- EXPECT_TYPE(Type::Common({f32, af, f32}), f32);
- EXPECT_TYPE(Type::Common({f16, af, f16}), f16);
- EXPECT_TYPE(Type::Common({i32, af, i32}), nullptr);
- EXPECT_TYPE(Type::Common({u32, af, u32}), nullptr);
-
- EXPECT_TYPE(Type::Common({ai, af, f32}), f32);
- EXPECT_TYPE(Type::Common({ai, af, f16}), f16);
- EXPECT_TYPE(Type::Common({ai, af, i32}), nullptr);
- EXPECT_TYPE(Type::Common({ai, af, u32}), nullptr);
-
- auto* vec3_ai = create<Vector>(ai, 3u);
- auto* vec3_af = create<Vector>(af, 3u);
- auto* vec3_f32 = create<Vector>(f32, 3u);
- auto* vec3_f16 = create<Vector>(f16, 3u);
- auto* vec4_f32 = create<Vector>(f32, 4u);
- auto* vec3_u32 = create<Vector>(u32, 3u);
- auto* vec3_i32 = create<Vector>(i32, 3u);
-
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_ai, vec3_ai}), vec3_ai);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_af, vec3_af}), vec3_af);
- EXPECT_TYPE(Type::Common({vec3_f32, vec3_f32, vec3_f32}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_f16, vec3_f16, vec3_f16}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec4_f32, vec4_f32, vec4_f32}), vec4_f32);
- EXPECT_TYPE(Type::Common({vec3_u32, vec3_u32, vec3_u32}), vec3_u32);
- EXPECT_TYPE(Type::Common({vec3_i32, vec3_i32, vec3_i32}), vec3_i32);
-
- EXPECT_TYPE(Type::Common({vec3_f32, vec3_ai, vec3_f32}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_f16, vec3_ai, vec3_f16}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec4_f32, vec3_ai, vec4_f32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_u32, vec3_ai, vec3_u32}), vec3_u32);
- EXPECT_TYPE(Type::Common({vec3_i32, vec3_ai, vec3_i32}), vec3_i32);
-
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_f32, vec3_ai}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_f16, vec3_ai}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec3_ai, vec4_f32, vec3_ai}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_u32, vec3_ai}), vec3_u32);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_i32, vec3_ai}), vec3_i32);
-
- EXPECT_TYPE(Type::Common({vec3_f32, vec3_af, vec3_f32}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_f16, vec3_af, vec3_f16}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec4_f32, vec3_af, vec4_f32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_u32, vec3_af, vec3_u32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_i32, vec3_af, vec3_i32}), nullptr);
-
- EXPECT_TYPE(Type::Common({vec3_af, vec3_f32, vec3_af}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_f16, vec3_af}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec3_af, vec4_f32, vec3_af}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_u32, vec3_af}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_af, vec3_i32, vec3_af}), nullptr);
-
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_af, vec3_f32}), vec3_f32);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_af, vec3_f16}), vec3_f16);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_af, vec4_f32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_af, vec3_u32}), nullptr);
- EXPECT_TYPE(Type::Common({vec3_ai, vec3_af, vec3_i32}), nullptr);
-
- auto* mat4x3_af = create<Matrix>(vec3_af, 4u);
- auto* mat3x4_f32 = create<Matrix>(vec4_f32, 3u);
- auto* mat4x3_f32 = create<Matrix>(vec3_f32, 4u);
- auto* mat4x3_f16 = create<Matrix>(vec3_f16, 4u);
-
- EXPECT_TYPE(Type::Common({mat4x3_af, mat4x3_af, mat4x3_af}), mat4x3_af);
- EXPECT_TYPE(Type::Common({mat3x4_f32, mat3x4_f32, mat3x4_f32}), mat3x4_f32);
- EXPECT_TYPE(Type::Common({mat4x3_f32, mat4x3_f32, mat4x3_f32}), mat4x3_f32);
- EXPECT_TYPE(Type::Common({mat4x3_f16, mat4x3_f16, mat4x3_f16}), mat4x3_f16);
-
- EXPECT_TYPE(Type::Common({mat3x4_f32, mat4x3_af, mat3x4_f32}), nullptr);
- EXPECT_TYPE(Type::Common({mat4x3_f32, mat4x3_af, mat4x3_f32}), mat4x3_f32);
- EXPECT_TYPE(Type::Common({mat4x3_f16, mat4x3_af, mat4x3_f16}), mat4x3_f16);
-
- EXPECT_TYPE(Type::Common({mat4x3_af, mat3x4_f32, mat4x3_af}), nullptr);
- EXPECT_TYPE(Type::Common({mat4x3_af, mat4x3_f32, mat4x3_af}), mat4x3_f32);
- EXPECT_TYPE(Type::Common({mat4x3_af, mat4x3_f16, mat4x3_af}), mat4x3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, ai, ai}), ai);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, af, af}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, f32, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, f16, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, i32, i32}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, u32, u32}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, af, ai}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, f32, ai}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, f16, ai}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, i32, ai}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, u32, ai}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{af, ai, af}), af);
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, ai, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, ai, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, ai, i32}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, ai, u32}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, f32, ai}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, f16, ai}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, i32, ai}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, u32, ai}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, ai, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, ai, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, ai, i32}), i32);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, ai, u32}), u32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{af, f32, af}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, f16, af}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, i32, af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{af, u32, af}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{f32, af, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{f16, af, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{i32, af, i32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{u32, af, u32}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, af, f32}), f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, af, f16}), f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, af, i32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{ai, af, u32}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_ai, vec3_ai}), vec3_ai);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_af, vec3_af}), vec3_af);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f32, vec3_f32, vec3_f32}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f16, vec3_f16, vec3_f16}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec4_f32, vec4_f32, vec4_f32}), vec4_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_u32, vec3_u32, vec3_u32}), vec3_u32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_i32, vec3_i32, vec3_i32}), vec3_i32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f32, vec3_ai, vec3_f32}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f16, vec3_ai, vec3_f16}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec4_f32, vec3_ai, vec4_f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_u32, vec3_ai, vec3_u32}), vec3_u32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_i32, vec3_ai, vec3_i32}), vec3_i32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_f32, vec3_ai}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_f16, vec3_ai}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec4_f32, vec3_ai}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_u32, vec3_ai}), vec3_u32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_i32, vec3_ai}), vec3_i32);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f32, vec3_af, vec3_f32}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_f16, vec3_af, vec3_f16}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec4_f32, vec3_af, vec4_f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_u32, vec3_af, vec3_u32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_i32, vec3_af, vec3_i32}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_f32, vec3_af}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_f16, vec3_af}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec4_f32, vec3_af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_u32, vec3_af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_af, vec3_i32, vec3_af}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_af, vec3_f32}), vec3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_af, vec3_f16}), vec3_f16);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_af, vec4_f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_af, vec3_u32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{vec3_ai, vec3_af, vec3_i32}), nullptr);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat4x3_af, mat4x3_af}), mat4x3_af);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat3x4_f32, mat3x4_f32, mat3x4_f32}), mat3x4_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f32, mat4x3_f32, mat4x3_f32}), mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f16, mat4x3_f16, mat4x3_f16}), mat4x3_f16);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{mat3x4_f32, mat4x3_af, mat3x4_f32}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f32, mat4x3_af, mat4x3_f32}), mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_f16, mat4x3_af, mat4x3_f16}), mat4x3_f16);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat3x4_f32, mat4x3_af}), nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat4x3_f32, mat4x3_af}), mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{mat4x3_af, mat4x3_f16, mat4x3_af}), mat4x3_f16);
+
+ EXPECT_TYPE(Type::Common(utils::Vector{arr_mat4x3_f16, arr_mat4x3_f32, arr_mat4x3_f16}),
+ nullptr);
+ EXPECT_TYPE(Type::Common(utils::Vector{arr_mat4x3_af, arr_mat4x3_f32, arr_mat4x3_af}),
+ arr_mat4x3_f32);
+ EXPECT_TYPE(Type::Common(utils::Vector{arr_mat4x3_af, arr_mat4x3_f16, arr_mat4x3_af}),
+ arr_mat4x3_f16);
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/sem/variable.cc b/chromium/third_party/dawn/src/tint/sem/variable.cc
index 0ada5aeeed9..28a373b6131 100644
--- a/chromium/third_party/dawn/src/tint/sem/variable.cc
+++ b/chromium/third_party/dawn/src/tint/sem/variable.cc
@@ -17,7 +17,9 @@
#include <utility>
#include "src/tint/ast/identifier_expression.h"
+#include "src/tint/ast/parameter.h"
#include "src/tint/ast/variable.h"
+#include "src/tint/sem/pointer.h"
TINT_INSTANTIATE_TYPEINFO(tint::sem::Variable);
TINT_INSTANTIATE_TYPEINFO(tint::sem::GlobalVariable);
@@ -26,14 +28,15 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Parameter);
TINT_INSTANTIATE_TYPEINFO(tint::sem::VariableUser);
namespace tint::sem {
-
Variable::Variable(const ast::Variable* declaration,
const sem::Type* type,
+ EvaluationStage stage,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value)
+ const Constant* constant_value)
: declaration_(declaration),
type_(type),
+ stage_(stage),
storage_class_(storage_class),
access_(access),
constant_value_(constant_value) {}
@@ -42,33 +45,37 @@ Variable::~Variable() = default;
LocalVariable::LocalVariable(const ast::Variable* declaration,
const sem::Type* type,
+ EvaluationStage stage,
ast::StorageClass storage_class,
ast::Access access,
const sem::Statement* statement,
- Constant constant_value)
- : Base(declaration, type, storage_class, access, std::move(constant_value)),
+ const Constant* constant_value)
+ : Base(declaration, type, stage, storage_class, access, constant_value),
statement_(statement) {}
LocalVariable::~LocalVariable() = default;
GlobalVariable::GlobalVariable(const ast::Variable* declaration,
const sem::Type* type,
+ EvaluationStage stage,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value,
+ const Constant* constant_value,
sem::BindingPoint binding_point)
- : Base(declaration, type, storage_class, access, std::move(constant_value)),
+ : Base(declaration, type, stage, storage_class, access, constant_value),
binding_point_(binding_point) {}
GlobalVariable::~GlobalVariable() = default;
-Parameter::Parameter(const ast::Variable* declaration,
+Parameter::Parameter(const ast::Parameter* declaration,
uint32_t index,
const sem::Type* type,
ast::StorageClass storage_class,
ast::Access access,
const ParameterUsage usage /* = ParameterUsage::kNone */)
- : Base(declaration, type, storage_class, access, Constant{}), index_(index), usage_(usage) {}
+ : Base(declaration, type, EvaluationStage::kRuntime, storage_class, access, nullptr),
+ index_(index),
+ usage_(usage) {}
Parameter::~Parameter() = default;
@@ -77,6 +84,7 @@ VariableUser::VariableUser(const ast::IdentifierExpression* declaration,
sem::Variable* variable)
: Base(declaration,
variable->Type(),
+ variable->Stage(),
statement,
variable->ConstantValue(),
/* has_side_effects */ false),
@@ -89,4 +97,6 @@ VariableUser::VariableUser(const ast::IdentifierExpression* declaration,
}
}
+VariableUser::~VariableUser() = default;
+
} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/variable.h b/chromium/third_party/dawn/src/tint/sem/variable.h
index 7026ca75062..2bf6d23ee6e 100644
--- a/chromium/third_party/dawn/src/tint/sem/variable.h
+++ b/chromium/third_party/dawn/src/tint/sem/variable.h
@@ -18,6 +18,8 @@
#include <utility>
#include <vector>
+#include "tint/override_id.h"
+
#include "src/tint/ast/access.h"
#include "src/tint/ast/storage_class.h"
#include "src/tint/sem/binding_point.h"
@@ -27,6 +29,7 @@
// Forward declarations
namespace tint::ast {
class IdentifierExpression;
+class Parameter;
class Variable;
} // namespace tint::ast
namespace tint::sem {
@@ -44,14 +47,16 @@ class Variable : public Castable<Variable, Node> {
/// Constructor
/// @param declaration the AST declaration node
/// @param type the variable type
+ /// @param stage the evaluation stage for an expression of this variable type
/// @param storage_class the variable storage class
/// @param access the variable access control type
- /// @param constant_value the constant value for the variable. May be invalid
+ /// @param constant_value the constant value for the variable. May be null
Variable(const ast::Variable* declaration,
const sem::Type* type,
+ EvaluationStage stage,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value);
+ const Constant* constant_value);
/// Destructor
~Variable() override;
@@ -62,6 +67,9 @@ class Variable : public Castable<Variable, Node> {
/// @returns the canonical type for the variable
const sem::Type* Type() const { return type_; }
+ /// @returns the evaluation stage for an expression of this variable type
+ EvaluationStage Stage() const { return stage_; }
+
/// @returns the storage class for the variable
ast::StorageClass StorageClass() const { return storage_class_; }
@@ -69,7 +77,7 @@ class Variable : public Castable<Variable, Node> {
ast::Access Access() const { return access_; }
/// @return the constant value of this expression
- const Constant& ConstantValue() const { return constant_value_; }
+ const Constant* ConstantValue() const { return constant_value_; }
/// @returns the variable constructor expression, or nullptr if the variable
/// does not have one.
@@ -88,9 +96,10 @@ class Variable : public Castable<Variable, Node> {
private:
const ast::Variable* const declaration_;
const sem::Type* const type_;
+ const EvaluationStage stage_;
const ast::StorageClass storage_class_;
const ast::Access access_;
- const Constant constant_value_;
+ const Constant* constant_value_;
const Expression* constructor_ = nullptr;
std::vector<const VariableUser*> users_;
};
@@ -101,16 +110,18 @@ class LocalVariable final : public Castable<LocalVariable, Variable> {
/// Constructor
/// @param declaration the AST declaration node
/// @param type the variable type
+ /// @param stage the evaluation stage for an expression of this variable type
/// @param storage_class the variable storage class
/// @param access the variable access control type
/// @param statement the statement that declared this local variable
- /// @param constant_value the constant value for the variable. May be invalid
+ /// @param constant_value the constant value for the variable. May be null
LocalVariable(const ast::Variable* declaration,
const sem::Type* type,
+ EvaluationStage stage,
ast::StorageClass storage_class,
ast::Access access,
const sem::Statement* statement,
- Constant constant_value);
+ const Constant* constant_value);
/// Destructor
~LocalVariable() override;
@@ -136,15 +147,17 @@ class GlobalVariable final : public Castable<GlobalVariable, Variable> {
/// Constructor
/// @param declaration the AST declaration node
/// @param type the variable type
+ /// @param stage the evaluation stage for an expression of this variable type
/// @param storage_class the variable storage class
/// @param access the variable access control type
- /// @param constant_value the constant value for the variable. May be invalid
+ /// @param constant_value the constant value for the variable. May be null
/// @param binding_point the optional resource binding point of the variable
GlobalVariable(const ast::Variable* declaration,
const sem::Type* type,
+ EvaluationStage stage,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value,
+ const Constant* constant_value,
sem::BindingPoint binding_point = {});
/// Destructor
@@ -154,25 +167,15 @@ class GlobalVariable final : public Castable<GlobalVariable, Variable> {
sem::BindingPoint BindingPoint() const { return binding_point_; }
/// @param id the constant identifier to assign to this variable
- void SetConstantId(uint16_t id) {
- constant_id_ = id;
- is_overridable_ = true;
- }
+ void SetOverrideId(OverrideId id) { override_id_ = id; }
/// @returns the pipeline constant ID associated with the variable
- uint16_t ConstantId() const { return constant_id_; }
-
- /// @param is_overridable true if this is a pipeline overridable constant
- void SetIsOverridable(bool is_overridable = true) { is_overridable_ = is_overridable; }
-
- /// @returns true if this is pipeline overridable constant
- bool IsOverridable() const { return is_overridable_; }
+ tint::OverrideId OverrideId() const { return override_id_; }
private:
const sem::BindingPoint binding_point_;
- bool is_overridable_ = false;
- uint16_t constant_id_ = 0;
+ tint::OverrideId override_id_;
};
/// Parameter is a function parameter
@@ -185,7 +188,7 @@ class Parameter final : public Castable<Parameter, Variable> {
/// @param storage_class the variable storage class
/// @param access the variable access control type
/// @param usage the semantic usage for the parameter
- Parameter(const ast::Variable* declaration,
+ Parameter(const ast::Parameter* declaration,
uint32_t index,
const sem::Type* type,
ast::StorageClass storage_class,
@@ -221,9 +224,6 @@ class Parameter final : public Castable<Parameter, Variable> {
const sem::Node* shadows_ = nullptr;
};
-/// ParameterList is a list of Parameter
-using ParameterList = std::vector<const Parameter*>;
-
/// VariableUser holds the semantic information for an identifier expression
/// node that resolves to a variable.
class VariableUser final : public Castable<VariableUser, Expression> {
@@ -235,6 +235,7 @@ class VariableUser final : public Castable<VariableUser, Expression> {
VariableUser(const ast::IdentifierExpression* declaration,
Statement* statement,
sem::Variable* variable);
+ ~VariableUser() override;
/// @returns the variable that this expression refers to
const sem::Variable* Variable() const { return variable_; }
diff --git a/chromium/third_party/dawn/src/tint/sem/while_statement.cc b/chromium/third_party/dawn/src/tint/sem/while_statement.cc
new file mode 100644
index 00000000000..495f83fefa1
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/sem/while_statement.cc
@@ -0,0 +1,34 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/while_statement.h"
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::WhileStatement);
+
+namespace tint::sem {
+
+WhileStatement::WhileStatement(const ast::WhileStatement* declaration,
+ const CompoundStatement* parent,
+ const sem::Function* function)
+ : Base(declaration, parent, function) {}
+
+WhileStatement::~WhileStatement() = default;
+
+const ast::WhileStatement* WhileStatement::Declaration() const {
+ return static_cast<const ast::WhileStatement*>(Base::Declaration());
+}
+
+} // namespace tint::sem
diff --git a/chromium/third_party/dawn/src/tint/sem/while_statement.h b/chromium/third_party/dawn/src/tint/sem/while_statement.h
new file mode 100644
index 00000000000..50f1831f1c1
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/sem/while_statement.h
@@ -0,0 +1,60 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0(the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_SEM_WHILE_STATEMENT_H_
+#define SRC_TINT_SEM_WHILE_STATEMENT_H_
+
+#include "src/tint/sem/statement.h"
+
+// Forward declarations
+namespace tint::ast {
+class WhileStatement;
+} // namespace tint::ast
+namespace tint::sem {
+class Expression;
+} // namespace tint::sem
+
+namespace tint::sem {
+
+/// Holds semantic information about a while statement
+class WhileStatement final : public Castable<WhileStatement, CompoundStatement> {
+ public:
+ /// Constructor
+ /// @param declaration the AST node for this while statement
+ /// @param parent the owning statement
+ /// @param function the owning function
+ WhileStatement(const ast::WhileStatement* declaration,
+ const CompoundStatement* parent,
+ const sem::Function* function);
+
+ /// Destructor
+ ~WhileStatement() override;
+
+ /// @returns the AST node
+ const ast::WhileStatement* Declaration() const;
+
+ /// @returns the whilecondition expression
+ const Expression* Condition() const { return condition_; }
+
+ /// Sets the while condition expression
+ /// @param condition the while condition expression
+ void SetCondition(const Expression* condition) { condition_ = condition; }
+
+ private:
+ const Expression* condition_ = nullptr;
+};
+
+} // namespace tint::sem
+
+#endif // SRC_TINT_SEM_WHILE_STATEMENT_H_
diff --git a/chromium/third_party/dawn/src/tint/symbol.cc b/chromium/third_party/dawn/src/tint/symbol.cc
index 09656975eed..9adc1aaa37b 100644
--- a/chromium/third_party/dawn/src/tint/symbol.cc
+++ b/chromium/third_party/dawn/src/tint/symbol.cc
@@ -23,8 +23,8 @@ Symbol::Symbol() = default;
Symbol::Symbol(uint32_t val, tint::ProgramID program_id) : val_(val), program_id_(program_id) {}
#if TINT_SYMBOL_STORE_DEBUG_NAME
-Symbol::Symbol(uint32_t val, tint::ProgramID program_id, std::string debug_name)
- : val_(val), program_id_(program_id), debug_name_(std::move(debug_name)) {}
+Symbol::Symbol(uint32_t val, tint::ProgramID pid, std::string debug_name)
+ : val_(val), program_id_(pid), debug_name_(std::move(debug_name)) {}
#endif
Symbol::Symbol(const Symbol& o) = default;
diff --git a/chromium/third_party/dawn/src/tint/symbol.h b/chromium/third_party/dawn/src/tint/symbol.h
index 1cbc6b2245b..fc0a0df56c6 100644
--- a/chromium/third_party/dawn/src/tint/symbol.h
+++ b/chromium/third_party/dawn/src/tint/symbol.h
@@ -41,9 +41,9 @@ class Symbol {
#if TINT_SYMBOL_STORE_DEBUG_NAME
/// Constructor
/// @param val the symbol value
- /// @param program_id the identifier of the program that owns this Symbol
+ /// @param pid the identifier of the program that owns this Symbol
/// @param debug_name name of symbols used only for debugging
- Symbol(uint32_t val, tint::ProgramID program_id, std::string debug_name);
+ Symbol(uint32_t val, tint::ProgramID pid, std::string debug_name);
#endif
/// Copy constructor
/// @param o the symbol to copy
diff --git a/chromium/third_party/dawn/src/tint/templates/enums.tmpl.inc b/chromium/third_party/dawn/src/tint/templates/enums.tmpl.inc
new file mode 100644
index 00000000000..d05d76331d8
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/templates/enums.tmpl.inc
@@ -0,0 +1,160 @@
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- define "EnumCase" -}}
+{{- /* Prints the 'Enum::kEntry' name for the provided sem.EnumEntry */ -}}
+{{- /* argument. */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{PascalCase $.Enum.Name}}::k{{PascalCase $.Name}}
+{{- end -}}
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- define "DeclareEnum" -}}
+{{- /* Declares the 'enum class' for the provided sem.Enum argument. */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum := PascalCase $.Name -}}
+enum class {{$enum}} {
+ kInvalid,
+{{- range $entry := $.Entries }}
+ k{{PascalCase $entry.Name}},{{if $entry.IsInternal}} // Tint-internal enum entry - not parsed{{end}}
+{{- end }}
+};
+
+/// @param out the std::ostream to write to
+/// @param value the {{$enum}}
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, {{$enum}} value);
+
+/// Parse{{$enum}} parses a {{$enum}} from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or {{$enum}}::kInvalid if the string could not be parsed.
+{{$enum}} Parse{{$enum}}(std::string_view str);
+
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- define "ParseEnum" -}}
+{{- /* Implements the 'ParseEnum' function for the provided sem.Enum */ -}}
+{{- /* argument. */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum := PascalCase $.Name -}}
+/// Parse{{$enum}} parses a {{$enum}} from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or {{$enum}}::kInvalid if the string could not be parsed.
+{{$enum}} Parse{{$enum}}(std::string_view str) {
+{{- range $entry := $.PublicEntries }}
+ if (str == "{{$entry.Name}}") {
+ return {{template "EnumCase" $entry}};
+ }
+{{- end }}
+ return {{$enum}}::kInvalid;
+}
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- define "EnumOStream" -}}
+{{- /* Implements the std::ostream 'operator<<()' function to print the */ -}}
+{{- /* provided sem.Enum. */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum := PascalCase $.Name -}}
+std::ostream& operator<<(std::ostream& out, {{$enum}} value) {
+ switch (value) {
+ case {{$enum}}::kInvalid:
+ return out << "invalid";
+{{- range $entry := $.Entries }}
+ case {{template "EnumCase" $entry}}:
+ return out << "{{$entry.Name}}";
+{{- end }}
+ }
+ return out << "<unknown>";
+}
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- define "TestParsePrintEnum" -}}
+{{- /* Implements unit tests for parsing and printing the provided */ -}}
+{{- /* sem.Enum argument. */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum := PascalCase $.Name -}}
+namespace parse_print_tests {
+
+struct Case {
+ const char* string;
+ {{$enum}} value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+ return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+{{- range $entry := $.PublicEntries }}
+ {"{{$entry.Name}}", {{template "EnumCase" $entry}}},
+{{- end }}
+};
+
+static constexpr Case kInvalidCases[] = {
+{{- $exclude := $.NameSet -}}
+{{- range $entry := $.PublicEntries }}
+ {"{{Scramble $entry.Name $exclude}}", {{$enum}}::kInvalid},
+ {"{{Scramble $entry.Name $exclude}}", {{$enum}}::kInvalid},
+ {"{{Scramble $entry.Name $exclude}}", {{$enum}}::kInvalid},
+{{- end }}
+};
+
+using {{$enum}}ParseTest = testing::TestWithParam<Case>;
+
+TEST_P({{$enum}}ParseTest, Parse) {
+ const char* string = GetParam().string;
+ {{$enum}} expect = GetParam().value;
+ EXPECT_EQ(expect, Parse{{$enum}}(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, {{$enum}}ParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, {{$enum}}ParseTest, testing::ValuesIn(kInvalidCases));
+
+using {{$enum}}PrintTest = testing::TestWithParam<Case>;
+
+TEST_P({{$enum}}PrintTest, Print) {
+ {{$enum}} value = GetParam().value;
+ const char* expect = GetParam().string;
+ EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, {{$enum}}PrintTest, testing::ValuesIn(kValidCases));
+
+} // namespace parse_print_tests
+
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- define "BenchmarkParseEnum" -}}
+{{- /* Implements a micro-benchmark for parsing the provided sem.Enum */ -}}
+{{- /* argument. */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum := PascalCase $.Name -}}
+void {{$enum}}Parser(::benchmark::State& state) {
+ std::array kStrings{
+{{- $exclude := $.NameSet -}}
+{{- range $entry := $.PublicEntries }}
+ "{{Scramble $entry.Name $exclude}}",
+ "{{Scramble $entry.Name $exclude}}",
+ "{{Scramble $entry.Name $exclude}}",
+ "{{$entry.Name}}",
+ "{{Scramble $entry.Name $exclude}}",
+ "{{Scramble $entry.Name $exclude}}",
+ "{{Scramble $entry.Name $exclude}}",
+{{- end }}
+ };
+ for (auto _ : state) {
+ for (auto& str : kStrings) {
+ auto result = Parse{{$enum}}(str);
+ benchmark::DoNotOptimize(result);
+ }
+ }
+}
+
+BENCHMARK({{$enum}}Parser);
+{{- end -}}
diff --git a/chromium/third_party/dawn/src/tint/text/unicode.cc b/chromium/third_party/dawn/src/tint/text/unicode.cc
index bf28c4e5bcc..e23f3dd6b0e 100644
--- a/chromium/third_party/dawn/src/tint/text/unicode.cc
+++ b/chromium/third_party/dawn/src/tint/text/unicode.cc
@@ -306,10 +306,26 @@ constexpr size_t kNumXIDContinueRanges = sizeof(kXIDContinueRanges) / sizeof(kXI
} // namespace
bool CodePoint::IsXIDStart() const {
+ // Short circuit ASCII. The binary search will find these last, but most
+ // of our current source is ASCII, so handle them quicker.
+ if ((value >= 'a' && value <= 'z') || (value >= 'A' && value <= 'Z')) {
+ return true;
+ }
+ // With [a-zA-Z] handled, nothing less then the next sequence start can be
+ // XIDStart, so filter them all out. This catches most of the common symbols
+ // that are used in ASCII.
+ if (value < 0x000aa) {
+ return false;
+ }
return std::binary_search(kXIDStartRanges, kXIDStartRanges + kNumXIDStartRanges, *this);
}
bool CodePoint::IsXIDContinue() const {
+ // Short circuit ASCII. The binary search will find these last, but most
+ // of our current source is ASCII, so handle them quicker.
+ if ((value >= '0' && value <= '9') || value == '_') {
+ return true;
+ }
return IsXIDStart() || std::binary_search(kXIDContinueRanges,
kXIDContinueRanges + kNumXIDContinueRanges, *this);
}
diff --git a/chromium/third_party/dawn/src/tint/tint.natvis b/chromium/third_party/dawn/src/tint/tint.natvis
index c1fd1f398e4..45ecf932c28 100644
--- a/chromium/third_party/dawn/src/tint/tint.natvis
+++ b/chromium/third_party/dawn/src/tint/tint.natvis
@@ -16,6 +16,34 @@
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+ <Type Name="tint::utils::Slice&lt;*&gt;">
+ <DisplayString>{{ length={len}, capacity={cap} }}</DisplayString>
+ <Expand>
+ <!--<Item Name="[length]">len</Item>
+ <Item Name="[capacity]">cap</Item>-->
+ <ArrayItems>
+ <Size>len</Size>
+ <ValuePointer>data</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="tint::utils::Vector&lt;*,*&gt;">
+ <Expand>
+ <Item Name="[heap]">impl_.slice.cap > (int)$T2</Item>
+ <ExpandedItem>impl_.slice</ExpandedItem>
+ <!--<Item Name="[slice]">impl_.slice</Item>-->
+ </Expand>
+ </Type>
+
+ <Type Name="tint::utils::VectorRef&lt;*&gt;">
+ <Expand>
+ <Item Name="[can move]">can_move_</Item>
+ <ExpandedItem>slice_</ExpandedItem>
+ <!--<Item Name="[slice]">slice_</Item>-->
+ </Expand>
+ </Type>
+
<Type Name="tint::Symbol">
<!-- Requires TINT_SYMBOL_STORE_DEBUG_NAME defined to 1 -->
<DisplayString Optional="true">{debug_name_,sb}</DisplayString>
@@ -63,7 +91,7 @@
</Type>
<Type Name="tint::ast::IdentifierExpression">
- <!--the ",sb" specifier removes the double quotes on the displayed string -->
+ <!--the ",sb" specifier removes the double quotes on the displayed string -->
<DisplayString>{symbol}</DisplayString>
<Expand>
<Item Name="symbol">symbol</Item>
@@ -101,11 +129,7 @@
<DisplayString>{*variable};</DisplayString>
</Type>
- <Type Name="tint::ast::UintLiteralExpression">
- <DisplayString>{value}</DisplayString>
- </Type>
-
- <Type Name="tint::ast::SintLiteralExpression">
+ <Type Name="tint::ast::IntLiteralExpression">
<DisplayString>{value}</DisplayString>
</Type>
diff --git a/chromium/third_party/dawn/src/tint/traits.h b/chromium/third_party/dawn/src/tint/traits.h
index eb81b3f0dbd..d830d2c4372 100644
--- a/chromium/third_party/dawn/src/tint/traits.h
+++ b/chromium/third_party/dawn/src/tint/traits.h
@@ -91,7 +91,7 @@ static constexpr bool IsTypeOrDerived =
/// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
/// invalid type.
-template <bool CONDITION, typename T>
+template <bool CONDITION, typename T = void>
using EnableIf = typename std::enable_if<CONDITION, T>::type;
/// If `T` is of type `BASE`, or derives from `BASE`, then EnableIfIsType
diff --git a/chromium/third_party/dawn/src/tint/transform/add_empty_entry_point.cc b/chromium/third_party/dawn/src/tint/transform/add_empty_entry_point.cc
index f037649e4ad..5ef4fe85eb2 100644
--- a/chromium/third_party/dawn/src/tint/transform/add_empty_entry_point.cc
+++ b/chromium/third_party/dawn/src/tint/transform/add_empty_entry_point.cc
@@ -39,7 +39,10 @@ bool AddEmptyEntryPoint::ShouldRun(const Program* program, const DataMap&) const
void AddEmptyEntryPoint::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
ctx.dst->Func(ctx.dst->Symbols().New("unused_entry_point"), {}, ctx.dst->ty.void_(), {},
- {ctx.dst->Stage(ast::PipelineStage::kCompute), ctx.dst->WorkgroupSize(1_i)});
+ utils::Vector{
+ ctx.dst->Stage(ast::PipelineStage::kCompute),
+ ctx.dst->WorkgroupSize(1_i),
+ });
ctx.Clone();
}
diff --git a/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.cc b/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.cc
index 38e0de66d5d..3615812305a 100644
--- a/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.cc
+++ b/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.cc
@@ -54,11 +54,12 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
// contains it in the destination program.
std::unordered_map<const sem::Type*, const ast::Struct*> wrapper_structs;
- // Process global variables that are buffers.
- for (auto* var : ctx.src->AST().GlobalVariables()) {
+ // Process global 'var' declarations that are buffers.
+ for (auto* var : ctx.src->AST().Globals<ast::Var>()) {
auto* sem_var = sem.Get<sem::GlobalVariable>(var);
if (var->declared_storage_class != ast::StorageClass::kStorage &&
- var->declared_storage_class != ast::StorageClass::kUniform) {
+ var->declared_storage_class != ast::StorageClass::kUniform &&
+ var->declared_storage_class != ast::StorageClass::kPushConstant) {
continue;
}
@@ -70,12 +71,13 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
// This is a non-struct or a struct that is nested somewhere else, so we
// need to wrap it first.
auto* wrapper = utils::GetOrCreate(wrapper_structs, ty, [&]() {
- auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
+ auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(
+ ctx.dst->ID(), ctx.dst->AllocateNodeID());
auto wrapper_name = ctx.src->Symbols().NameFor(var->symbol) + "_block";
auto* ret = ctx.dst->create<ast::Struct>(
ctx.dst->Symbols().New(wrapper_name),
- ast::StructMemberList{ctx.dst->Member(kMemberName, CreateASTTypeFor(ctx, ty))},
- ast::AttributeList{block});
+ utils::Vector{ctx.dst->Member(kMemberName, CreateASTTypeFor(ctx, ty))},
+ utils::Vector{block});
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), var, ret);
return ret;
});
@@ -89,7 +91,8 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
}
} else {
// Add a block attribute to this struct directly.
- auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
+ auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(
+ ctx.dst->ID(), ctx.dst->AllocateNodeID());
ctx.InsertFront(str->Declaration()->attributes, block);
}
}
@@ -97,7 +100,8 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
ctx.Clone();
}
-AddSpirvBlockAttribute::SpirvBlockAttribute::SpirvBlockAttribute(ProgramID pid) : Base(pid) {}
+AddSpirvBlockAttribute::SpirvBlockAttribute::SpirvBlockAttribute(ProgramID pid, ast::NodeID nid)
+ : Base(pid, nid) {}
AddSpirvBlockAttribute::SpirvBlockAttribute::~SpirvBlockAttribute() = default;
std::string AddSpirvBlockAttribute::SpirvBlockAttribute::InternalName() const {
return "spirv_block";
@@ -105,7 +109,8 @@ std::string AddSpirvBlockAttribute::SpirvBlockAttribute::InternalName() const {
const AddSpirvBlockAttribute::SpirvBlockAttribute*
AddSpirvBlockAttribute::SpirvBlockAttribute::Clone(CloneContext* ctx) const {
- return ctx->dst->ASTNodes().Create<AddSpirvBlockAttribute::SpirvBlockAttribute>(ctx->dst->ID());
+ return ctx->dst->ASTNodes().Create<AddSpirvBlockAttribute::SpirvBlockAttribute>(
+ ctx->dst->ID(), ctx->dst->AllocateNodeID());
}
} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.h b/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.h
index 67faaa5ec1e..51409c8a239 100644
--- a/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.h
+++ b/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute.h
@@ -35,7 +35,8 @@ class AddSpirvBlockAttribute final : public Castable<AddSpirvBlockAttribute, Tra
public:
/// Constructor
/// @param program_id the identifier of the program that owns this node
- explicit SpirvBlockAttribute(ProgramID program_id);
+ /// @param nid the unique node identifier
+ SpirvBlockAttribute(ProgramID program_id, ast::NodeID nid);
/// Destructor
~SpirvBlockAttribute() override;
diff --git a/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute_test.cc b/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute_test.cc
index 455be60df30..90f9219d33e 100644
--- a/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/add_spirv_block_attribute_test.cc
@@ -196,6 +196,71 @@ fn main() {
EXPECT_EQ(expect, str(got));
}
+TEST_F(AddSpirvBlockAttributeTest, BasicScalar_PushConstant) {
+ auto* src = R"(
+enable chromium_experimental_push_constant;
+var<push_constant> u : f32;
+
+@fragment
+fn main() {
+ let f = u;
+}
+)";
+ auto* expect = R"(
+enable chromium_experimental_push_constant;
+
+@internal(spirv_block)
+struct u_block {
+ inner : f32,
+}
+
+var<push_constant> u : u_block;
+
+@fragment
+fn main() {
+ let f = u.inner;
+}
+)";
+
+ auto got = Run<AddSpirvBlockAttribute>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(AddSpirvBlockAttributeTest, BasicStruct_PushConstant) {
+ auto* src = R"(
+enable chromium_experimental_push_constant;
+struct S {
+ f : f32,
+};
+var<push_constant> u : S;
+
+@fragment
+fn main() {
+ let f = u.f;
+}
+)";
+ auto* expect = R"(
+enable chromium_experimental_push_constant;
+
+@internal(spirv_block)
+struct S {
+ f : f32,
+}
+
+var<push_constant> u : S;
+
+@fragment
+fn main() {
+ let f = u.f;
+}
+)";
+
+ auto got = Run<AddSpirvBlockAttribute>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(AddSpirvBlockAttributeTest, Nested_OuterBuffer_InnerNotBuffer) {
auto* src = R"(
struct Inner {
diff --git a/chromium/third_party/dawn/src/tint/transform/array_length_from_uniform.cc b/chromium/third_party/dawn/src/tint/transform/array_length_from_uniform.cc
index 86c45345d8b..cdb75c890a4 100644
--- a/chromium/third_party/dawn/src/tint/transform/array_length_from_uniform.cc
+++ b/chromium/third_party/dawn/src/tint/transform/array_length_from_uniform.cc
@@ -141,13 +141,14 @@ void ArrayLengthFromUniform::Run(CloneContext& ctx, const DataMap& inputs, DataM
// aligned.
auto* buffer_size_struct = ctx.dst->Structure(
ctx.dst->Sym(),
- {ctx.dst->Member(kBufferSizeMemberName,
- ctx.dst->ty.array(ctx.dst->ty.vec4(ctx.dst->ty.u32()),
- u32((max_buffer_size_index / 4) + 1)))});
- buffer_size_ubo = ctx.dst->Global(
+ utils::Vector{
+ ctx.dst->Member(kBufferSizeMemberName,
+ ctx.dst->ty.array(ctx.dst->ty.vec4(ctx.dst->ty.u32()),
+ u32((max_buffer_size_index / 4) + 1))),
+ });
+ buffer_size_ubo = ctx.dst->GlobalVar(
ctx.dst->Sym(), ctx.dst->ty.Of(buffer_size_struct), ast::StorageClass::kUniform,
- ast::AttributeList{
- ctx.dst->GroupAndBinding(cfg->ubo_binding.group, cfg->ubo_binding.binding)});
+ ctx.dst->GroupAndBinding(cfg->ubo_binding.group, cfg->ubo_binding.binding));
}
return buffer_size_ubo;
};
diff --git a/chromium/third_party/dawn/src/tint/transform/binding_remapper.cc b/chromium/third_party/dawn/src/tint/transform/binding_remapper.cc
index e3b7afdf896..28071453c7a 100644
--- a/chromium/third_party/dawn/src/tint/transform/binding_remapper.cc
+++ b/chromium/third_party/dawn/src/tint/transform/binding_remapper.cc
@@ -22,6 +22,7 @@
#include "src/tint/program_builder.h"
#include "src/tint/sem/function.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/utils/string.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::BindingRemapper);
TINT_INSTANTIATE_TYPEINFO(tint::transform::BindingRemapper::Remappings);
@@ -67,8 +68,8 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
}
auto* func = ctx.src->Sem().Get(func_ast);
std::unordered_map<sem::BindingPoint, int> binding_point_counts;
- for (auto* var : func->TransitivelyReferencedGlobals()) {
- if (auto binding_point = var->Declaration()->BindingPoint()) {
+ for (auto* global : func->TransitivelyReferencedGlobals()) {
+ if (auto binding_point = global->Declaration()->BindingPoint()) {
BindingPoint from{binding_point.group->value, binding_point.binding->value};
auto bp_it = remappings->binding_points.find(from);
if (bp_it != remappings->binding_points.end()) {
@@ -88,7 +89,7 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
}
}
- for (auto* var : ctx.src->AST().GlobalVariables()) {
+ for (auto* var : ctx.src->AST().Globals<ast::Var>()) {
if (auto binding_point = var->BindingPoint()) {
// The original binding point
BindingPoint from{binding_point.group->value, binding_point.binding->value};
@@ -125,15 +126,15 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
ctx.dst->Diagnostics().add_error(
diag::System::Transform,
"cannot apply access control to variable with storage class " +
- std::string(ast::ToString(sem->StorageClass())));
+ std::string(utils::ToString(sem->StorageClass())));
return;
}
auto* ty = sem->Type()->UnwrapRef();
const ast::Type* inner_ty = CreateASTTypeFor(ctx, ty);
- auto* new_var = ctx.dst->create<ast::Variable>(
- ctx.Clone(var->source), ctx.Clone(var->symbol), var->declared_storage_class, ac,
- inner_ty, false, false, ctx.Clone(var->constructor),
- ctx.Clone(var->attributes));
+ auto* new_var =
+ ctx.dst->Var(ctx.Clone(var->source), ctx.Clone(var->symbol), inner_ty,
+ var->declared_storage_class, ac, ctx.Clone(var->constructor),
+ ctx.Clone(var->attributes));
ctx.Replace(var, new_var);
}
diff --git a/chromium/third_party/dawn/src/tint/transform/binding_remapper_test.cc b/chromium/third_party/dawn/src/tint/transform/binding_remapper_test.cc
index 32748866081..564a3a5b245 100644
--- a/chromium/third_party/dawn/src/tint/transform/binding_remapper_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/binding_remapper_test.cc
@@ -137,9 +137,9 @@ struct S {
a : f32,
};
-@group(2) @binding(1) var<storage, read> a : S;
+@group(2) @binding(1) var<storage, read_write> a : S;
-@group(3) @binding(2) var<storage, write> b : S;
+@group(3) @binding(2) var<storage, read_write> b : S;
@group(4) @binding(3) var<storage, read> c : S;
@@ -153,9 +153,9 @@ struct S {
a : f32,
}
-@group(2) @binding(1) var<storage, write> a : S;
+@group(2) @binding(1) var<storage, read_write> a : S;
-@group(3) @binding(2) var<storage, write> b : S;
+@group(3) @binding(2) var<storage, read_write> b : S;
@group(4) @binding(3) var<storage, read> c : S;
@@ -168,7 +168,7 @@ fn f() {
data.Add<BindingRemapper::Remappings>(
BindingRemapper::BindingPoints{},
BindingRemapper::AccessControls{
- {{2, 1}, ast::Access::kWrite}, // Modify access control
+ {{2, 1}, ast::Access::kReadWrite}, // Modify access control
// Keep @group(3) @binding(2) as is
{{4, 3}, ast::Access::kRead}, // Add access control
});
@@ -197,9 +197,9 @@ struct S {
a : f32,
}
-@group(4) @binding(5) var<storage, write> a : S;
+@group(4) @binding(5) var<storage, read_write> a : S;
-@group(6) @binding(7) var<storage, write> b : S;
+@group(6) @binding(7) var<storage, read_write> b : S;
@compute @workgroup_size(1)
fn f() {
@@ -213,8 +213,8 @@ fn f() {
{{3, 2}, {6, 7}},
},
BindingRemapper::AccessControls{
- {{2, 1}, ast::Access::kWrite},
- {{3, 2}, ast::Access::kWrite},
+ {{2, 1}, ast::Access::kReadWrite},
+ {{3, 2}, ast::Access::kReadWrite},
});
auto got = Run<BindingRemapper>(src, data);
diff --git a/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.cc b/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.cc
index 9bde1cc7792..3ca70355148 100644
--- a/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.cc
+++ b/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.cc
@@ -15,6 +15,7 @@
#include "src/tint/transform/builtin_polyfill.h"
#include <unordered_map>
+#include <utility>
#include "src/tint/program_builder.h"
#include "src/tint/sem/builtin.h"
@@ -44,6 +45,98 @@ struct BuiltinPolyfill::State {
/// The source clone context
const sem::Info& sem = ctx.src->Sem();
+ /// Builds the polyfill function for the `acosh` builtin
+ /// @param ty the parameter and return type for the function
+ /// @return the polyfill function name
+ Symbol acosh(const sem::Type* ty) {
+ auto name = b.Symbols().New("tint_acosh");
+ uint32_t width = WidthOf(ty);
+
+ auto V = [&](AFloat value) -> const ast::Expression* {
+ const ast::Expression* expr = b.Expr(value);
+ if (width == 1) {
+ return expr;
+ }
+ return b.Construct(T(ty), expr);
+ };
+
+ utils::Vector<const ast::Statement*, 4> body;
+ switch (polyfill.acosh) {
+ case Level::kFull:
+ // return log(x + sqrt(x*x - 1));
+ body.Push(b.Return(
+ b.Call("log", b.Add("x", b.Call("sqrt", b.Sub(b.Mul("x", "x"), 1_a))))));
+ break;
+ case Level::kRangeCheck: {
+ // return select(acosh(x), 0, x < 1);
+ body.Push(b.Return(
+ b.Call("select", b.Call("acosh", "x"), V(0.0_a), b.LessThan("x", V(1.0_a)))));
+ break;
+ }
+ default:
+ TINT_ICE(Transform, b.Diagnostics())
+ << "unhandled polyfill level: " << static_cast<int>(polyfill.acosh);
+ return {};
+ }
+
+ b.Func(name, utils::Vector{b.Param("x", T(ty))}, T(ty), body);
+
+ return name;
+ }
+
+ /// Builds the polyfill function for the `asinh` builtin
+ /// @param ty the parameter and return type for the function
+ /// @return the polyfill function name
+ Symbol asinh(const sem::Type* ty) {
+ auto name = b.Symbols().New("tint_sinh");
+
+ // return log(x + sqrt(x*x + 1));
+ b.Func(name, utils::Vector{b.Param("x", T(ty))}, T(ty),
+ utils::Vector{
+ b.Return(b.Call("log", b.Add("x", b.Call("sqrt", b.Add(b.Mul("x", "x"), 1_a))))),
+ });
+
+ return name;
+ }
+
+ /// Builds the polyfill function for the `atanh` builtin
+ /// @param ty the parameter and return type for the function
+ /// @return the polyfill function name
+ Symbol atanh(const sem::Type* ty) {
+ auto name = b.Symbols().New("tint_atanh");
+ uint32_t width = WidthOf(ty);
+
+ auto V = [&](AFloat value) -> const ast::Expression* {
+ const ast::Expression* expr = b.Expr(value);
+ if (width == 1) {
+ return expr;
+ }
+ return b.Construct(T(ty), expr);
+ };
+
+ utils::Vector<const ast::Statement*, 1> body;
+ switch (polyfill.atanh) {
+ case Level::kFull:
+ // return log((1+x) / (1-x)) * 0.5
+ body.Push(
+ b.Return(b.Mul(b.Call("log", b.Div(b.Add(1_a, "x"), b.Sub(1_a, "x"))), 0.5_a)));
+ break;
+ case Level::kRangeCheck:
+ // return select(atanh(x), 0, x >= 1);
+ body.Push(b.Return(b.Call("select", b.Call("atanh", "x"), V(0.0_a),
+ b.GreaterThanEqual("x", V(1.0_a)))));
+ break;
+ default:
+ TINT_ICE(Transform, b.Diagnostics())
+ << "unhandled polyfill level: " << static_cast<int>(polyfill.acosh);
+ return {};
+ }
+
+ b.Func(name, utils::Vector{b.Param("x", T(ty))}, T(ty), body);
+
+ return name;
+ }
+
/// Builds the polyfill function for the `countLeadingZeros` builtin
/// @param ty the parameter and return type for the function
/// @return the polyfill function name
@@ -62,8 +155,12 @@ struct BuiltinPolyfill::State {
return ScalarOrVector(width, u32(value));
};
b.Func(
- name, {b.Param("v", T(ty))}, T(ty),
- {
+ name,
+ utils::Vector{
+ b.Param("v", T(ty)),
+ },
+ T(ty),
+ utils::Vector{
// var x = U(v);
b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
// let b16 = select(0, 16, x <= 0x0000ffff);
@@ -123,8 +220,12 @@ struct BuiltinPolyfill::State {
return b.Construct(b.ty.vec<bool>(width), value);
};
b.Func(
- name, {b.Param("v", T(ty))}, T(ty),
- {
+ name,
+ utils::Vector{
+ b.Param("v", T(ty)),
+ },
+ T(ty),
+ utils::Vector{
// var x = U(v);
b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
// let b16 = select(16, 0, bool(x & 0x0000ffff));
@@ -176,20 +277,20 @@ struct BuiltinPolyfill::State {
return b.Construct(b.ty.vec<u32>(width), value);
};
- ast::StatementList body = {
+ utils::Vector<const ast::Statement*, 8> body{
b.Decl(b.Let("s", nullptr, b.Call("min", "offset", u32(W)))),
b.Decl(b.Let("e", nullptr, b.Call("min", u32(W), b.Add("s", "count")))),
};
switch (polyfill.extract_bits) {
case Level::kFull:
- body.emplace_back(b.Decl(b.Let("shl", nullptr, b.Sub(u32(W), "e"))));
- body.emplace_back(b.Decl(b.Let("shr", nullptr, b.Add("shl", "s"))));
- body.emplace_back(
+ body.Push(b.Decl(b.Let("shl", nullptr, b.Sub(u32(W), "e"))));
+ body.Push(b.Decl(b.Let("shr", nullptr, b.Add("shl", "s"))));
+ body.Push(
b.Return(b.Shr(b.Shl("v", vecN_u32(b.Expr("shl"))), vecN_u32(b.Expr("shr")))));
break;
case Level::kClampParameters:
- body.emplace_back(b.Return(b.Call("extractBits", "v", "s", b.Sub("e", "s"))));
+ body.Push(b.Return(b.Call("extractBits", "v", "s", b.Sub("e", "s"))));
break;
default:
TINT_ICE(Transform, b.Diagnostics())
@@ -198,12 +299,12 @@ struct BuiltinPolyfill::State {
}
b.Func(name,
- {
+ utils::Vector{
b.Param("v", T(ty)),
b.Param("offset", b.ty.u32()),
b.Param("count", b.ty.u32()),
},
- T(ty), body);
+ T(ty), std::move(body));
return name;
}
@@ -244,8 +345,12 @@ struct BuiltinPolyfill::State {
}
b.Func(
- name, {b.Param("v", T(ty))}, T(ty),
- {
+ name,
+ utils::Vector{
+ b.Param("v", T(ty)),
+ },
+ T(ty),
+ utils::Vector{
// var x = v; (unsigned)
// var x = select(U(v), ~U(v), v < 0); (signed)
b.Decl(b.Var("x", nullptr, x)),
@@ -306,8 +411,12 @@ struct BuiltinPolyfill::State {
return b.Construct(b.ty.vec<bool>(width), value);
};
b.Func(
- name, {b.Param("v", T(ty))}, T(ty),
- {
+ name,
+ utils::Vector{
+ b.Param("v", T(ty)),
+ },
+ T(ty),
+ utils::Vector{
// var x = U(v);
b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
// let b16 = select(16, 0, bool(x & 0x0000ffff));
@@ -369,7 +478,7 @@ struct BuiltinPolyfill::State {
return b.vec(b.ty.u32(), width, value);
};
- ast::StatementList body = {
+ utils::Vector<const ast::Statement*, 8> body = {
b.Decl(b.Let("s", nullptr, b.Call("min", "offset", u32(W)))),
b.Decl(b.Let("e", nullptr, b.Call("min", u32(W), b.Add("s", "count")))),
};
@@ -377,15 +486,15 @@ struct BuiltinPolyfill::State {
switch (polyfill.insert_bits) {
case Level::kFull:
// let mask = ((1 << s) - 1) ^ ((1 << e) - 1)
- body.emplace_back(
+ body.Push(
b.Decl(b.Let("mask", nullptr,
b.Xor(b.Sub(b.Shl(1_u, "s"), 1_u), b.Sub(b.Shl(1_u, "e"), 1_u)))));
// return ((n << s) & mask) | (v & ~mask)
- body.emplace_back(b.Return(b.Or(b.And(b.Shl("n", U("s")), V("mask")),
- b.And("v", V(b.Complement("mask"))))));
+ body.Push(b.Return(b.Or(b.And(b.Shl("n", U("s")), V("mask")),
+ b.And("v", V(b.Complement("mask"))))));
break;
case Level::kClampParameters:
- body.emplace_back(b.Return(b.Call("insertBits", "v", "n", "s", b.Sub("e", "s"))));
+ body.Push(b.Return(b.Call("insertBits", "v", "n", "s", b.Sub("e", "s"))));
break;
default:
TINT_ICE(Transform, b.Diagnostics())
@@ -394,7 +503,7 @@ struct BuiltinPolyfill::State {
}
b.Func(name,
- {
+ utils::Vector{
b.Param("v", T(ty)),
b.Param("n", T(ty)),
b.Param("offset", b.ty.u32()),
@@ -440,6 +549,21 @@ bool BuiltinPolyfill::ShouldRun(const Program* program, const DataMap& data) con
if (auto* call = sem.Get<sem::Call>(node)) {
if (auto* builtin = call->Target()->As<sem::Builtin>()) {
switch (builtin->Type()) {
+ case sem::BuiltinType::kAcosh:
+ if (builtins.acosh != Level::kNone) {
+ return true;
+ }
+ break;
+ case sem::BuiltinType::kAsinh:
+ if (builtins.asinh) {
+ return true;
+ }
+ break;
+ case sem::BuiltinType::kAtanh:
+ if (builtins.atanh != Level::kNone) {
+ return true;
+ }
+ break;
case sem::BuiltinType::kCountLeadingZeros:
if (builtins.count_leading_zeros) {
return true;
@@ -496,6 +620,24 @@ void BuiltinPolyfill::Run(CloneContext& ctx, const DataMap& data, DataMap&) cons
if (auto* builtin = call->Target()->As<sem::Builtin>()) {
Symbol polyfill;
switch (builtin->Type()) {
+ case sem::BuiltinType::kAcosh:
+ if (builtins.acosh != Level::kNone) {
+ polyfill = utils::GetOrCreate(
+ polyfills, builtin, [&] { return s.acosh(builtin->ReturnType()); });
+ }
+ break;
+ case sem::BuiltinType::kAsinh:
+ if (builtins.asinh) {
+ polyfill = utils::GetOrCreate(
+ polyfills, builtin, [&] { return s.asinh(builtin->ReturnType()); });
+ }
+ break;
+ case sem::BuiltinType::kAtanh:
+ if (builtins.atanh != Level::kNone) {
+ polyfill = utils::GetOrCreate(
+ polyfills, builtin, [&] { return s.atanh(builtin->ReturnType()); });
+ }
+ break;
case sem::BuiltinType::kCountLeadingZeros:
if (builtins.count_leading_zeros) {
polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
diff --git a/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.h b/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.h
index 8453189fb5a..8df41971316 100644
--- a/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.h
+++ b/chromium/third_party/dawn/src/tint/transform/builtin_polyfill.h
@@ -33,12 +33,20 @@ class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
kNone,
/// Clamp the parameters to the inner implementation.
kClampParameters,
+ /// Range check the input.
+ kRangeCheck,
/// Polyfill the entire function
kFull,
};
/// Specifies the builtins that should be polyfilled by the transform.
struct Builtins {
+ /// What level should `acosh` be polyfilled?
+ Level acosh = Level::kNone;
+ /// Should `asinh` be polyfilled?
+ bool asinh = false;
+ /// What level should `atanh` be polyfilled?
+ Level atanh = Level::kNone;
/// Should `countLeadingZeros()` be polyfilled?
bool count_leading_zeros = false;
/// Should `countTrailingZeros()` be polyfilled?
diff --git a/chromium/third_party/dawn/src/tint/transform/builtin_polyfill_test.cc b/chromium/third_party/dawn/src/tint/transform/builtin_polyfill_test.cc
index bc3dda8cbac..1292b658910 100644
--- a/chromium/third_party/dawn/src/tint/transform/builtin_polyfill_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/builtin_polyfill_test.cc
@@ -42,6 +42,292 @@ TEST_F(BuiltinPolyfillTest, EmptyModule) {
}
////////////////////////////////////////////////////////////////////////////////
+// acosh
+////////////////////////////////////////////////////////////////////////////////
+DataMap polyfillAcosh(Level level) {
+ BuiltinPolyfill::Builtins builtins;
+ builtins.acosh = level;
+ DataMap data;
+ data.Add<BuiltinPolyfill::Config>(builtins);
+ return data;
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunAcosh) {
+ auto* src = R"(
+fn f() {
+ acosh(1.0);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillAcosh(Level::kNone)));
+ EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAcosh(Level::kClampParameters)));
+ EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAcosh(Level::kFull)));
+}
+
+TEST_F(BuiltinPolyfillTest, Acosh_Full_f32) {
+ auto* src = R"(
+fn f() {
+ let r : f32 = acosh(1234);
+}
+)";
+
+ auto* expect = R"(
+fn tint_acosh(x : f32) -> f32 {
+ return log((x + sqrt(((x * x) - 1))));
+}
+
+fn f() {
+ let r : f32 = tint_acosh(1234);
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kFull));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Acosh_Full_vec3_f32) {
+ auto* src = R"(
+fn f() {
+ let r : vec3<f32> = acosh(vec3<f32>(1234));
+}
+)";
+
+ auto* expect = R"(
+fn tint_acosh(x : vec3<f32>) -> vec3<f32> {
+ return log((x + sqrt(((x * x) - 1))));
+}
+
+fn f() {
+ let r : vec3<f32> = tint_acosh(vec3<f32>(1234));
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kFull));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Acosh_Range_f32) {
+ auto* src = R"(
+fn f() {
+ let r : f32 = acosh(1234);
+}
+)";
+
+ auto* expect = R"(
+fn tint_acosh(x : f32) -> f32 {
+ return select(acosh(x), 0.0, (x < 1.0));
+}
+
+fn f() {
+ let r : f32 = tint_acosh(1234);
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kRangeCheck));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Acosh_Range_vec3_f32) {
+ auto* src = R"(
+fn f() {
+ let r : vec3<f32> = acosh(vec3<f32>(1234));
+}
+)";
+
+ auto* expect = R"(
+fn tint_acosh(x : vec3<f32>) -> vec3<f32> {
+ return select(acosh(x), vec3<f32>(0.0), (x < vec3<f32>(1.0)));
+}
+
+fn f() {
+ let r : vec3<f32> = tint_acosh(vec3<f32>(1234));
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kRangeCheck));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// asinh
+////////////////////////////////////////////////////////////////////////////////
+DataMap polyfillSinh() {
+ BuiltinPolyfill::Builtins builtins;
+ builtins.asinh = true;
+ DataMap data;
+ data.Add<BuiltinPolyfill::Config>(builtins);
+ return data;
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunAsinh) {
+ auto* src = R"(
+fn f() {
+ asinh(1.0);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillSinh()));
+}
+
+TEST_F(BuiltinPolyfillTest, Asinh_f32) {
+ auto* src = R"(
+fn f() {
+ let r : f32 = asinh(1234);
+}
+)";
+
+ auto* expect = R"(
+fn tint_sinh(x : f32) -> f32 {
+ return log((x + sqrt(((x * x) + 1))));
+}
+
+fn f() {
+ let r : f32 = tint_sinh(1234);
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillSinh());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Asinh_vec3_f32) {
+ auto* src = R"(
+fn f() {
+ let r : vec3<f32> = asinh(vec3<f32>(1234));
+}
+)";
+
+ auto* expect = R"(
+fn tint_sinh(x : vec3<f32>) -> vec3<f32> {
+ return log((x + sqrt(((x * x) + 1))));
+}
+
+fn f() {
+ let r : vec3<f32> = tint_sinh(vec3<f32>(1234));
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillSinh());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// atanh
+////////////////////////////////////////////////////////////////////////////////
+DataMap polyfillAtanh(Level level) {
+ BuiltinPolyfill::Builtins builtins;
+ builtins.atanh = level;
+ DataMap data;
+ data.Add<BuiltinPolyfill::Config>(builtins);
+ return data;
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunAtanh) {
+ auto* src = R"(
+fn f() {
+ atanh(1.0);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillAtanh(Level::kNone)));
+ EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAtanh(Level::kClampParameters)));
+ EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAtanh(Level::kFull)));
+}
+
+TEST_F(BuiltinPolyfillTest, Atanh_Full_f32) {
+ auto* src = R"(
+fn f() {
+ let r : f32 = atanh(1234);
+}
+)";
+
+ auto* expect = R"(
+fn tint_atanh(x : f32) -> f32 {
+ return (log(((1 + x) / (1 - x))) * 0.5);
+}
+
+fn f() {
+ let r : f32 = tint_atanh(1234);
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAtanh(Level::kFull));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Atanh_Full_vec3_f32) {
+ auto* src = R"(
+fn f() {
+ let r : vec3<f32> = atanh(vec3<f32>(1234));
+}
+)";
+
+ auto* expect = R"(
+fn tint_atanh(x : vec3<f32>) -> vec3<f32> {
+ return (log(((1 + x) / (1 - x))) * 0.5);
+}
+
+fn f() {
+ let r : vec3<f32> = tint_atanh(vec3<f32>(1234));
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAtanh(Level::kFull));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Atanh_Range_f32) {
+ auto* src = R"(
+fn f() {
+ let r : f32 = atanh(1234);
+}
+)";
+
+ auto* expect = R"(
+fn tint_atanh(x : f32) -> f32 {
+ return select(atanh(x), 0.0, (x >= 1.0));
+}
+
+fn f() {
+ let r : f32 = tint_atanh(1234);
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAtanh(Level::kRangeCheck));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Atanh_Range_vec3_f32) {
+ auto* src = R"(
+fn f() {
+ let r : vec3<f32> = atanh(vec3<f32>(1234));
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ let r : vec3<f32> = atanh(vec3<f32>(1234));
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kRangeCheck));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+////////////////////////////////////////////////////////////////////////////////
// countLeadingZeros
////////////////////////////////////////////////////////////////////////////////
DataMap polyfillCountLeadingZeros() {
diff --git a/chromium/third_party/dawn/src/tint/transform/calculate_array_length.cc b/chromium/third_party/dawn/src/tint/transform/calculate_array_length.cc
index bdda1cd43ba..6c15e739c9f 100644
--- a/chromium/third_party/dawn/src/tint/transform/calculate_array_length.cc
+++ b/chromium/third_party/dawn/src/tint/transform/calculate_array_length.cc
@@ -23,6 +23,7 @@
#include "src/tint/sem/block_statement.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/function.h"
+#include "src/tint/sem/reference.h"
#include "src/tint/sem/statement.h"
#include "src/tint/sem/struct.h"
#include "src/tint/sem/variable.h"
@@ -56,7 +57,8 @@ struct ArrayUsage {
} // namespace
-CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid) : Base(pid) {}
+CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid, ast::NodeID nid)
+ : Base(pid, nid) {}
CalculateArrayLength::BufferSizeIntrinsic::~BufferSizeIntrinsic() = default;
std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
return "intrinsic_buffer_size";
@@ -64,7 +66,8 @@ std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
const CalculateArrayLength::BufferSizeIntrinsic* CalculateArrayLength::BufferSizeIntrinsic::Clone(
CloneContext* ctx) const {
- return ctx->dst->ASTNodes().Create<CalculateArrayLength::BufferSizeIntrinsic>(ctx->dst->ID());
+ return ctx->dst->ASTNodes().Create<CalculateArrayLength::BufferSizeIntrinsic>(
+ ctx->dst->ID(), ctx->dst->AllocateNodeID());
}
CalculateArrayLength::CalculateArrayLength() = default;
@@ -89,30 +92,29 @@ void CalculateArrayLength::Run(CloneContext& ctx, const DataMap&, DataMap&) cons
// get_buffer_size_intrinsic() emits the function decorated with
// BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
// [RW]ByteAddressBuffer.GetDimensions().
- std::unordered_map<const sem::Type*, Symbol> buffer_size_intrinsics;
- auto get_buffer_size_intrinsic = [&](const sem::Type* buffer_type) {
+ std::unordered_map<const sem::Reference*, Symbol> buffer_size_intrinsics;
+ auto get_buffer_size_intrinsic = [&](const sem::Reference* buffer_type) {
return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
auto name = ctx.dst->Sym();
auto* type = CreateASTTypeFor(ctx, buffer_type);
auto* disable_validation =
- ctx.dst->Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
+ ctx.dst->Disable(ast::DisabledValidation::kFunctionParameter);
ctx.dst->AST().AddFunction(ctx.dst->create<ast::Function>(
name,
- ast::VariableList{
- // Note: The buffer parameter requires the kStorage StorageClass
- // in order for HLSL to emit this as a ByteAddressBuffer.
- ctx.dst->create<ast::Variable>(ctx.dst->Sym("buffer"),
- ast::StorageClass::kStorage,
- ast::Access::kUndefined, type, true, false,
- nullptr, ast::AttributeList{disable_validation}),
+ utils::Vector{
+ ctx.dst->Param("buffer",
+ ctx.dst->ty.pointer(type, buffer_type->StorageClass(),
+ buffer_type->Access()),
+ utils::Vector{disable_validation}),
ctx.dst->Param("result", ctx.dst->ty.pointer(ctx.dst->ty.u32(),
ast::StorageClass::kFunction)),
},
ctx.dst->ty.void_(), nullptr,
- ast::AttributeList{
- ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
+ utils::Vector{
+ ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID(),
+ ctx.dst->AllocateNodeID()),
},
- ast::AttributeList{}));
+ utils::Empty));
return name;
});
@@ -128,10 +130,10 @@ void CalculateArrayLength::Run(CloneContext& ctx, const DataMap&, DataMap&) cons
if (builtin->Type() == sem::BuiltinType::kArrayLength) {
// We're dealing with an arrayLength() call
- // A runtime-sized array can only appear as the store type of a
- // variable, or the last element of a structure (which cannot itself
- // be nested). Given that we require SimplifyPointers, we can assume
- // that the arrayLength() call has one of two forms:
+ // A runtime-sized array can only appear as the store type of a variable, or the
+ // last element of a structure (which cannot itself be nested). Given that we
+ // require SimplifyPointers, we can assume that the arrayLength() call has one
+ // of two forms:
// arrayLength(&struct_var.array_member)
// arrayLength(&array_var)
auto* arg = call_expr->args[0];
@@ -152,10 +154,9 @@ void CalculateArrayLength::Run(CloneContext& ctx, const DataMap&, DataMap&) cons
break;
}
auto* storage_buffer_var = storage_buffer_sem->Variable();
- auto* storage_buffer_type = storage_buffer_sem->Type()->UnwrapRef();
+ auto* storage_buffer_type = storage_buffer_sem->Type()->As<sem::Reference>();
- // Generate BufferSizeIntrinsic for this storage type if we haven't
- // already
+ // Generate BufferSizeIntrinsic for this storage type if we haven't already
auto buffer_size = get_buffer_size_intrinsic(storage_buffer_type);
// Find the current statement block
@@ -177,7 +178,7 @@ void CalculateArrayLength::Run(CloneContext& ctx, const DataMap&, DataMap&) cons
// BufferSizeIntrinsic(X, ARGS...) is
// translated to:
// X.GetDimensions(ARGS..) by the writer
- buffer_size, ctx.Clone(storage_buffer_expr),
+ buffer_size, ctx.dst->AddressOf(ctx.Clone(storage_buffer_expr)),
ctx.dst->AddressOf(
ctx.dst->Expr(buffer_size_result->variable->symbol))));
@@ -188,22 +189,26 @@ void CalculateArrayLength::Run(CloneContext& ctx, const DataMap&, DataMap&) cons
auto name = ctx.dst->Sym();
const ast::Expression* total_size =
ctx.dst->Expr(buffer_size_result->variable);
- const sem::Array* array_type = nullptr;
- if (auto* str = storage_buffer_type->As<sem::Struct>()) {
- // The variable is a struct, so subtract the byte offset of
- // the array member.
- auto* array_member_sem = str->Members().back();
- array_type = array_member_sem->Type()->As<sem::Array>();
- total_size =
- ctx.dst->Sub(total_size, u32(array_member_sem->Offset()));
- } else if (auto* arr = storage_buffer_type->As<sem::Array>()) {
- array_type = arr;
- } else {
+
+ const sem::Array* array_type = Switch(
+ storage_buffer_type->StoreType(),
+ [&](const sem::Struct* str) {
+ // The variable is a struct, so subtract the byte offset of
+ // the array member.
+ auto* array_member_sem = str->Members().back();
+ total_size =
+ ctx.dst->Sub(total_size, u32(array_member_sem->Offset()));
+ return array_member_sem->Type()->As<sem::Array>();
+ },
+ [&](const sem::Array* arr) { return arr; });
+
+ if (!array_type) {
TINT_ICE(Transform, ctx.dst->Diagnostics())
<< "expected form of arrayLength argument to be "
"&array_var or &struct_var.array_member";
return name;
}
+
uint32_t array_stride = array_type->Size();
auto* array_length_var = ctx.dst->Decl(
ctx.dst->Let(name, ctx.dst->ty.u32(),
diff --git a/chromium/third_party/dawn/src/tint/transform/calculate_array_length.h b/chromium/third_party/dawn/src/tint/transform/calculate_array_length.h
index 401e081aa73..8db8dcceca1 100644
--- a/chromium/third_party/dawn/src/tint/transform/calculate_array_length.h
+++ b/chromium/third_party/dawn/src/tint/transform/calculate_array_length.h
@@ -40,7 +40,8 @@ class CalculateArrayLength final : public Castable<CalculateArrayLength, Transfo
public:
/// Constructor
/// @param program_id the identifier of the program that owns this node
- explicit BufferSizeIntrinsic(ProgramID program_id);
+ /// @param nid the unique node identifier
+ BufferSizeIntrinsic(ProgramID program_id, ast::NodeID nid);
/// Destructor
~BufferSizeIntrinsic() override;
diff --git a/chromium/third_party/dawn/src/tint/transform/calculate_array_length_test.cc b/chromium/third_party/dawn/src/tint/transform/calculate_array_length_test.cc
index e2674b05729..98f2ed753d0 100644
--- a/chromium/third_party/dawn/src/tint/transform/calculate_array_length_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/calculate_array_length_test.cc
@@ -76,14 +76,14 @@ fn main() {
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
@group(0) @binding(0) var<storage, read> sb : array<i32>;
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(sb, &(tint_symbol_1));
+ tint_symbol(&(sb), &(tint_symbol_1));
let tint_symbol_2 : u32 = (tint_symbol_1 / 4u);
var len : u32 = tint_symbol_2;
}
@@ -111,7 +111,7 @@ fn main() {
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
struct SB {
x : i32,
@@ -123,7 +123,7 @@ struct SB {
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(sb, &(tint_symbol_1));
+ tint_symbol(&(sb), &(tint_symbol_1));
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
var len : u32 = tint_symbol_2;
}
@@ -149,7 +149,7 @@ fn main() {
)";
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<S>, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<S>, read>, result : ptr<function, u32>)
struct S {
f : f32,
@@ -160,7 +160,7 @@ struct S {
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(arr, &(tint_symbol_1));
+ tint_symbol(&(arr), &(tint_symbol_1));
let tint_symbol_2 : u32 = (tint_symbol_1 / 4u);
let len = tint_symbol_2;
}
@@ -186,7 +186,7 @@ fn main() {
)";
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<array<S, 4u>>, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<array<S, 4u>>, read>, result : ptr<function, u32>)
struct S {
f : f32,
@@ -197,7 +197,7 @@ struct S {
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(arr, &(tint_symbol_1));
+ tint_symbol(&(arr), &(tint_symbol_1));
let tint_symbol_2 : u32 = (tint_symbol_1 / 16u);
let len = tint_symbol_2;
}
@@ -222,14 +222,14 @@ fn main() {
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
@group(0) @binding(0) var<storage, read> sb : array<i32>;
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(sb, &(tint_symbol_1));
+ tint_symbol(&(sb), &(tint_symbol_1));
let tint_symbol_2 : u32 = (tint_symbol_1 / 4u);
var a : u32 = tint_symbol_2;
var b : u32 = tint_symbol_2;
@@ -261,7 +261,7 @@ fn main() {
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
struct SB {
x : i32,
@@ -273,7 +273,7 @@ struct SB {
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(sb, &(tint_symbol_1));
+ tint_symbol(&(sb), &(tint_symbol_1));
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
var a : u32 = tint_symbol_2;
var b : u32 = tint_symbol_2;
@@ -309,7 +309,7 @@ fn main() {
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
struct SB {
x : i32,
@@ -322,13 +322,13 @@ struct SB {
fn main() {
if (true) {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(sb, &(tint_symbol_1));
+ tint_symbol(&(sb), &(tint_symbol_1));
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
var len : u32 = tint_symbol_2;
} else {
if (true) {
var tint_symbol_3 : u32 = 0u;
- tint_symbol(sb, &(tint_symbol_3));
+ tint_symbol(&(sb), &(tint_symbol_3));
let tint_symbol_4 : u32 = ((tint_symbol_3 - 4u) / 4u);
var len : u32 = tint_symbol_4;
}
@@ -370,13 +370,13 @@ fn main() {
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB1, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB1, read>, result : ptr<function, u32>)
@internal(intrinsic_buffer_size)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB2, result : ptr<function, u32>)
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB2, read>, result : ptr<function, u32>)
@internal(intrinsic_buffer_size)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
struct SB1 {
x : i32,
@@ -397,13 +397,13 @@ struct SB2 {
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(sb1, &(tint_symbol_1));
+ tint_symbol(&(sb1), &(tint_symbol_1));
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
var tint_symbol_4 : u32 = 0u;
- tint_symbol_3(sb2, &(tint_symbol_4));
+ tint_symbol_3(&(sb2), &(tint_symbol_4));
let tint_symbol_5 : u32 = ((tint_symbol_4 - 16u) / 16u);
var tint_symbol_7 : u32 = 0u;
- tint_symbol_6(sb3, &(tint_symbol_7));
+ tint_symbol_6(&(sb3), &(tint_symbol_7));
let tint_symbol_8 : u32 = (tint_symbol_7 / 4u);
var len1 : u32 = tint_symbol_2;
var len2 : u32 = tint_symbol_5;
@@ -440,7 +440,7 @@ fn main() {
auto* expect =
R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
struct SB {
x : i32,
@@ -454,12 +454,12 @@ struct SB {
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(a, &(tint_symbol_1));
+ tint_symbol(&(a), &(tint_symbol_1));
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
var a_1 : u32 = tint_symbol_2;
{
var tint_symbol_3 : u32 = 0u;
- tint_symbol(a, &(tint_symbol_3));
+ tint_symbol(&(a), &(tint_symbol_3));
let tint_symbol_4 : u32 = ((tint_symbol_3 - 4u) / 4u);
var b_1 : u32 = tint_symbol_4;
}
@@ -500,24 +500,24 @@ struct SB2 {
auto* expect = R"(
@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB1, result : ptr<function, u32>)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB1, read>, result : ptr<function, u32>)
@internal(intrinsic_buffer_size)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB2, result : ptr<function, u32>)
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB2, read>, result : ptr<function, u32>)
@internal(intrinsic_buffer_size)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
@compute @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
- tint_symbol(sb1, &(tint_symbol_1));
+ tint_symbol(&(sb1), &(tint_symbol_1));
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
var tint_symbol_4 : u32 = 0u;
- tint_symbol_3(sb2, &(tint_symbol_4));
+ tint_symbol_3(&(sb2), &(tint_symbol_4));
let tint_symbol_5 : u32 = ((tint_symbol_4 - 16u) / 16u);
var tint_symbol_7 : u32 = 0u;
- tint_symbol_6(sb3, &(tint_symbol_7));
+ tint_symbol_6(&(sb3), &(tint_symbol_7));
let tint_symbol_8 : u32 = (tint_symbol_7 / 4u);
var len1 : u32 = tint_symbol_2;
var len2 : u32 = tint_symbol_5;
diff --git a/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io.cc b/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io.cc
index 44d577bb521..7670f09bc94 100644
--- a/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io.cc
@@ -69,9 +69,9 @@ bool IsShaderIOAttribute(const ast::Attribute* attr) {
}
// Returns true if `attrs` contains a `sample_mask` builtin.
-bool HasSampleMask(const ast::AttributeList& attrs) {
+bool HasSampleMask(utils::VectorRef<const ast::Attribute*> attrs) {
auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attrs);
- return builtin && builtin->builtin == ast::Builtin::kSampleMask;
+ return builtin && builtin->builtin == ast::BuiltinValue::kSampleMask;
}
} // namespace
@@ -85,7 +85,7 @@ struct CanonicalizeEntryPointIO::State {
/// The type of the output value.
const ast::Type* type;
/// The shader IO attributes.
- ast::AttributeList attributes;
+ utils::Vector<const ast::Attribute*, 2> attributes;
/// The value itself.
const ast::Expression* value;
};
@@ -100,19 +100,19 @@ struct CanonicalizeEntryPointIO::State {
const sem::Function* func_sem;
/// The new entry point wrapper function's parameters.
- ast::VariableList wrapper_ep_parameters;
+ utils::Vector<const ast::Parameter*, 8> wrapper_ep_parameters;
/// The members of the wrapper function's struct parameter.
- ast::StructMemberList wrapper_struct_param_members;
+ utils::Vector<const ast::StructMember*, 8> wrapper_struct_param_members;
/// The name of the wrapper function's struct parameter.
Symbol wrapper_struct_param_name;
/// The parameters that will be passed to the original function.
- ast::ExpressionList inner_call_parameters;
+ utils::Vector<const ast::Expression*, 8> inner_call_parameters;
/// The members of the wrapper function's struct return type.
- ast::StructMemberList wrapper_struct_output_members;
+ utils::Vector<const ast::StructMember*, 8> wrapper_struct_output_members;
/// The wrapper function output values.
- std::vector<OutputValue> wrapper_output_values;
+ utils::Vector<OutputValue, 8> wrapper_output_values;
/// The body of the wrapper function.
- ast::StatementList wrapper_body;
+ utils::Vector<const ast::Statement*, 8> wrapper_body;
/// Input names used by the entrypoint
std::unordered_set<std::string> input_names;
@@ -129,12 +129,13 @@ struct CanonicalizeEntryPointIO::State {
/// @param src the attributes to clone
/// @param do_interpolate whether to clone InterpolateAttribute
/// @return the cloned attributes
- ast::AttributeList CloneShaderIOAttributes(const ast::AttributeList& src, bool do_interpolate) {
- ast::AttributeList new_attributes;
+ template <size_t N>
+ auto CloneShaderIOAttributes(utils::Vector<const ast::Attribute*, N> src, bool do_interpolate) {
+ utils::Vector<const ast::Attribute*, N> new_attributes;
for (auto* attr : src) {
if (IsShaderIOAttribute(attr) &&
- (do_interpolate || !attr->Is<ast::InterpolateAttribute>())) {
- new_attributes.push_back(ctx.Clone(attr));
+ (do_interpolate || !attr->template Is<ast::InterpolateAttribute>())) {
+ new_attributes.Push(ctx.Clone(attr));
}
}
return new_attributes;
@@ -156,30 +157,32 @@ struct CanonicalizeEntryPointIO::State {
/// @returns an expression which evaluates to the value of the shader input
const ast::Expression* AddInput(std::string name,
const sem::Type* type,
- ast::AttributeList attributes) {
+ utils::Vector<const ast::Attribute*, 8> attributes) {
auto* ast_type = CreateASTTypeFor(ctx, type);
if (cfg.shader_style == ShaderStyle::kSpirv || cfg.shader_style == ShaderStyle::kGlsl) {
- // Vulkan requires that integer user-defined fragment inputs are
- // always decorated with `Flat`.
- // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
- // attribute is required for integers.
- if (type->is_integer_scalar_or_vector() &&
- ast::HasAttribute<ast::LocationAttribute>(attributes) &&
+ // Vulkan requires that integer user-defined fragment inputs are always decorated with
+ // `Flat`. See:
+ // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/StandaloneSpirv.html#VUID-StandaloneSpirv-Flat-04744
+ // TODO(crbug.com/tint/1224): Remove this once a flat interpolation attribute is
+ // required for integers.
+ if (func_ast->PipelineStage() == ast::PipelineStage::kFragment &&
+ type->is_integer_scalar_or_vector() &&
!ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
- func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
- attributes.push_back(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
- ast::InterpolationSampling::kNone));
+ (ast::HasAttribute<ast::LocationAttribute>(attributes) ||
+ cfg.shader_style == ShaderStyle::kSpirv)) {
+ attributes.Push(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
+ ast::InterpolationSampling::kNone));
}
// Disable validation for use of the `input` storage class.
- attributes.push_back(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+ attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
// In GLSL, if it's a builtin, override the name with the
// corresponding gl_ builtin name
auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attributes);
if (cfg.shader_style == ShaderStyle::kGlsl && builtin) {
name = GLSLBuiltinToString(builtin->builtin, func_ast->PipelineStage(),
- ast::StorageClass::kInput);
+ ast::StorageClass::kIn);
}
auto symbol = ctx.dst->Symbols().New(name);
@@ -189,14 +192,14 @@ struct CanonicalizeEntryPointIO::State {
if (builtin) {
if (cfg.shader_style == ShaderStyle::kGlsl) {
value = FromGLSLBuiltin(builtin->builtin, value, ast_type);
- } else if (builtin->builtin == ast::Builtin::kSampleMask) {
+ } else if (builtin->builtin == ast::BuiltinValue::kSampleMask) {
// Vulkan requires the type of a SampleMask builtin to be an array.
// Declare it as array<u32, 1> and then load the first element.
ast_type = ctx.dst->ty.array(ast_type, 1_u);
value = ctx.dst->IndexAccessor(value, 0_i);
}
}
- ctx.dst->Global(symbol, ast_type, ast::StorageClass::kInput, std::move(attributes));
+ ctx.dst->GlobalVar(symbol, ast_type, ast::StorageClass::kIn, std::move(attributes));
return value;
} else if (cfg.shader_style == ShaderStyle::kMsl &&
ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
@@ -204,14 +207,13 @@ struct CanonicalizeEntryPointIO::State {
// parameter list and pass it directly to the inner function.
Symbol symbol = input_names.emplace(name).second ? ctx.dst->Symbols().Register(name)
: ctx.dst->Symbols().New(name);
- wrapper_ep_parameters.push_back(
- ctx.dst->Param(symbol, ast_type, std::move(attributes)));
+ wrapper_ep_parameters.Push(ctx.dst->Param(symbol, ast_type, std::move(attributes)));
return ctx.dst->Expr(symbol);
} else {
// Otherwise, move it to the new structure member list.
Symbol symbol = input_names.emplace(name).second ? ctx.dst->Symbols().Register(name)
: ctx.dst->Symbols().New(name);
- wrapper_struct_param_members.push_back(
+ wrapper_struct_param_members.Push(
ctx.dst->Member(symbol, ast_type, std::move(attributes)));
return ctx.dst->MemberAccessor(InputStructSymbol(), symbol);
}
@@ -224,18 +226,19 @@ struct CanonicalizeEntryPointIO::State {
/// @param value the value of the shader output
void AddOutput(std::string name,
const sem::Type* type,
- ast::AttributeList attributes,
+ utils::Vector<const ast::Attribute*, 8> attributes,
const ast::Expression* value) {
- // Vulkan requires that integer user-defined vertex outputs are
- // always decorated with `Flat`.
- // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
- // attribute is required for integers.
- if (cfg.shader_style == ShaderStyle::kSpirv && type->is_integer_scalar_or_vector() &&
+ // Vulkan requires that integer user-defined vertex outputs are always decorated with
+ // `Flat`.
+ // TODO(crbug.com/tint/1224): Remove this once a flat interpolation attribute is required
+ // for integers.
+ if (cfg.shader_style == ShaderStyle::kSpirv &&
+ func_ast->PipelineStage() == ast::PipelineStage::kVertex &&
+ type->is_integer_scalar_or_vector() &&
ast::HasAttribute<ast::LocationAttribute>(attributes) &&
- !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
- func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
- attributes.push_back(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
- ast::InterpolationSampling::kNone));
+ !ast::HasAttribute<ast::InterpolateAttribute>(attributes)) {
+ attributes.Push(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
+ ast::InterpolationSampling::kNone));
}
// In GLSL, if it's a builtin, override the name with the
@@ -243,7 +246,7 @@ struct CanonicalizeEntryPointIO::State {
if (cfg.shader_style == ShaderStyle::kGlsl) {
if (auto* b = ast::GetAttribute<ast::BuiltinAttribute>(attributes)) {
name = GLSLBuiltinToString(b->builtin, func_ast->PipelineStage(),
- ast::StorageClass::kOutput);
+ ast::StorageClass::kOut);
value = ToGLSLBuiltin(b->builtin, value, type);
}
}
@@ -253,7 +256,7 @@ struct CanonicalizeEntryPointIO::State {
output.type = CreateASTTypeFor(ctx, type);
output.attributes = std::move(attributes);
output.value = value;
- wrapper_output_values.push_back(output);
+ wrapper_output_values.Push(output);
}
/// Process a non-struct parameter.
@@ -262,19 +265,23 @@ struct CanonicalizeEntryPointIO::State {
/// that will be passed to the original function.
/// @param param the original function parameter
void ProcessNonStructParameter(const sem::Parameter* param) {
+ // Do not add interpolation attributes on vertex input
+ bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kVertex;
// Remove the shader IO attributes from the inner function parameter, and
// attach them to the new object instead.
- ast::AttributeList attributes;
+ utils::Vector<const ast::Attribute*, 8> attributes;
for (auto* attr : param->Declaration()->attributes) {
if (IsShaderIOAttribute(attr)) {
ctx.Remove(param->Declaration()->attributes, attr);
- attributes.push_back(ctx.Clone(attr));
+ if ((do_interpolate || !attr->Is<ast::InterpolateAttribute>())) {
+ attributes.Push(ctx.Clone(attr));
+ }
}
}
auto name = ctx.src->Symbols().NameFor(param->Declaration()->symbol);
auto* input_expr = AddInput(name, param->Type(), std::move(attributes));
- inner_call_parameters.push_back(input_expr);
+ inner_call_parameters.Push(input_expr);
}
/// Process a struct parameter.
@@ -283,11 +290,14 @@ struct CanonicalizeEntryPointIO::State {
/// the original function.
/// @param param the original function parameter
void ProcessStructParameter(const sem::Parameter* param) {
+ // Do not add interpolation attributes on vertex input
+ bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kVertex;
+
auto* str = param->Type()->As<sem::Struct>();
// Recreate struct members in the outer entry point and build an initializer
// list to pass them through to the inner function.
- ast::ExpressionList inner_struct_values;
+ utils::Vector<const ast::Expression*, 8> inner_struct_values;
for (auto* member : str->Members()) {
if (member->Type()->Is<sem::Struct>()) {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
@@ -297,19 +307,13 @@ struct CanonicalizeEntryPointIO::State {
auto* member_ast = member->Declaration();
auto name = ctx.src->Symbols().NameFor(member_ast->symbol);
- // In GLSL, do not add interpolation attributes on vertex input
- bool do_interpolate = true;
- if (cfg.shader_style == ShaderStyle::kGlsl &&
- func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
- do_interpolate = false;
- }
auto attributes = CloneShaderIOAttributes(member_ast->attributes, do_interpolate);
auto* input_expr = AddInput(name, member->Type(), std::move(attributes));
- inner_struct_values.push_back(input_expr);
+ inner_struct_values.Push(input_expr);
}
// Construct the original structure using the new shader input objects.
- inner_call_parameters.push_back(
+ inner_call_parameters.Push(
ctx.dst->Construct(ctx.Clone(param->Declaration()->type), inner_struct_values));
}
@@ -319,12 +323,8 @@ struct CanonicalizeEntryPointIO::State {
/// @param inner_ret_type the original function return type
/// @param original_result the result object produced by the original function
void ProcessReturnType(const sem::Type* inner_ret_type, Symbol original_result) {
- bool do_interpolate = true;
- // In GLSL, do not add interpolation attributes on fragment output
- if (cfg.shader_style == ShaderStyle::kGlsl &&
- func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
- do_interpolate = false;
- }
+ // Do not add interpolation attributes on fragment output
+ bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kFragment;
if (auto* str = inner_ret_type->As<sem::Struct>()) {
for (auto* member : str->Members()) {
if (member->Type()->Is<sem::Struct>()) {
@@ -366,7 +366,7 @@ struct CanonicalizeEntryPointIO::State {
// No existing sample mask builtin was found, so create a new output value
// using the fixed sample mask.
AddOutput("fixed_sample_mask", ctx.dst->create<sem::U32>(),
- {ctx.dst->Builtin(ast::Builtin::kSampleMask)},
+ {ctx.dst->Builtin(ast::BuiltinValue::kSampleMask)},
ctx.dst->Expr(u32(cfg.fixed_sample_mask)));
}
@@ -374,7 +374,7 @@ struct CanonicalizeEntryPointIO::State {
void AddVertexPointSize() {
// Create a new output value and assign it a literal 1.0 value.
AddOutput("vertex_point_size", ctx.dst->create<sem::F32>(),
- {ctx.dst->Builtin(ast::Builtin::kPointSize)}, ctx.dst->Expr(1_f));
+ {ctx.dst->Builtin(ast::BuiltinValue::kPointSize)}, ctx.dst->Expr(1_f));
}
/// Create an expression for gl_Position.[component]
@@ -394,19 +394,19 @@ struct CanonicalizeEntryPointIO::State {
// Create the new struct type.
auto struct_name = ctx.dst->Sym();
- auto* in_struct = ctx.dst->create<ast::Struct>(struct_name, wrapper_struct_param_members,
- ast::AttributeList{});
+ auto* in_struct =
+ ctx.dst->create<ast::Struct>(struct_name, wrapper_struct_param_members, utils::Empty);
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, in_struct);
// Create a new function parameter using this struct type.
auto* param = ctx.dst->Param(InputStructSymbol(), ctx.dst->ty.type_name(struct_name));
- wrapper_ep_parameters.push_back(param);
+ wrapper_ep_parameters.Push(param);
}
/// Create and return the wrapper function's struct result object.
/// @returns the struct type
ast::Struct* CreateOutputStruct() {
- ast::StatementList assignments;
+ utils::Vector<const ast::Statement*, 8> assignments;
auto wrapper_result = ctx.dst->Symbols().New("wrapper_result");
@@ -422,9 +422,9 @@ struct CanonicalizeEntryPointIO::State {
}
member_names.insert(ctx.dst->Symbols().NameFor(name));
- wrapper_struct_output_members.push_back(
+ wrapper_struct_output_members.Push(
ctx.dst->Member(name, outval.type, std::move(outval.attributes)));
- assignments.push_back(
+ assignments.Push(
ctx.dst->Assign(ctx.dst->MemberAccessor(wrapper_result, name), outval.value));
}
@@ -434,14 +434,16 @@ struct CanonicalizeEntryPointIO::State {
// Create the new struct type.
auto* out_struct = ctx.dst->create<ast::Struct>(
- ctx.dst->Sym(), wrapper_struct_output_members, ast::AttributeList{});
+ ctx.dst->Sym(), wrapper_struct_output_members, utils::Empty);
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, out_struct);
// Create the output struct object, assign its members, and return it.
auto* result_object = ctx.dst->Var(wrapper_result, ctx.dst->ty.type_name(out_struct->name));
- wrapper_body.push_back(ctx.dst->Decl(result_object));
- wrapper_body.insert(wrapper_body.end(), assignments.begin(), assignments.end());
- wrapper_body.push_back(ctx.dst->Return(wrapper_result));
+ wrapper_body.Push(ctx.dst->Decl(result_object));
+ for (auto* assignment : assignments) {
+ wrapper_body.Push(assignment);
+ }
+ wrapper_body.Push(ctx.dst->Return(wrapper_result));
return out_struct;
}
@@ -450,8 +452,8 @@ struct CanonicalizeEntryPointIO::State {
void CreateGlobalOutputVariables() {
for (auto& outval : wrapper_output_values) {
// Disable validation for use of the `output` storage class.
- ast::AttributeList attributes = std::move(outval.attributes);
- attributes.push_back(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+ utils::Vector<const ast::Attribute*, 8> attributes = std::move(outval.attributes);
+ attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
// Create the global variable and assign it the output value.
auto name = ctx.dst->Symbols().New(outval.name);
@@ -463,8 +465,8 @@ struct CanonicalizeEntryPointIO::State {
type = ctx.dst->ty.array(type, 1_u);
lhs = ctx.dst->IndexAccessor(lhs, 0_i);
}
- ctx.dst->Global(name, type, ast::StorageClass::kOutput, std::move(attributes));
- wrapper_body.push_back(ctx.dst->Assign(lhs, outval.value));
+ ctx.dst->GlobalVar(name, type, ast::StorageClass::kOut, std::move(attributes));
+ wrapper_body.Push(ctx.dst->Assign(lhs, outval.value));
}
}
@@ -488,7 +490,7 @@ struct CanonicalizeEntryPointIO::State {
// processing.
auto* inner_function = ctx.dst->create<ast::Function>(
inner_name, ctx.Clone(func_ast->params), ctx.Clone(func_ast->return_type),
- ctx.Clone(func_ast->body), ast::AttributeList{}, ast::AttributeList{});
+ ctx.Clone(func_ast->body), utils::Empty, utils::Empty);
ctx.Replace(func_ast, inner_function);
// Call the function.
@@ -509,7 +511,7 @@ struct CanonicalizeEntryPointIO::State {
}
// Exit early if there is no shader IO to handle.
- if (func_sem->Parameters().size() == 0 && func_sem->ReturnType()->Is<sem::Void>() &&
+ if (func_sem->Parameters().Length() == 0 && func_sem->ReturnType()->Is<sem::Void>() &&
!needs_fixed_sample_mask && !needs_vertex_point_size &&
cfg.shader_style != ShaderStyle::kGlsl) {
return;
@@ -517,7 +519,7 @@ struct CanonicalizeEntryPointIO::State {
// Process the entry point parameters, collecting those that need to be
// aggregated into a single structure.
- if (!func_sem->Parameters().empty()) {
+ if (!func_sem->Parameters().IsEmpty()) {
for (auto* param : func_sem->Parameters()) {
if (param->Type()->Is<sem::Struct>()) {
ProcessStructParameter(param);
@@ -527,7 +529,7 @@ struct CanonicalizeEntryPointIO::State {
}
// Create a structure parameter for the outer entry point if necessary.
- if (!wrapper_struct_param_members.empty()) {
+ if (!wrapper_struct_param_members.IsEmpty()) {
CreateInputStruct();
}
}
@@ -539,12 +541,12 @@ struct CanonicalizeEntryPointIO::State {
std::function<const ast::Type*()> wrapper_ret_type = [&] { return ctx.dst->ty.void_(); };
if (func_sem->ReturnType()->Is<sem::Void>()) {
// The function call is just a statement with no result.
- wrapper_body.push_back(ctx.dst->CallStmt(call_inner));
+ wrapper_body.Push(ctx.dst->CallStmt(call_inner));
} else {
// Capture the result of calling the original function.
auto* inner_result =
ctx.dst->Let(ctx.dst->Symbols().New("inner_result"), nullptr, call_inner);
- wrapper_body.push_back(ctx.dst->Decl(inner_result));
+ wrapper_body.Push(ctx.dst->Decl(inner_result));
// Process the original return type to determine the outputs that the
// outer function needs to produce.
@@ -562,7 +564,7 @@ struct CanonicalizeEntryPointIO::State {
}
// Produce the entry point outputs, if necessary.
- if (!wrapper_output_values.empty()) {
+ if (!wrapper_output_values.IsEmpty()) {
if (cfg.shader_style == ShaderStyle::kSpirv || cfg.shader_style == ShaderStyle::kGlsl) {
CreateGlobalOutputVariables();
} else {
@@ -578,11 +580,11 @@ struct CanonicalizeEntryPointIO::State {
auto* pos_y = GLPosition("y");
auto* negate_pos_y =
ctx.dst->create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, GLPosition("y"));
- wrapper_body.push_back(ctx.dst->Assign(pos_y, negate_pos_y));
+ wrapper_body.Push(ctx.dst->Assign(pos_y, negate_pos_y));
auto* two_z = ctx.dst->Mul(ctx.dst->Expr(2_f), GLPosition("z"));
auto* fixed_z = ctx.dst->Sub(two_z, GLPosition("w"));
- wrapper_body.push_back(ctx.dst->Assign(GLPosition("z"), fixed_z));
+ wrapper_body.Push(ctx.dst->Assign(GLPosition("z"), fixed_z));
}
// Create the wrapper entry point function.
@@ -597,7 +599,7 @@ struct CanonicalizeEntryPointIO::State {
auto* wrapper_func = ctx.dst->create<ast::Function>(
name, wrapper_ep_parameters, wrapper_ret_type(), ctx.dst->Block(wrapper_body),
- ctx.Clone(func_ast->attributes), ast::AttributeList{});
+ ctx.Clone(func_ast->attributes), utils::Empty);
ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), func_ast, wrapper_func);
}
@@ -606,11 +608,11 @@ struct CanonicalizeEntryPointIO::State {
/// @param stage the current pipeline stage
/// @param storage_class the storage class (input or output)
/// @returns the gl_ string corresponding to that builtin
- const char* GLSLBuiltinToString(ast::Builtin builtin,
+ const char* GLSLBuiltinToString(ast::BuiltinValue builtin,
ast::PipelineStage stage,
ast::StorageClass storage_class) {
switch (builtin) {
- case ast::Builtin::kPosition:
+ case ast::BuiltinValue::kPosition:
switch (stage) {
case ast::PipelineStage::kVertex:
return "gl_Position";
@@ -619,28 +621,28 @@ struct CanonicalizeEntryPointIO::State {
default:
return "";
}
- case ast::Builtin::kVertexIndex:
+ case ast::BuiltinValue::kVertexIndex:
return "gl_VertexID";
- case ast::Builtin::kInstanceIndex:
+ case ast::BuiltinValue::kInstanceIndex:
return "gl_InstanceID";
- case ast::Builtin::kFrontFacing:
+ case ast::BuiltinValue::kFrontFacing:
return "gl_FrontFacing";
- case ast::Builtin::kFragDepth:
+ case ast::BuiltinValue::kFragDepth:
return "gl_FragDepth";
- case ast::Builtin::kLocalInvocationId:
+ case ast::BuiltinValue::kLocalInvocationId:
return "gl_LocalInvocationID";
- case ast::Builtin::kLocalInvocationIndex:
+ case ast::BuiltinValue::kLocalInvocationIndex:
return "gl_LocalInvocationIndex";
- case ast::Builtin::kGlobalInvocationId:
+ case ast::BuiltinValue::kGlobalInvocationId:
return "gl_GlobalInvocationID";
- case ast::Builtin::kNumWorkgroups:
+ case ast::BuiltinValue::kNumWorkgroups:
return "gl_NumWorkGroups";
- case ast::Builtin::kWorkgroupId:
+ case ast::BuiltinValue::kWorkgroupId:
return "gl_WorkGroupID";
- case ast::Builtin::kSampleIndex:
+ case ast::BuiltinValue::kSampleIndex:
return "gl_SampleID";
- case ast::Builtin::kSampleMask:
- if (storage_class == ast::StorageClass::kInput) {
+ case ast::BuiltinValue::kSampleMask:
+ if (storage_class == ast::StorageClass::kIn) {
return "gl_SampleMaskIn";
} else {
return "gl_SampleMask";
@@ -656,18 +658,18 @@ struct CanonicalizeEntryPointIO::State {
/// @param ast_type (inout) the incoming WGSL and outgoing GLSL types
/// @returns an expression representing the GLSL builtin converted to what
/// WGSL expects
- const ast::Expression* FromGLSLBuiltin(ast::Builtin builtin,
+ const ast::Expression* FromGLSLBuiltin(ast::BuiltinValue builtin,
const ast::Expression* value,
const ast::Type*& ast_type) {
switch (builtin) {
- case ast::Builtin::kVertexIndex:
- case ast::Builtin::kInstanceIndex:
- case ast::Builtin::kSampleIndex:
+ case ast::BuiltinValue::kVertexIndex:
+ case ast::BuiltinValue::kInstanceIndex:
+ case ast::BuiltinValue::kSampleIndex:
// GLSL uses i32 for these, so bitcast to u32.
value = ctx.dst->Bitcast(ast_type, value);
ast_type = ctx.dst->ty.i32();
break;
- case ast::Builtin::kSampleMask:
+ case ast::BuiltinValue::kSampleMask:
// gl_SampleMask is an array of i32. Retrieve the first element and
// bitcast it to u32.
value = ctx.dst->IndexAccessor(value, 0_i);
@@ -686,14 +688,14 @@ struct CanonicalizeEntryPointIO::State {
/// @param value the value to convert
/// @param type (out) the type to which the value was converted
/// @returns the converted value which can be assigned to the GLSL builtin
- const ast::Expression* ToGLSLBuiltin(ast::Builtin builtin,
+ const ast::Expression* ToGLSLBuiltin(ast::BuiltinValue builtin,
const ast::Expression* value,
const sem::Type*& type) {
switch (builtin) {
- case ast::Builtin::kVertexIndex:
- case ast::Builtin::kInstanceIndex:
- case ast::Builtin::kSampleIndex:
- case ast::Builtin::kSampleMask:
+ case ast::BuiltinValue::kVertexIndex:
+ case ast::BuiltinValue::kInstanceIndex:
+ case ast::BuiltinValue::kSampleIndex:
+ case ast::BuiltinValue::kSampleMask:
type = ctx.dst->create<sem::I32>();
value = ctx.dst->Bitcast(CreateASTTypeFor(ctx, type), value);
break;
diff --git a/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io_test.cc b/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io_test.cc
index f17c5f5e880..f2af21389db 100644
--- a/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/canonicalize_entry_point_io_test.cc
@@ -1978,13 +1978,13 @@ fn frag_main(inputs : FragmentInterface) -> FragmentInterface {
@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> vu_3 : vec4<u32>;
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
+@location(0) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
+@location(1) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
struct VertexIn {
i : i32,
@@ -2108,13 +2108,13 @@ struct FragmentInterface {
@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> vu_3 : vec4<u32>;
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
+@location(0) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
+@location(1) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
fn vert_main_inner(in : VertexIn) -> VertexOut {
return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
@@ -2344,7 +2344,7 @@ struct tint_symbol_1 {
}
struct tint_symbol_2 {
- @location(1) @interpolate(flat)
+ @location(1)
value : f32,
}
@@ -2397,7 +2397,7 @@ struct tint_symbol_1 {
}
struct tint_symbol_2 {
- @location(1) @interpolate(flat)
+ @location(1)
value : f32,
}
@@ -3163,7 +3163,7 @@ fn vert_main() -> @builtin(position) vec4<f32> {
auto* expect = R"(
@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> value : vec4<f32>;
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
fn vert_main_inner() -> vec4<f32> {
return vec4<f32>();
@@ -3197,7 +3197,7 @@ fn vert_main() -> @builtin(position) vec4<f32> {
struct tint_symbol {
@builtin(position)
value : vec4<f32>,
- @builtin(pointsize)
+ @builtin(point_size)
vertex_point_size : f32,
}
@@ -3238,7 +3238,7 @@ fn vert_main() -> VertOut {
auto* expect = R"(
@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> pos_1 : vec4<f32>;
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
struct VertOut {
pos : vec4<f32>,
@@ -3279,7 +3279,7 @@ struct VertOut {
auto* expect = R"(
@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> pos_1 : vec4<f32>;
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
fn vert_main_inner() -> VertOut {
return VertOut();
@@ -3325,7 +3325,7 @@ struct VertOut {
struct tint_symbol {
@builtin(position)
pos : vec4<f32>,
- @builtin(pointsize)
+ @builtin(point_size)
vertex_point_size : f32,
}
@@ -3367,7 +3367,7 @@ struct VertOut {
struct tint_symbol {
@builtin(position)
pos : vec4<f32>,
- @builtin(pointsize)
+ @builtin(point_size)
vertex_point_size : f32,
}
@@ -3432,7 +3432,7 @@ fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_1_1 : vec4<f32>;
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
var<private> vertex_point_size : f32;
@@ -3510,7 +3510,7 @@ struct VertOut {
@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_1_1 : vec4<f32>;
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
let x = (collide.collide + collide_1.collide);
@@ -3601,7 +3601,7 @@ struct tint_symbol_2 {
vertex_point_size : vec4<f32>,
@builtin(position)
vertex_point_size_1 : vec4<f32>,
- @builtin(pointsize)
+ @builtin(point_size)
vertex_point_size_2 : f32,
}
@@ -3664,7 +3664,7 @@ struct tint_symbol_2 {
vertex_point_size : vec4<f32>,
@builtin(position)
vertex_point_size_1 : vec4<f32>,
- @builtin(pointsize)
+ @builtin(point_size)
vertex_point_size_2 : f32,
}
@@ -3753,7 +3753,7 @@ struct tint_symbol_2 {
vertex_point_size : vec4<f32>,
@builtin(position)
vertex_point_size_1 : vec4<f32>,
- @builtin(pointsize)
+ @builtin(point_size)
vertex_point_size_2 : f32,
}
@@ -3816,7 +3816,7 @@ struct tint_symbol_2 {
vertex_point_size : vec4<f32>,
@builtin(position)
vertex_point_size_1 : vec4<f32>,
- @builtin(pointsize)
+ @builtin(point_size)
vertex_point_size_2 : f32,
}
@@ -3868,9 +3868,9 @@ fn main(@builtin(sample_index) sample_index : u32,
)";
auto* expect = R"(
-@builtin(sample_index) @internal(disable_validation__ignore_storage_class) var<in> sample_index_1 : u32;
+@builtin(sample_index) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> sample_index_1 : u32;
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<in> mask_in_1 : array<u32, 1u>;
+@builtin(sample_mask) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> mask_in_1 : array<u32, 1u>;
@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> value : array<u32, 1u>;
diff --git a/chromium/third_party/dawn/src/tint/transform/combine_samplers.cc b/chromium/third_party/dawn/src/tint/transform/combine_samplers.cc
index c9d4913b99a..ca9005b3cfb 100644
--- a/chromium/third_party/dawn/src/tint/transform/combine_samplers.cc
+++ b/chromium/third_party/dawn/src/tint/transform/combine_samplers.cc
@@ -19,6 +19,7 @@
#include <utility>
#include <vector>
+#include "src/tint/program_builder.h"
#include "src/tint/sem/function.h"
#include "src/tint/sem/statement.h"
@@ -77,9 +78,9 @@ struct CombineSamplers::State {
/// Group and binding attributes used by all combined sampler globals.
/// Group 0 and binding 0 are used, with collisions disabled.
/// @returns the newly-created attribute list
- ast::AttributeList Attributes() const {
- auto attributes = ctx.dst->GroupAndBinding(0, 0);
- attributes.push_back(ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision));
+ auto Attributes() const {
+ utils::Vector<const ast::Attribute*, 3> attributes = ctx.dst->GroupAndBinding(0, 0);
+ attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision));
return attributes;
}
@@ -109,7 +110,7 @@ struct CombineSamplers::State {
}
const ast::Type* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
Symbol symbol = ctx.dst->Symbols().New(name);
- return ctx.dst->Global(symbol, type, Attributes());
+ return ctx.dst->GlobalVar(symbol, type, Attributes());
}
/// Creates placeholder global sampler variables.
@@ -121,7 +122,7 @@ struct CombineSamplers::State {
? "placeholder_comparison_sampler"
: "placeholder_sampler";
Symbol symbol = ctx.dst->Symbols().New(name);
- return ctx.dst->Global(symbol, type, Attributes());
+ return ctx.dst->GlobalVar(symbol, type, Attributes());
}
/// Creates ast::Type for a given texture and sampler variable pair.
@@ -147,16 +148,16 @@ struct CombineSamplers::State {
// Remove all texture and sampler global variables. These will be replaced
// by combined samplers.
- for (auto* var : ctx.src->AST().GlobalVariables()) {
- auto* type = sem.Get(var->type);
- if (type && type->IsAnyOf<sem::Texture, sem::Sampler>() &&
+ for (auto* global : ctx.src->AST().GlobalVariables()) {
+ auto* type = sem.Get(global->type);
+ if (tint::IsAnyOf<sem::Texture, sem::Sampler>(type) &&
!type->Is<sem::StorageTexture>()) {
- ctx.Remove(ctx.src->AST().GlobalDeclarations(), var);
- } else if (auto binding_point = var->BindingPoint()) {
+ ctx.Remove(ctx.src->AST().GlobalDeclarations(), global);
+ } else if (auto binding_point = global->BindingPoint()) {
if (binding_point.group->value == 0 && binding_point.binding->value == 0) {
auto* attribute =
ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
- ctx.InsertFront(var->attributes, attribute);
+ ctx.InsertFront(global->attributes, attribute);
}
}
}
@@ -166,10 +167,10 @@ struct CombineSamplers::State {
ctx.ReplaceAll([&](const ast::Function* src) -> const ast::Function* {
if (auto* func = sem.Get(src)) {
auto pairs = func->TextureSamplerPairs();
- if (pairs.empty()) {
+ if (pairs.IsEmpty()) {
return nullptr;
}
- ast::VariableList params;
+ utils::Vector<const ast::Parameter*, 8> params;
for (auto pair : func->TextureSamplerPairs()) {
const sem::Variable* texture_var = pair.first;
const sem::Variable* sampler_var = pair.second;
@@ -188,10 +189,9 @@ struct CombineSamplers::State {
} else {
// Either texture or sampler (or both) is a function parameter;
// add a new function parameter to represent the combined sampler.
- const ast::Type* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
- const ast::Variable* var =
- ctx.dst->Param(ctx.dst->Symbols().New(name), type);
- params.push_back(var);
+ auto* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
+ auto* var = ctx.dst->Param(ctx.dst->Symbols().New(name), type);
+ params.Push(var);
function_combined_texture_samplers_[func][pair] = var;
}
}
@@ -199,7 +199,7 @@ struct CombineSamplers::State {
// function signature.
for (auto* var : src->params) {
if (!sem.Get(var->type)->IsAnyOf<sem::Texture, sem::Sampler>()) {
- params.push_back(ctx.Clone(var));
+ params.Push(ctx.Clone(var));
}
}
// Create a new function signature that differs only in the parameter
@@ -221,23 +221,25 @@ struct CombineSamplers::State {
// the combined global samplers, as appropriate.
ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
if (auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>()) {
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
// Replace all texture builtin calls.
if (auto* builtin = call->Target()->As<sem::Builtin>()) {
const auto& signature = builtin->Signature();
- int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
- int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
+ auto sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
+ auto texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
if (texture_index == -1) {
return nullptr;
}
- const sem::Expression* texture = call->Arguments()[texture_index];
+ const sem::Expression* texture =
+ call->Arguments()[static_cast<size_t>(texture_index)];
// We don't want to combine storage textures with anything, since
// they never have associated samplers in GLSL.
if (texture->Type()->UnwrapRef()->Is<sem::StorageTexture>()) {
return nullptr;
}
const sem::Expression* sampler =
- sampler_index != -1 ? call->Arguments()[sampler_index] : nullptr;
+ sampler_index != -1 ? call->Arguments()[static_cast<size_t>(sampler_index)]
+ : nullptr;
auto* texture_var = texture->As<sem::VariableUser>()->Variable();
auto* sampler_var =
sampler ? sampler->As<sem::VariableUser>()->Variable() : nullptr;
@@ -250,7 +252,7 @@ struct CombineSamplers::State {
? global_combined_texture_samplers_[new_pair]
: function_combined_texture_samplers_[call->Stmt()->Function()]
[new_pair];
- args.push_back(ctx.dst->Expr(var->symbol));
+ args.Push(ctx.dst->Expr(var->symbol));
} else if (auto* sampler_type = type->As<sem::Sampler>()) {
ast::SamplerKind kind = sampler_type->kind();
int index = (kind == ast::SamplerKind::kSampler) ? 0 : 1;
@@ -258,9 +260,9 @@ struct CombineSamplers::State {
if (!p) {
p = CreatePlaceholder(kind);
}
- args.push_back(ctx.dst->Expr(p->symbol));
+ args.Push(ctx.dst->Expr(p->symbol));
} else {
- args.push_back(ctx.Clone(arg));
+ args.Push(ctx.Clone(arg));
}
}
const ast::Expression* value =
@@ -302,7 +304,7 @@ struct CombineSamplers::State {
: function_combined_texture_samplers_[call->Stmt()->Function()]
[new_pair];
auto* arg = ctx.dst->Expr(var->symbol);
- args.push_back(arg);
+ args.Push(arg);
}
// Append all of the remaining non-texture and non-sampler
// parameters.
@@ -310,7 +312,7 @@ struct CombineSamplers::State {
if (!ctx.src->TypeOf(arg)
->UnwrapRef()
->IsAnyOf<sem::Texture, sem::Sampler>()) {
- args.push_back(ctx.Clone(arg));
+ args.Push(ctx.Clone(arg));
}
}
return ctx.dst->Call(ctx.Clone(expr->target.name), args);
diff --git a/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.cc b/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.cc
index a90a6e2711c..99fe94e264a 100644
--- a/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.cc
+++ b/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.cc
@@ -73,7 +73,7 @@ struct OffsetExpr : Offset {
/// OffsetLiteral is an implementation of Offset that constructs a u32 literal
/// value.
-struct OffsetLiteral : Castable<OffsetLiteral, Offset> {
+struct OffsetLiteral final : Castable<OffsetLiteral, Offset> {
uint32_t const literal = 0;
explicit OffsetLiteral(uint32_t lit) : literal(lit) {}
@@ -98,29 +98,32 @@ struct OffsetBinOp : Offset {
/// LoadStoreKey is the unordered map key to a load or store intrinsic.
struct LoadStoreKey {
ast::StorageClass const storage_class; // buffer storage class
+ ast::Access const access; // buffer access
sem::Type const* buf_ty = nullptr; // buffer type
sem::Type const* el_ty = nullptr; // element type
bool operator==(const LoadStoreKey& rhs) const {
- return storage_class == rhs.storage_class && buf_ty == rhs.buf_ty && el_ty == rhs.el_ty;
+ return storage_class == rhs.storage_class && access == rhs.access && buf_ty == rhs.buf_ty &&
+ el_ty == rhs.el_ty;
}
struct Hasher {
inline std::size_t operator()(const LoadStoreKey& u) const {
- return utils::Hash(u.storage_class, u.buf_ty, u.el_ty);
+ return utils::Hash(u.storage_class, u.access, u.buf_ty, u.el_ty);
}
};
};
/// AtomicKey is the unordered map key to an atomic intrinsic.
struct AtomicKey {
+ ast::Access const access; // buffer access
sem::Type const* buf_ty = nullptr; // buffer type
sem::Type const* el_ty = nullptr; // element type
sem::BuiltinType const op; // atomic op
bool operator==(const AtomicKey& rhs) const {
- return buf_ty == rhs.buf_ty && el_ty == rhs.el_ty && op == rhs.op;
+ return access == rhs.access && buf_ty == rhs.buf_ty && el_ty == rhs.el_ty && op == rhs.op;
}
struct Hasher {
inline std::size_t operator()(const AtomicKey& u) const {
- return utils::Hash(u.buf_ty, u.el_ty, u.op);
+ return utils::Hash(u.access, u.buf_ty, u.el_ty, u.op);
}
};
};
@@ -199,7 +202,8 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicLoadFor(ProgramBuilder* builder,
return nullptr;
}
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
- builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, storage_class, type);
+ builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad,
+ storage_class, type);
}
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
@@ -212,7 +216,8 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicStoreFor(ProgramBuilder* builder,
return nullptr;
}
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
- builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kStore, storage_class, type);
+ builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kStore,
+ storage_class, type);
}
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
@@ -267,7 +272,7 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ProgramBuilder* builder,
return nullptr;
}
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
- builder->ID(), op, ast::StorageClass::kStorage, type);
+ builder->ID(), builder->AllocateNodeID(), op, ast::StorageClass::kStorage, type);
}
/// BufferAccess describes a single storage or uniform buffer access
@@ -323,7 +328,7 @@ struct DecomposeMemoryAccess::State {
/// @returns an Offset for the given ast::Expression
const Offset* ToOffset(const ast::Expression* expr) {
if (auto* lit = expr->As<ast::IntLiteralExpression>()) {
- if (lit->value > 0) {
+ if (lit->value >= 0) {
return offsets_.Create<OffsetLiteral>(static_cast<uint32_t>(lit->value));
}
}
@@ -374,10 +379,10 @@ struct DecomposeMemoryAccess::State {
auto* lhs_lit = tint::As<OffsetLiteral>(lhs);
auto* rhs_lit = tint::As<OffsetLiteral>(rhs);
if (lhs_lit && lhs_lit->literal == 0) {
- return offsets_.Create<OffsetLiteral>(0);
+ return offsets_.Create<OffsetLiteral>(0u);
}
if (rhs_lit && rhs_lit->literal == 0) {
- return offsets_.Create<OffsetLiteral>(0);
+ return offsets_.Create<OffsetLiteral>(0u);
}
if (lhs_lit && lhs_lit->literal == 1) {
return rhs;
@@ -420,10 +425,10 @@ struct DecomposeMemoryAccess::State {
return access;
}
- /// LoadFunc() returns a symbol to an intrinsic function that loads an element
- /// of type `el_ty` from a storage or uniform buffer of type `buf_ty`.
+ /// LoadFunc() returns a symbol to an intrinsic function that loads an element of type `el_ty`
+ /// from a storage or uniform buffer of type `buf_ty`.
/// The emitted function has the signature:
- /// `fn load(buf : buf_ty, offset : u32) -> el_ty`
+ /// `fn load(buf : ptr<SC, buf_ty, A>, offset : u32) -> el_ty`
/// @param buf_ty the storage or uniform buffer type
/// @param el_ty the storage or uniform buffer element type
/// @param var_user the variable user
@@ -432,89 +437,84 @@ struct DecomposeMemoryAccess::State {
const sem::Type* el_ty,
const sem::VariableUser* var_user) {
auto storage_class = var_user->Variable()->StorageClass();
- return utils::GetOrCreate(load_funcs, LoadStoreKey{storage_class, buf_ty, el_ty}, [&] {
- auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
- auto* disable_validation =
- b.Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
-
- ast::VariableList params = {
- // Note: The buffer parameter requires the StorageClass in
- // order for HLSL to emit this as a ByteAddressBuffer or cbuffer
- // array.
- b.create<ast::Variable>(b.Sym("buffer"), storage_class,
- var_user->Variable()->Access(), buf_ast_ty, true, false,
- nullptr, ast::AttributeList{disable_validation}),
- b.Param("offset", b.ty.u32()),
- };
-
- auto name = b.Sym();
-
- if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, storage_class, el_ty)) {
- auto* el_ast_ty = CreateASTTypeFor(ctx, el_ty);
- auto* func = b.create<ast::Function>(
- name, params, el_ast_ty, nullptr,
- ast::AttributeList{
- intrinsic,
- b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
- },
- ast::AttributeList{});
- b.AST().AddFunction(func);
- } else if (auto* arr_ty = el_ty->As<sem::Array>()) {
- // fn load_func(buf : buf_ty, offset : u32) -> array<T, N> {
- // var arr : array<T, N>;
- // for (var i = 0u; i < array_count; i = i + 1) {
- // arr[i] = el_load_func(buf, offset + i * array_stride)
- // }
- // return arr;
- // }
- auto load = LoadFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
- auto* arr = b.Var(b.Symbols().New("arr"), CreateASTTypeFor(ctx, arr_ty));
- auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0_u));
- auto* for_init = b.Decl(i);
- auto* for_cond = b.create<ast::BinaryExpression>(
- ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_ty->Count())));
- auto* for_cont = b.Assign(i, b.Add(i, 1_u));
- auto* arr_el = b.IndexAccessor(arr, i);
- auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
- auto* el_val = b.Call(load, "buffer", el_offset);
- auto* for_loop =
- b.For(for_init, for_cond, for_cont, b.Block(b.Assign(arr_el, el_val)));
-
- b.Func(name, params, CreateASTTypeFor(ctx, arr_ty),
- {
- b.Decl(arr),
- for_loop,
- b.Return(arr),
- });
- } else {
- ast::ExpressionList values;
- if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
- auto* vec_ty = mat_ty->ColumnType();
- Symbol load = LoadFunc(buf_ty, vec_ty, var_user);
- for (uint32_t i = 0; i < mat_ty->columns(); i++) {
- auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
- values.emplace_back(b.Call(load, "buffer", offset));
- }
- } else if (auto* str = el_ty->As<sem::Struct>()) {
- for (auto* member : str->Members()) {
- auto* offset = b.Add("offset", u32(member->Offset()));
- Symbol load = LoadFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
- values.emplace_back(b.Call(load, "buffer", offset));
+ auto access = var_user->Variable()->Access();
+ return utils::GetOrCreate(
+ load_funcs, LoadStoreKey{storage_class, access, buf_ty, el_ty}, [&] {
+ utils::Vector params{
+ b.Param("buffer",
+ b.ty.pointer(CreateASTTypeFor(ctx, buf_ty), storage_class, access),
+ utils::Vector{b.Disable(ast::DisabledValidation::kFunctionParameter)}),
+ b.Param("offset", b.ty.u32()),
+ };
+
+ auto name = b.Sym();
+
+ if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, storage_class, el_ty)) {
+ auto* el_ast_ty = CreateASTTypeFor(ctx, el_ty);
+ auto* func = b.create<ast::Function>(
+ name, params, el_ast_ty, nullptr,
+ utils::Vector{
+ intrinsic,
+ b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+ },
+ utils::Empty);
+ b.AST().AddFunction(func);
+ } else if (auto* arr_ty = el_ty->As<sem::Array>()) {
+ // fn load_func(buffer : buf_ty, offset : u32) -> array<T, N> {
+ // var arr : array<T, N>;
+ // for (var i = 0u; i < array_count; i = i + 1) {
+ // arr[i] = el_load_func(buffer, offset + i * array_stride)
+ // }
+ // return arr;
+ // }
+ auto load = LoadFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
+ auto* arr = b.Var(b.Symbols().New("arr"), CreateASTTypeFor(ctx, arr_ty));
+ auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0_u));
+ auto* for_init = b.Decl(i);
+ auto* for_cond = b.create<ast::BinaryExpression>(
+ ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_ty->Count())));
+ auto* for_cont = b.Assign(i, b.Add(i, 1_u));
+ auto* arr_el = b.IndexAccessor(arr, i);
+ auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
+ auto* el_val = b.Call(load, "buffer", el_offset);
+ auto* for_loop =
+ b.For(for_init, for_cond, for_cont, b.Block(b.Assign(arr_el, el_val)));
+
+ b.Func(name, params, CreateASTTypeFor(ctx, arr_ty),
+ utils::Vector{
+ b.Decl(arr),
+ for_loop,
+ b.Return(arr),
+ });
+ } else {
+ utils::Vector<const ast::Expression*, 8> values;
+ if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
+ auto* vec_ty = mat_ty->ColumnType();
+ Symbol load = LoadFunc(buf_ty, vec_ty, var_user);
+ for (uint32_t i = 0; i < mat_ty->columns(); i++) {
+ auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
+ values.Push(b.Call(load, "buffer", offset));
+ }
+ } else if (auto* str = el_ty->As<sem::Struct>()) {
+ for (auto* member : str->Members()) {
+ auto* offset = b.Add("offset", u32(member->Offset()));
+ Symbol load = LoadFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
+ values.Push(b.Call(load, "buffer", offset));
+ }
}
+ b.Func(name, params, CreateASTTypeFor(ctx, el_ty),
+ utils::Vector{
+ b.Return(b.Construct(CreateASTTypeFor(ctx, el_ty), values)),
+ });
}
- b.Func(name, params, CreateASTTypeFor(ctx, el_ty),
- {
- b.Return(b.Construct(CreateASTTypeFor(ctx, el_ty), values)),
- });
- }
- return name;
- });
+ return name;
+ });
}
/// StoreFunc() returns a symbol to an intrinsic function that stores an
/// element of type `el_ty` to a storage buffer of type `buf_ty`.
/// The function has the signature:
- /// `fn store(buf : buf_ty, offset : u32, value : el_ty)`
+ /// `fn store(buf : ptr<SC, buf_ty, A>, offset : u32, value : el_ty)`
/// @param buf_ty the storage buffer type
/// @param el_ty the storage buffer element type
/// @param var_user the variable user
@@ -523,87 +523,95 @@ struct DecomposeMemoryAccess::State {
const sem::Type* el_ty,
const sem::VariableUser* var_user) {
auto storage_class = var_user->Variable()->StorageClass();
- return utils::GetOrCreate(store_funcs, LoadStoreKey{storage_class, buf_ty, el_ty}, [&] {
- auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
- auto* el_ast_ty = CreateASTTypeFor(ctx, el_ty);
- auto* disable_validation =
- b.Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
- ast::VariableList params{
- // Note: The buffer parameter requires the StorageClass in
- // order for HLSL to emit this as a ByteAddressBuffer.
-
- b.create<ast::Variable>(b.Sym("buffer"), storage_class,
- var_user->Variable()->Access(), buf_ast_ty, true, false,
- nullptr, ast::AttributeList{disable_validation}),
- b.Param("offset", b.ty.u32()),
- b.Param("value", el_ast_ty),
- };
+ auto access = var_user->Variable()->Access();
+ return utils::GetOrCreate(
+ store_funcs, LoadStoreKey{storage_class, access, buf_ty, el_ty}, [&] {
+ utils::Vector params{
+ b.Param("buffer",
+ b.ty.pointer(CreateASTTypeFor(ctx, buf_ty), storage_class, access),
+ utils::Vector{b.Disable(ast::DisabledValidation::kFunctionParameter)}),
+ b.Param("offset", b.ty.u32()),
+ b.Param("value", CreateASTTypeFor(ctx, el_ty)),
+ };
+
+ auto name = b.Sym();
+
+ if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, storage_class, el_ty)) {
+ auto* func = b.create<ast::Function>(
+ name, params, b.ty.void_(), nullptr,
+ utils::Vector{
+ intrinsic,
+ b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+ },
+ utils::Empty);
+ b.AST().AddFunction(func);
+ } else {
+ auto body = Switch<utils::Vector<const ast::Statement*, 8>>(
+ el_ty, //
+ [&](const sem::Array* arr_ty) {
+ // fn store_func(buffer : buf_ty, offset : u32, value : el_ty) {
+ // var array = value; // No dynamic indexing on constant arrays
+ // for (var i = 0u; i < array_count; i = i + 1) {
+ // arr[i] = el_store_func(buffer, offset + i * array_stride,
+ // value[i])
+ // }
+ // return arr;
+ // }
+ auto* array = b.Var(b.Symbols().New("array"), nullptr, b.Expr("value"));
+ auto store =
+ StoreFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
+ auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0_u));
+ auto* for_init = b.Decl(i);
+ auto* for_cond = b.create<ast::BinaryExpression>(
+ ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_ty->Count())));
+ auto* for_cont = b.Assign(i, b.Add(i, 1_u));
+ auto* arr_el = b.IndexAccessor(array, i);
+ auto* el_offset =
+ b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
+ auto* store_stmt =
+ b.CallStmt(b.Call(store, "buffer", el_offset, arr_el));
+ auto* for_loop =
+ b.For(for_init, for_cond, for_cont, b.Block(store_stmt));
+
+ return utils::Vector{b.Decl(array), for_loop};
+ },
+ [&](const sem::Matrix* mat_ty) {
+ auto* vec_ty = mat_ty->ColumnType();
+ Symbol store = StoreFunc(buf_ty, vec_ty, var_user);
+ utils::Vector<const ast::Statement*, 4> stmts;
+ for (uint32_t i = 0; i < mat_ty->columns(); i++) {
+ auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
+ auto* element = b.IndexAccessor("value", u32(i));
+ auto* call = b.Call(store, "buffer", offset, element);
+ stmts.Push(b.CallStmt(call));
+ }
+ return stmts;
+ },
+ [&](const sem::Struct* str) {
+ utils::Vector<const ast::Statement*, 8> stmts;
+ for (auto* member : str->Members()) {
+ auto* offset = b.Add("offset", u32(member->Offset()));
+ auto* element = b.MemberAccessor(
+ "value", ctx.Clone(member->Declaration()->symbol));
+ Symbol store =
+ StoreFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
+ auto* call = b.Call(store, "buffer", offset, element);
+ stmts.Push(b.CallStmt(call));
+ }
+ return stmts;
+ });
- auto name = b.Sym();
-
- if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, storage_class, el_ty)) {
- auto* func = b.create<ast::Function>(
- name, params, b.ty.void_(), nullptr,
- ast::AttributeList{
- intrinsic,
- b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
- },
- ast::AttributeList{});
- b.AST().AddFunction(func);
- } else {
- ast::StatementList body;
- if (auto* arr_ty = el_ty->As<sem::Array>()) {
- // fn store_func(buf : buf_ty, offset : u32, value : el_ty) {
- // var array = value; // No dynamic indexing on constant arrays
- // for (var i = 0u; i < array_count; i = i + 1) {
- // arr[i] = el_store_func(buf, offset + i * array_stride,
- // value[i])
- // }
- // return arr;
- // }
- auto* array = b.Var(b.Symbols().New("array"), nullptr, b.Expr("value"));
- auto store = StoreFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
- auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0_u));
- auto* for_init = b.Decl(i);
- auto* for_cond = b.create<ast::BinaryExpression>(
- ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_ty->Count())));
- auto* for_cont = b.Assign(i, b.Add(i, 1_u));
- auto* arr_el = b.IndexAccessor(array, i);
- auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
- auto* store_stmt = b.CallStmt(b.Call(store, "buffer", el_offset, arr_el));
- auto* for_loop = b.For(for_init, for_cond, for_cont, b.Block(store_stmt));
-
- body = {b.Decl(array), for_loop};
- } else if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
- auto* vec_ty = mat_ty->ColumnType();
- Symbol store = StoreFunc(buf_ty, vec_ty, var_user);
- for (uint32_t i = 0; i < mat_ty->columns(); i++) {
- auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
- auto* access = b.IndexAccessor("value", u32(i));
- auto* call = b.Call(store, "buffer", offset, access);
- body.emplace_back(b.CallStmt(call));
- }
- } else if (auto* str = el_ty->As<sem::Struct>()) {
- for (auto* member : str->Members()) {
- auto* offset = b.Add("offset", u32(member->Offset()));
- auto* access =
- b.MemberAccessor("value", ctx.Clone(member->Declaration()->symbol));
- Symbol store = StoreFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
- auto* call = b.Call(store, "buffer", offset, access);
- body.emplace_back(b.CallStmt(call));
- }
+ b.Func(name, params, b.ty.void_(), body);
}
- b.Func(name, params, b.ty.void_(), body);
- }
- return name;
- });
+ return name;
+ });
}
/// AtomicFunc() returns a symbol to an intrinsic function that performs an
/// atomic operation from a storage buffer of type `buf_ty`. The function has
/// the signature:
- // `fn atomic_op(buf : buf_ty, offset : u32, ...) -> T`
+ // `fn atomic_op(buf : ptr<storage, buf_ty, A>, offset : u32, ...) -> T`
/// @param buf_ty the storage buffer type
/// @param el_ty the storage buffer element type
/// @param intrinsic the atomic intrinsic
@@ -614,27 +622,23 @@ struct DecomposeMemoryAccess::State {
const sem::Builtin* intrinsic,
const sem::VariableUser* var_user) {
auto op = intrinsic->Type();
- return utils::GetOrCreate(atomic_funcs, AtomicKey{buf_ty, el_ty, op}, [&] {
- auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
- auto* disable_validation =
- b.Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
+ auto access = var_user->Variable()->Access();
+ return utils::GetOrCreate(atomic_funcs, AtomicKey{access, buf_ty, el_ty, op}, [&] {
// The first parameter to all WGSL atomics is the expression to the
// atomic. This is replaced with two parameters: the buffer and offset.
-
- ast::VariableList params = {
- // Note: The buffer parameter requires the kStorage StorageClass in
- // order for HLSL to emit this as a ByteAddressBuffer.
- b.create<ast::Variable>(b.Sym("buffer"), ast::StorageClass::kStorage,
- var_user->Variable()->Access(), buf_ast_ty, true, false,
- nullptr, ast::AttributeList{disable_validation}),
+ utils::Vector params{
+ b.Param("buffer",
+ b.ty.pointer(CreateASTTypeFor(ctx, buf_ty), ast::StorageClass::kStorage,
+ access),
+ utils::Vector{b.Disable(ast::DisabledValidation::kFunctionParameter)}),
b.Param("offset", b.ty.u32()),
};
// Other parameters are copied as-is:
- for (size_t i = 1; i < intrinsic->Parameters().size(); i++) {
+ for (size_t i = 1; i < intrinsic->Parameters().Length(); i++) {
auto* param = intrinsic->Parameters()[i];
auto* ty = CreateASTTypeFor(ctx, param->Type());
- params.emplace_back(b.Param("param_" + std::to_string(i), ty));
+ params.Push(b.Param("param_" + std::to_string(i), ty));
}
auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty);
@@ -651,10 +655,10 @@ struct DecomposeMemoryAccess::State {
auto* str = intrinsic->ReturnType()->As<sem::Struct>();
TINT_ASSERT(Transform, str && str->Declaration() == nullptr);
- ast::StructMemberList ast_members;
- ast_members.reserve(str->Members().size());
+ utils::Vector<const ast::StructMember*, 8> ast_members;
+ ast_members.Reserve(str->Members().size());
for (auto& m : str->Members()) {
- ast_members.push_back(
+ ast_members.Push(
b.Member(ctx.Clone(m->Name()), CreateASTTypeFor(ctx, m->Type())));
}
@@ -667,11 +671,11 @@ struct DecomposeMemoryAccess::State {
auto* func = b.create<ast::Function>(
b.Symbols().New(std::string{"tint_"} + intrinsic->str()), params, ret_ty, nullptr,
- ast::AttributeList{
+ utils::Vector{
atomic,
b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
},
- ast::AttributeList{});
+ utils::Empty);
b.AST().AddFunction(func);
return func->symbol;
@@ -679,8 +683,12 @@ struct DecomposeMemoryAccess::State {
}
};
-DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid, Op o, ast::StorageClass sc, DataType ty)
- : Base(pid), op(o), storage_class(sc), type(ty) {}
+DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid,
+ ast::NodeID nid,
+ Op o,
+ ast::StorageClass sc,
+ DataType ty)
+ : Base(pid, nid), op(o), storage_class(sc), type(ty) {}
DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
std::stringstream ss;
@@ -769,8 +777,8 @@ std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
const DecomposeMemoryAccess::Intrinsic* DecomposeMemoryAccess::Intrinsic::Clone(
CloneContext* ctx) const {
- return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(ctx->dst->ID(), op,
- storage_class, type);
+ return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
+ ctx->dst->ID(), ctx->dst->AllocateNodeID(), op, storage_class, type);
}
bool DecomposeMemoryAccess::Intrinsic::IsAtomic() const {
@@ -826,10 +834,10 @@ void DecomposeMemoryAccess::Run(CloneContext& ctx, const DataMap&, DataMap&) con
// X.Y
auto* accessor_sem = sem.Get(accessor);
if (auto* swizzle = accessor_sem->As<sem::Swizzle>()) {
- if (swizzle->Indices().size() == 1) {
+ if (swizzle->Indices().Length() == 1) {
if (auto access = state.TakeAccess(accessor->structure)) {
auto* vec_ty = access.type->As<sem::Vector>();
- auto* offset = state.Mul(vec_ty->type()->Size(), swizzle->Indices()[0]);
+ auto* offset = state.Mul(vec_ty->type()->Size(), swizzle->Indices()[0u]);
state.AddAccess(accessor, {
access.var,
state.Add(access.offset, offset),
@@ -910,8 +918,7 @@ void DecomposeMemoryAccess::Run(CloneContext& ctx, const DataMap&, DataMap&) con
if (auto* builtin = call->Target()->As<sem::Builtin>()) {
if (builtin->Type() == sem::BuiltinType::kArrayLength) {
// arrayLength(X)
- // Don't convert X into a load, this builtin actually requires the
- // real pointer.
+ // Don't convert X into a load, this builtin actually requires the real pointer.
state.TakeAccess(call_expr->args[0]);
continue;
}
@@ -926,10 +933,11 @@ void DecomposeMemoryAccess::Run(CloneContext& ctx, const DataMap&, DataMap&) con
Symbol func = state.AtomicFunc(buf_ty, el_ty, builtin,
access.var->As<sem::VariableUser>());
- ast::ExpressionList args{ctx.Clone(buf), offset};
- for (size_t i = 1; i < call_expr->args.size(); i++) {
+ utils::Vector<const ast::Expression*, 8> args{
+ ctx.dst->AddressOf(ctx.Clone(buf)), offset};
+ for (size_t i = 1; i < call_expr->args.Length(); i++) {
auto* arg = call_expr->args[i];
- args.emplace_back(ctx.Clone(arg));
+ args.Push(ctx.Clone(arg));
}
return ctx.dst->Call(func, args);
});
@@ -948,26 +956,26 @@ void DecomposeMemoryAccess::Run(CloneContext& ctx, const DataMap&, DataMap&) con
}
BufferAccess access = access_it->second;
ctx.Replace(expr, [=, &ctx, &state] {
- auto* buf = access.var->Declaration();
+ auto* buf = ctx.dst->AddressOf(ctx.CloneWithoutTransform(access.var->Declaration()));
auto* offset = access.offset->Build(ctx);
auto* buf_ty = access.var->Type()->UnwrapRef();
auto* el_ty = access.type->UnwrapRef();
Symbol func = state.LoadFunc(buf_ty, el_ty, access.var->As<sem::VariableUser>());
- return ctx.dst->Call(func, ctx.CloneWithoutTransform(buf), offset);
+ return ctx.dst->Call(func, buf, offset);
});
}
// And replace all storage and uniform buffer assignments with stores
for (auto store : state.stores) {
ctx.Replace(store.assignment, [=, &ctx, &state] {
- auto* buf = store.target.var->Declaration();
+ auto* buf =
+ ctx.dst->AddressOf(ctx.CloneWithoutTransform((store.target.var->Declaration())));
auto* offset = store.target.offset->Build(ctx);
auto* buf_ty = store.target.var->Type()->UnwrapRef();
auto* el_ty = store.target.type->UnwrapRef();
auto* value = store.assignment->rhs;
Symbol func = state.StoreFunc(buf_ty, el_ty, store.target.var->As<sem::VariableUser>());
- auto* call =
- ctx.dst->Call(func, ctx.CloneWithoutTransform(buf), offset, ctx.Clone(value));
+ auto* call = ctx.dst->Call(func, buf, offset, ctx.Clone(value));
return ctx.dst->CallStmt(call);
});
}
diff --git a/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.h b/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.h
index 76cb23e2ff3..1d95dc493dc 100644
--- a/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.h
+++ b/chromium/third_party/dawn/src/tint/transform/decompose_memory_access.h
@@ -72,11 +72,12 @@ class DecomposeMemoryAccess final : public Castable<DecomposeMemoryAccess, Trans
};
/// Constructor
- /// @param program_id the identifier of the program that owns this node
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
/// @param o the op of the intrinsic
/// @param sc the storage class of the buffer
/// @param ty the data type of the intrinsic
- Intrinsic(ProgramID program_id, Op o, ast::StorageClass sc, DataType ty);
+ Intrinsic(ProgramID pid, ast::NodeID nid, Op o, ast::StorageClass sc, DataType ty);
/// Destructor
~Intrinsic() override;
diff --git a/chromium/third_party/dawn/src/tint/transform/decompose_memory_access_test.cc b/chromium/third_party/dawn/src/tint/transform/decompose_memory_access_test.cc
index 4b96bcbb424..581731e1300 100644
--- a/chromium/third_party/dawn/src/tint/transform/decompose_memory_access_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/decompose_memory_access_test.cc
@@ -134,78 +134,78 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<i32>
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<u32>
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<f32>
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<i32>
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<u32>
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<f32>
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<i32>
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<u32>
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<f32>
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
}
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f32> {
return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f32> {
return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f32> {
return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f32> {
return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
var arr : array<vec3<f32>, 2u>;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
@@ -215,28 +215,28 @@ fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_pa
@compute @workgroup_size(1)
fn main() {
- var a : i32 = tint_symbol(sb, 0u);
- var b : u32 = tint_symbol_1(sb, 4u);
- var c : f32 = tint_symbol_2(sb, 8u);
- var d : vec2<i32> = tint_symbol_3(sb, 16u);
- var e : vec2<u32> = tint_symbol_4(sb, 24u);
- var f : vec2<f32> = tint_symbol_5(sb, 32u);
- var g : vec3<i32> = tint_symbol_6(sb, 48u);
- var h : vec3<u32> = tint_symbol_7(sb, 64u);
- var i : vec3<f32> = tint_symbol_8(sb, 80u);
- var j : vec4<i32> = tint_symbol_9(sb, 96u);
- var k : vec4<u32> = tint_symbol_10(sb, 112u);
- var l : vec4<f32> = tint_symbol_11(sb, 128u);
- var m : mat2x2<f32> = tint_symbol_12(sb, 144u);
- var n : mat2x3<f32> = tint_symbol_13(sb, 160u);
- var o : mat2x4<f32> = tint_symbol_14(sb, 192u);
- var p : mat3x2<f32> = tint_symbol_15(sb, 224u);
- var q : mat3x3<f32> = tint_symbol_16(sb, 256u);
- var r : mat3x4<f32> = tint_symbol_17(sb, 304u);
- var s : mat4x2<f32> = tint_symbol_18(sb, 352u);
- var t : mat4x3<f32> = tint_symbol_19(sb, 384u);
- var u : mat4x4<f32> = tint_symbol_20(sb, 448u);
- var v : array<vec3<f32>, 2> = tint_symbol_21(sb, 512u);
+ var a : i32 = tint_symbol(&(sb), 0u);
+ var b : u32 = tint_symbol_1(&(sb), 4u);
+ var c : f32 = tint_symbol_2(&(sb), 8u);
+ var d : vec2<i32> = tint_symbol_3(&(sb), 16u);
+ var e : vec2<u32> = tint_symbol_4(&(sb), 24u);
+ var f : vec2<f32> = tint_symbol_5(&(sb), 32u);
+ var g : vec3<i32> = tint_symbol_6(&(sb), 48u);
+ var h : vec3<u32> = tint_symbol_7(&(sb), 64u);
+ var i : vec3<f32> = tint_symbol_8(&(sb), 80u);
+ var j : vec4<i32> = tint_symbol_9(&(sb), 96u);
+ var k : vec4<u32> = tint_symbol_10(&(sb), 112u);
+ var l : vec4<f32> = tint_symbol_11(&(sb), 128u);
+ var m : mat2x2<f32> = tint_symbol_12(&(sb), 144u);
+ var n : mat2x3<f32> = tint_symbol_13(&(sb), 160u);
+ var o : mat2x4<f32> = tint_symbol_14(&(sb), 192u);
+ var p : mat3x2<f32> = tint_symbol_15(&(sb), 224u);
+ var q : mat3x3<f32> = tint_symbol_16(&(sb), 256u);
+ var r : mat3x4<f32> = tint_symbol_17(&(sb), 304u);
+ var s : mat4x2<f32> = tint_symbol_18(&(sb), 352u);
+ var t : mat4x3<f32> = tint_symbol_19(&(sb), 384u);
+ var u : mat4x4<f32> = tint_symbol_20(&(sb), 448u);
+ var v : array<vec3<f32>, 2> = tint_symbol_21(&(sb), 512u);
}
)";
@@ -303,78 +303,78 @@ struct SB {
auto* expect = R"(
@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<i32>
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<u32>
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<f32>
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<i32>
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<u32>
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<f32>
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<i32>
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<u32>
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<f32>
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
}
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f32> {
return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f32> {
return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f32> {
return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f32> {
return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
var arr : array<vec3<f32>, 2u>;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
@@ -384,28 +384,28 @@ fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_pa
@compute @workgroup_size(1)
fn main() {
- var a : i32 = tint_symbol(sb, 0u);
- var b : u32 = tint_symbol_1(sb, 4u);
- var c : f32 = tint_symbol_2(sb, 8u);
- var d : vec2<i32> = tint_symbol_3(sb, 16u);
- var e : vec2<u32> = tint_symbol_4(sb, 24u);
- var f : vec2<f32> = tint_symbol_5(sb, 32u);
- var g : vec3<i32> = tint_symbol_6(sb, 48u);
- var h : vec3<u32> = tint_symbol_7(sb, 64u);
- var i : vec3<f32> = tint_symbol_8(sb, 80u);
- var j : vec4<i32> = tint_symbol_9(sb, 96u);
- var k : vec4<u32> = tint_symbol_10(sb, 112u);
- var l : vec4<f32> = tint_symbol_11(sb, 128u);
- var m : mat2x2<f32> = tint_symbol_12(sb, 144u);
- var n : mat2x3<f32> = tint_symbol_13(sb, 160u);
- var o : mat2x4<f32> = tint_symbol_14(sb, 192u);
- var p : mat3x2<f32> = tint_symbol_15(sb, 224u);
- var q : mat3x3<f32> = tint_symbol_16(sb, 256u);
- var r : mat3x4<f32> = tint_symbol_17(sb, 304u);
- var s : mat4x2<f32> = tint_symbol_18(sb, 352u);
- var t : mat4x3<f32> = tint_symbol_19(sb, 384u);
- var u : mat4x4<f32> = tint_symbol_20(sb, 448u);
- var v : array<vec3<f32>, 2> = tint_symbol_21(sb, 512u);
+ var a : i32 = tint_symbol(&(sb), 0u);
+ var b : u32 = tint_symbol_1(&(sb), 4u);
+ var c : f32 = tint_symbol_2(&(sb), 8u);
+ var d : vec2<i32> = tint_symbol_3(&(sb), 16u);
+ var e : vec2<u32> = tint_symbol_4(&(sb), 24u);
+ var f : vec2<f32> = tint_symbol_5(&(sb), 32u);
+ var g : vec3<i32> = tint_symbol_6(&(sb), 48u);
+ var h : vec3<u32> = tint_symbol_7(&(sb), 64u);
+ var i : vec3<f32> = tint_symbol_8(&(sb), 80u);
+ var j : vec4<i32> = tint_symbol_9(&(sb), 96u);
+ var k : vec4<u32> = tint_symbol_10(&(sb), 112u);
+ var l : vec4<f32> = tint_symbol_11(&(sb), 128u);
+ var m : mat2x2<f32> = tint_symbol_12(&(sb), 144u);
+ var n : mat2x3<f32> = tint_symbol_13(&(sb), 160u);
+ var o : mat2x4<f32> = tint_symbol_14(&(sb), 192u);
+ var p : mat3x2<f32> = tint_symbol_15(&(sb), 224u);
+ var q : mat3x3<f32> = tint_symbol_16(&(sb), 256u);
+ var r : mat3x4<f32> = tint_symbol_17(&(sb), 304u);
+ var s : mat4x2<f32> = tint_symbol_18(&(sb), 352u);
+ var t : mat4x3<f32> = tint_symbol_19(&(sb), 384u);
+ var u : mat4x4<f32> = tint_symbol_20(&(sb), 448u);
+ var v : array<vec3<f32>, 2> = tint_symbol_21(&(sb), 512u);
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -526,78 +526,78 @@ struct UB {
@group(0) @binding(0) var<uniform> ub : UB;
@internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> i32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> i32
@internal(intrinsic_load_uniform_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> u32
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> u32
@internal(intrinsic_load_uniform_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> f32
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> f32
@internal(intrinsic_load_uniform_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<i32>
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec2<i32>
@internal(intrinsic_load_uniform_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<u32>
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec2<u32>
@internal(intrinsic_load_uniform_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<f32>
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec2<f32>
@internal(intrinsic_load_uniform_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<i32>
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec3<i32>
@internal(intrinsic_load_uniform_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<u32>
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec3<u32>
@internal(intrinsic_load_uniform_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<f32>
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec3<f32>
@internal(intrinsic_load_uniform_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<i32>
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec4<i32>
@internal(intrinsic_load_uniform_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<u32>
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec4<u32>
@internal(intrinsic_load_uniform_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<f32>
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec4<f32>
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat2x2<f32> {
return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
}
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat2x3<f32> {
return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat2x4<f32> {
return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat3x2<f32> {
return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat3x3<f32> {
return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat3x4<f32> {
return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat4x2<f32> {
return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat4x3<f32> {
return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat4x4<f32> {
return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> array<vec3<f32>, 2u> {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> array<vec3<f32>, 2u> {
var arr : array<vec3<f32>, 2u>;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
@@ -607,28 +607,28 @@ fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_pa
@compute @workgroup_size(1)
fn main() {
- var a : i32 = tint_symbol(ub, 0u);
- var b : u32 = tint_symbol_1(ub, 4u);
- var c : f32 = tint_symbol_2(ub, 8u);
- var d : vec2<i32> = tint_symbol_3(ub, 16u);
- var e : vec2<u32> = tint_symbol_4(ub, 24u);
- var f : vec2<f32> = tint_symbol_5(ub, 32u);
- var g : vec3<i32> = tint_symbol_6(ub, 48u);
- var h : vec3<u32> = tint_symbol_7(ub, 64u);
- var i : vec3<f32> = tint_symbol_8(ub, 80u);
- var j : vec4<i32> = tint_symbol_9(ub, 96u);
- var k : vec4<u32> = tint_symbol_10(ub, 112u);
- var l : vec4<f32> = tint_symbol_11(ub, 128u);
- var m : mat2x2<f32> = tint_symbol_12(ub, 144u);
- var n : mat2x3<f32> = tint_symbol_13(ub, 160u);
- var o : mat2x4<f32> = tint_symbol_14(ub, 192u);
- var p : mat3x2<f32> = tint_symbol_15(ub, 224u);
- var q : mat3x3<f32> = tint_symbol_16(ub, 256u);
- var r : mat3x4<f32> = tint_symbol_17(ub, 304u);
- var s : mat4x2<f32> = tint_symbol_18(ub, 352u);
- var t : mat4x3<f32> = tint_symbol_19(ub, 384u);
- var u : mat4x4<f32> = tint_symbol_20(ub, 448u);
- var v : array<vec3<f32>, 2> = tint_symbol_21(ub, 512u);
+ var a : i32 = tint_symbol(&(ub), 0u);
+ var b : u32 = tint_symbol_1(&(ub), 4u);
+ var c : f32 = tint_symbol_2(&(ub), 8u);
+ var d : vec2<i32> = tint_symbol_3(&(ub), 16u);
+ var e : vec2<u32> = tint_symbol_4(&(ub), 24u);
+ var f : vec2<f32> = tint_symbol_5(&(ub), 32u);
+ var g : vec3<i32> = tint_symbol_6(&(ub), 48u);
+ var h : vec3<u32> = tint_symbol_7(&(ub), 64u);
+ var i : vec3<f32> = tint_symbol_8(&(ub), 80u);
+ var j : vec4<i32> = tint_symbol_9(&(ub), 96u);
+ var k : vec4<u32> = tint_symbol_10(&(ub), 112u);
+ var l : vec4<f32> = tint_symbol_11(&(ub), 128u);
+ var m : mat2x2<f32> = tint_symbol_12(&(ub), 144u);
+ var n : mat2x3<f32> = tint_symbol_13(&(ub), 160u);
+ var o : mat2x4<f32> = tint_symbol_14(&(ub), 192u);
+ var p : mat3x2<f32> = tint_symbol_15(&(ub), 224u);
+ var q : mat3x3<f32> = tint_symbol_16(&(ub), 256u);
+ var r : mat3x4<f32> = tint_symbol_17(&(ub), 304u);
+ var s : mat4x2<f32> = tint_symbol_18(&(ub), 352u);
+ var t : mat4x3<f32> = tint_symbol_19(&(ub), 384u);
+ var u : mat4x4<f32> = tint_symbol_20(&(ub), 448u);
+ var v : array<vec3<f32>, 2> = tint_symbol_21(&(ub), 512u);
}
)";
@@ -695,78 +695,78 @@ struct UB {
auto* expect = R"(
@internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> i32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> i32
@internal(intrinsic_load_uniform_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> u32
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> u32
@internal(intrinsic_load_uniform_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> f32
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> f32
@internal(intrinsic_load_uniform_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<i32>
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec2<i32>
@internal(intrinsic_load_uniform_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<u32>
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec2<u32>
@internal(intrinsic_load_uniform_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<f32>
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec2<f32>
@internal(intrinsic_load_uniform_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<i32>
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec3<i32>
@internal(intrinsic_load_uniform_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<u32>
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec3<u32>
@internal(intrinsic_load_uniform_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<f32>
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec3<f32>
@internal(intrinsic_load_uniform_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<i32>
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec4<i32>
@internal(intrinsic_load_uniform_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<u32>
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec4<u32>
@internal(intrinsic_load_uniform_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<f32>
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> vec4<f32>
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat2x2<f32> {
return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
}
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat2x3<f32> {
return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat2x4<f32> {
return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat3x2<f32> {
return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat3x3<f32> {
return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat3x4<f32> {
return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat4x2<f32> {
return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat4x3<f32> {
return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> mat4x4<f32> {
return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> array<vec3<f32>, 2u> {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB, read>, offset : u32) -> array<vec3<f32>, 2u> {
var arr : array<vec3<f32>, 2u>;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
@@ -776,28 +776,28 @@ fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_pa
@compute @workgroup_size(1)
fn main() {
- var a : i32 = tint_symbol(ub, 0u);
- var b : u32 = tint_symbol_1(ub, 4u);
- var c : f32 = tint_symbol_2(ub, 8u);
- var d : vec2<i32> = tint_symbol_3(ub, 16u);
- var e : vec2<u32> = tint_symbol_4(ub, 24u);
- var f : vec2<f32> = tint_symbol_5(ub, 32u);
- var g : vec3<i32> = tint_symbol_6(ub, 48u);
- var h : vec3<u32> = tint_symbol_7(ub, 64u);
- var i : vec3<f32> = tint_symbol_8(ub, 80u);
- var j : vec4<i32> = tint_symbol_9(ub, 96u);
- var k : vec4<u32> = tint_symbol_10(ub, 112u);
- var l : vec4<f32> = tint_symbol_11(ub, 128u);
- var m : mat2x2<f32> = tint_symbol_12(ub, 144u);
- var n : mat2x3<f32> = tint_symbol_13(ub, 160u);
- var o : mat2x4<f32> = tint_symbol_14(ub, 192u);
- var p : mat3x2<f32> = tint_symbol_15(ub, 224u);
- var q : mat3x3<f32> = tint_symbol_16(ub, 256u);
- var r : mat3x4<f32> = tint_symbol_17(ub, 304u);
- var s : mat4x2<f32> = tint_symbol_18(ub, 352u);
- var t : mat4x3<f32> = tint_symbol_19(ub, 384u);
- var u : mat4x4<f32> = tint_symbol_20(ub, 448u);
- var v : array<vec3<f32>, 2> = tint_symbol_21(ub, 512u);
+ var a : i32 = tint_symbol(&(ub), 0u);
+ var b : u32 = tint_symbol_1(&(ub), 4u);
+ var c : f32 = tint_symbol_2(&(ub), 8u);
+ var d : vec2<i32> = tint_symbol_3(&(ub), 16u);
+ var e : vec2<u32> = tint_symbol_4(&(ub), 24u);
+ var f : vec2<f32> = tint_symbol_5(&(ub), 32u);
+ var g : vec3<i32> = tint_symbol_6(&(ub), 48u);
+ var h : vec3<u32> = tint_symbol_7(&(ub), 64u);
+ var i : vec3<f32> = tint_symbol_8(&(ub), 80u);
+ var j : vec4<i32> = tint_symbol_9(&(ub), 96u);
+ var k : vec4<u32> = tint_symbol_10(&(ub), 112u);
+ var l : vec4<f32> = tint_symbol_11(&(ub), 128u);
+ var m : mat2x2<f32> = tint_symbol_12(&(ub), 144u);
+ var n : mat2x3<f32> = tint_symbol_13(&(ub), 160u);
+ var o : mat2x4<f32> = tint_symbol_14(&(ub), 192u);
+ var p : mat3x2<f32> = tint_symbol_15(&(ub), 224u);
+ var q : mat3x3<f32> = tint_symbol_16(&(ub), 256u);
+ var r : mat3x4<f32> = tint_symbol_17(&(ub), 304u);
+ var s : mat4x2<f32> = tint_symbol_18(&(ub), 352u);
+ var t : mat4x3<f32> = tint_symbol_19(&(ub), 384u);
+ var u : mat4x4<f32> = tint_symbol_20(&(ub), 448u);
+ var v : array<vec3<f32>, 2> = tint_symbol_21(&(ub), 512u);
}
@group(0) @binding(0) var<uniform> ub : UB;
@@ -918,96 +918,96 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : u32)
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : f32)
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<i32>)
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<u32>)
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<f32>)
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<i32>)
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<u32>)
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<f32>)
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<i32>)
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<u32>)
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<f32>)
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x2<f32>) {
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
tint_symbol_5(buffer, (offset + 0u), value[0u]);
tint_symbol_5(buffer, (offset + 8u), value[1u]);
}
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x3<f32>) {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
tint_symbol_8(buffer, (offset + 0u), value[0u]);
tint_symbol_8(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x4<f32>) {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
tint_symbol_11(buffer, (offset + 0u), value[0u]);
tint_symbol_11(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x2<f32>) {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f32>) {
tint_symbol_5(buffer, (offset + 0u), value[0u]);
tint_symbol_5(buffer, (offset + 8u), value[1u]);
tint_symbol_5(buffer, (offset + 16u), value[2u]);
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x3<f32>) {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f32>) {
tint_symbol_8(buffer, (offset + 0u), value[0u]);
tint_symbol_8(buffer, (offset + 16u), value[1u]);
tint_symbol_8(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x4<f32>) {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
tint_symbol_11(buffer, (offset + 0u), value[0u]);
tint_symbol_11(buffer, (offset + 16u), value[1u]);
tint_symbol_11(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x2<f32>) {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f32>) {
tint_symbol_5(buffer, (offset + 0u), value[0u]);
tint_symbol_5(buffer, (offset + 8u), value[1u]);
tint_symbol_5(buffer, (offset + 16u), value[2u]);
tint_symbol_5(buffer, (offset + 24u), value[3u]);
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x3<f32>) {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f32>) {
tint_symbol_8(buffer, (offset + 0u), value[0u]);
tint_symbol_8(buffer, (offset + 16u), value[1u]);
tint_symbol_8(buffer, (offset + 32u), value[2u]);
tint_symbol_8(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x4<f32>) {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
tint_symbol_11(buffer, (offset + 0u), value[0u]);
tint_symbol_11(buffer, (offset + 16u), value[1u]);
tint_symbol_11(buffer, (offset + 32u), value[2u]);
tint_symbol_11(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
var array = value;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
tint_symbol_8(buffer, (offset + (i_1 * 16u)), array[i_1]);
@@ -1016,28 +1016,28 @@ fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_pa
@compute @workgroup_size(1)
fn main() {
- tint_symbol(sb, 0u, i32());
- tint_symbol_1(sb, 4u, u32());
- tint_symbol_2(sb, 8u, f32());
- tint_symbol_3(sb, 16u, vec2<i32>());
- tint_symbol_4(sb, 24u, vec2<u32>());
- tint_symbol_5(sb, 32u, vec2<f32>());
- tint_symbol_6(sb, 48u, vec3<i32>());
- tint_symbol_7(sb, 64u, vec3<u32>());
- tint_symbol_8(sb, 80u, vec3<f32>());
- tint_symbol_9(sb, 96u, vec4<i32>());
- tint_symbol_10(sb, 112u, vec4<u32>());
- tint_symbol_11(sb, 128u, vec4<f32>());
- tint_symbol_12(sb, 144u, mat2x2<f32>());
- tint_symbol_13(sb, 160u, mat2x3<f32>());
- tint_symbol_14(sb, 192u, mat2x4<f32>());
- tint_symbol_15(sb, 224u, mat3x2<f32>());
- tint_symbol_16(sb, 256u, mat3x3<f32>());
- tint_symbol_17(sb, 304u, mat3x4<f32>());
- tint_symbol_18(sb, 352u, mat4x2<f32>());
- tint_symbol_19(sb, 384u, mat4x3<f32>());
- tint_symbol_20(sb, 448u, mat4x4<f32>());
- tint_symbol_21(sb, 512u, array<vec3<f32>, 2>());
+ tint_symbol(&(sb), 0u, i32());
+ tint_symbol_1(&(sb), 4u, u32());
+ tint_symbol_2(&(sb), 8u, f32());
+ tint_symbol_3(&(sb), 16u, vec2<i32>());
+ tint_symbol_4(&(sb), 24u, vec2<u32>());
+ tint_symbol_5(&(sb), 32u, vec2<f32>());
+ tint_symbol_6(&(sb), 48u, vec3<i32>());
+ tint_symbol_7(&(sb), 64u, vec3<u32>());
+ tint_symbol_8(&(sb), 80u, vec3<f32>());
+ tint_symbol_9(&(sb), 96u, vec4<i32>());
+ tint_symbol_10(&(sb), 112u, vec4<u32>());
+ tint_symbol_11(&(sb), 128u, vec4<f32>());
+ tint_symbol_12(&(sb), 144u, mat2x2<f32>());
+ tint_symbol_13(&(sb), 160u, mat2x3<f32>());
+ tint_symbol_14(&(sb), 192u, mat2x4<f32>());
+ tint_symbol_15(&(sb), 224u, mat3x2<f32>());
+ tint_symbol_16(&(sb), 256u, mat3x3<f32>());
+ tint_symbol_17(&(sb), 304u, mat3x4<f32>());
+ tint_symbol_18(&(sb), 352u, mat4x2<f32>());
+ tint_symbol_19(&(sb), 384u, mat4x3<f32>());
+ tint_symbol_20(&(sb), 448u, mat4x4<f32>());
+ tint_symbol_21(&(sb), 512u, array<vec3<f32>, 2>());
}
)";
@@ -1104,96 +1104,96 @@ struct SB {
auto* expect = R"(
@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : u32)
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : f32)
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<i32>)
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<u32>)
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<f32>)
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<i32>)
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<u32>)
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<f32>)
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<i32>)
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<u32>)
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<f32>)
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x2<f32>) {
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
tint_symbol_5(buffer, (offset + 0u), value[0u]);
tint_symbol_5(buffer, (offset + 8u), value[1u]);
}
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x3<f32>) {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
tint_symbol_8(buffer, (offset + 0u), value[0u]);
tint_symbol_8(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x4<f32>) {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
tint_symbol_11(buffer, (offset + 0u), value[0u]);
tint_symbol_11(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x2<f32>) {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f32>) {
tint_symbol_5(buffer, (offset + 0u), value[0u]);
tint_symbol_5(buffer, (offset + 8u), value[1u]);
tint_symbol_5(buffer, (offset + 16u), value[2u]);
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x3<f32>) {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f32>) {
tint_symbol_8(buffer, (offset + 0u), value[0u]);
tint_symbol_8(buffer, (offset + 16u), value[1u]);
tint_symbol_8(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x4<f32>) {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
tint_symbol_11(buffer, (offset + 0u), value[0u]);
tint_symbol_11(buffer, (offset + 16u), value[1u]);
tint_symbol_11(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x2<f32>) {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f32>) {
tint_symbol_5(buffer, (offset + 0u), value[0u]);
tint_symbol_5(buffer, (offset + 8u), value[1u]);
tint_symbol_5(buffer, (offset + 16u), value[2u]);
tint_symbol_5(buffer, (offset + 24u), value[3u]);
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x3<f32>) {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f32>) {
tint_symbol_8(buffer, (offset + 0u), value[0u]);
tint_symbol_8(buffer, (offset + 16u), value[1u]);
tint_symbol_8(buffer, (offset + 32u), value[2u]);
tint_symbol_8(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x4<f32>) {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
tint_symbol_11(buffer, (offset + 0u), value[0u]);
tint_symbol_11(buffer, (offset + 16u), value[1u]);
tint_symbol_11(buffer, (offset + 32u), value[2u]);
tint_symbol_11(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
var array = value;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
tint_symbol_8(buffer, (offset + (i_1 * 16u)), array[i_1]);
@@ -1202,28 +1202,28 @@ fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_pa
@compute @workgroup_size(1)
fn main() {
- tint_symbol(sb, 0u, i32());
- tint_symbol_1(sb, 4u, u32());
- tint_symbol_2(sb, 8u, f32());
- tint_symbol_3(sb, 16u, vec2<i32>());
- tint_symbol_4(sb, 24u, vec2<u32>());
- tint_symbol_5(sb, 32u, vec2<f32>());
- tint_symbol_6(sb, 48u, vec3<i32>());
- tint_symbol_7(sb, 64u, vec3<u32>());
- tint_symbol_8(sb, 80u, vec3<f32>());
- tint_symbol_9(sb, 96u, vec4<i32>());
- tint_symbol_10(sb, 112u, vec4<u32>());
- tint_symbol_11(sb, 128u, vec4<f32>());
- tint_symbol_12(sb, 144u, mat2x2<f32>());
- tint_symbol_13(sb, 160u, mat2x3<f32>());
- tint_symbol_14(sb, 192u, mat2x4<f32>());
- tint_symbol_15(sb, 224u, mat3x2<f32>());
- tint_symbol_16(sb, 256u, mat3x3<f32>());
- tint_symbol_17(sb, 304u, mat3x4<f32>());
- tint_symbol_18(sb, 352u, mat4x2<f32>());
- tint_symbol_19(sb, 384u, mat4x3<f32>());
- tint_symbol_20(sb, 448u, mat4x4<f32>());
- tint_symbol_21(sb, 512u, array<vec3<f32>, 2>());
+ tint_symbol(&(sb), 0u, i32());
+ tint_symbol_1(&(sb), 4u, u32());
+ tint_symbol_2(&(sb), 8u, f32());
+ tint_symbol_3(&(sb), 16u, vec2<i32>());
+ tint_symbol_4(&(sb), 24u, vec2<u32>());
+ tint_symbol_5(&(sb), 32u, vec2<f32>());
+ tint_symbol_6(&(sb), 48u, vec3<i32>());
+ tint_symbol_7(&(sb), 64u, vec3<u32>());
+ tint_symbol_8(&(sb), 80u, vec3<f32>());
+ tint_symbol_9(&(sb), 96u, vec4<i32>());
+ tint_symbol_10(&(sb), 112u, vec4<u32>());
+ tint_symbol_11(&(sb), 128u, vec4<f32>());
+ tint_symbol_12(&(sb), 144u, mat2x2<f32>());
+ tint_symbol_13(&(sb), 160u, mat2x3<f32>());
+ tint_symbol_14(&(sb), 192u, mat2x4<f32>());
+ tint_symbol_15(&(sb), 224u, mat3x2<f32>());
+ tint_symbol_16(&(sb), 256u, mat3x3<f32>());
+ tint_symbol_17(&(sb), 304u, mat3x4<f32>());
+ tint_symbol_18(&(sb), 352u, mat4x2<f32>());
+ tint_symbol_19(&(sb), 384u, mat4x3<f32>());
+ tint_symbol_20(&(sb), 448u, mat4x4<f32>());
+ tint_symbol_21(&(sb), 512u, array<vec3<f32>, 2>());
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -1323,78 +1323,78 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<i32>
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<u32>
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<f32>
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<i32>
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<u32>
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<f32>
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<i32>
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<u32>
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<f32>
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
return mat2x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)));
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
return mat2x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)));
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
return mat2x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)));
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f32> {
return mat3x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)), tint_symbol_6(buffer, (offset + 16u)));
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f32> {
return mat3x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)));
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
return mat3x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)));
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f32> {
return mat4x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)), tint_symbol_6(buffer, (offset + 16u)), tint_symbol_6(buffer, (offset + 24u)));
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f32> {
return mat4x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)), tint_symbol_9(buffer, (offset + 48u)));
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
}
-fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
+fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
var arr : array<vec3<f32>, 2u>;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
arr[i_1] = tint_symbol_9(buffer, (offset + (i_1 * 16u)));
@@ -1402,13 +1402,13 @@ fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_pa
return arr;
}
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> SB {
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> SB {
return SB(tint_symbol_1(buffer, (offset + 0u)), tint_symbol_2(buffer, (offset + 4u)), tint_symbol_3(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)), tint_symbol_6(buffer, (offset + 32u)), tint_symbol_7(buffer, (offset + 48u)), tint_symbol_8(buffer, (offset + 64u)), tint_symbol_9(buffer, (offset + 80u)), tint_symbol_10(buffer, (offset + 96u)), tint_symbol_11(buffer, (offset + 112u)), tint_symbol_12(buffer, (offset + 128u)), tint_symbol_13(buffer, (offset + 144u)), tint_symbol_14(buffer, (offset + 160u)), tint_symbol_15(buffer, (offset + 192u)), tint_symbol_16(buffer, (offset + 224u)), tint_symbol_17(buffer, (offset + 256u)), tint_symbol_18(buffer, (offset + 304u)), tint_symbol_19(buffer, (offset + 352u)), tint_symbol_20(buffer, (offset + 384u)), tint_symbol_21(buffer, (offset + 448u)), tint_symbol_22(buffer, (offset + 512u)));
}
@compute @workgroup_size(1)
fn main() {
- var x : SB = tint_symbol(sb, 0u);
+ var x : SB = tint_symbol(&(sb), 0u);
}
)";
@@ -1454,78 +1454,78 @@ struct SB {
auto* expect = R"(
@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<i32>
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<u32>
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<f32>
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<i32>
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<u32>
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<f32>
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<i32>
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<u32>
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<f32>
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
return mat2x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)));
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
return mat2x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)));
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
return mat2x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)));
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f32> {
return mat3x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)), tint_symbol_6(buffer, (offset + 16u)));
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f32> {
return mat3x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)));
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
return mat3x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)));
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f32> {
return mat4x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)), tint_symbol_6(buffer, (offset + 16u)), tint_symbol_6(buffer, (offset + 24u)));
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f32> {
return mat4x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)), tint_symbol_9(buffer, (offset + 48u)));
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
}
-fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
+fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
var arr : array<vec3<f32>, 2u>;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
arr[i_1] = tint_symbol_9(buffer, (offset + (i_1 * 16u)));
@@ -1533,13 +1533,13 @@ fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_pa
return arr;
}
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> SB {
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> SB {
return SB(tint_symbol_1(buffer, (offset + 0u)), tint_symbol_2(buffer, (offset + 4u)), tint_symbol_3(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)), tint_symbol_6(buffer, (offset + 32u)), tint_symbol_7(buffer, (offset + 48u)), tint_symbol_8(buffer, (offset + 64u)), tint_symbol_9(buffer, (offset + 80u)), tint_symbol_10(buffer, (offset + 96u)), tint_symbol_11(buffer, (offset + 112u)), tint_symbol_12(buffer, (offset + 128u)), tint_symbol_13(buffer, (offset + 144u)), tint_symbol_14(buffer, (offset + 160u)), tint_symbol_15(buffer, (offset + 192u)), tint_symbol_16(buffer, (offset + 224u)), tint_symbol_17(buffer, (offset + 256u)), tint_symbol_18(buffer, (offset + 304u)), tint_symbol_19(buffer, (offset + 352u)), tint_symbol_20(buffer, (offset + 384u)), tint_symbol_21(buffer, (offset + 448u)), tint_symbol_22(buffer, (offset + 512u)));
}
@compute @workgroup_size(1)
fn main() {
- var x : SB = tint_symbol(sb, 0u);
+ var x : SB = tint_symbol(&(sb), 0u);
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -1639,103 +1639,103 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : u32)
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : f32)
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<i32>)
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<u32>)
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<f32>)
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<i32>)
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<u32>)
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<f32>)
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<i32>)
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<u32>)
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<f32>)
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x2<f32>) {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
tint_symbol_6(buffer, (offset + 0u), value[0u]);
tint_symbol_6(buffer, (offset + 8u), value[1u]);
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x3<f32>) {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
tint_symbol_9(buffer, (offset + 0u), value[0u]);
tint_symbol_9(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x4<f32>) {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
tint_symbol_12(buffer, (offset + 0u), value[0u]);
tint_symbol_12(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x2<f32>) {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f32>) {
tint_symbol_6(buffer, (offset + 0u), value[0u]);
tint_symbol_6(buffer, (offset + 8u), value[1u]);
tint_symbol_6(buffer, (offset + 16u), value[2u]);
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x3<f32>) {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f32>) {
tint_symbol_9(buffer, (offset + 0u), value[0u]);
tint_symbol_9(buffer, (offset + 16u), value[1u]);
tint_symbol_9(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x4<f32>) {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
tint_symbol_12(buffer, (offset + 0u), value[0u]);
tint_symbol_12(buffer, (offset + 16u), value[1u]);
tint_symbol_12(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x2<f32>) {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f32>) {
tint_symbol_6(buffer, (offset + 0u), value[0u]);
tint_symbol_6(buffer, (offset + 8u), value[1u]);
tint_symbol_6(buffer, (offset + 16u), value[2u]);
tint_symbol_6(buffer, (offset + 24u), value[3u]);
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x3<f32>) {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f32>) {
tint_symbol_9(buffer, (offset + 0u), value[0u]);
tint_symbol_9(buffer, (offset + 16u), value[1u]);
tint_symbol_9(buffer, (offset + 32u), value[2u]);
tint_symbol_9(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x4<f32>) {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
tint_symbol_12(buffer, (offset + 0u), value[0u]);
tint_symbol_12(buffer, (offset + 16u), value[1u]);
tint_symbol_12(buffer, (offset + 32u), value[2u]);
tint_symbol_12(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
+fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
var array = value;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
tint_symbol_9(buffer, (offset + (i_1 * 16u)), array[i_1]);
}
}
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : SB) {
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : SB) {
tint_symbol_1(buffer, (offset + 0u), value.a);
tint_symbol_2(buffer, (offset + 4u), value.b);
tint_symbol_3(buffer, (offset + 8u), value.c);
@@ -1762,7 +1762,7 @@ fn tint_symbol(@internal(disable_validation__ignore_constructible_function_param
@compute @workgroup_size(1)
fn main() {
- tint_symbol(sb, 0u, SB());
+ tint_symbol(&(sb), 0u, SB());
}
)";
@@ -1808,103 +1808,103 @@ struct SB {
auto* expect = R"(
@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
+fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : u32)
+fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : f32)
+fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<i32>)
+fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<u32>)
+fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<f32>)
+fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<i32>)
+fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<u32>)
+fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<f32>)
+fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<i32>)
+fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<u32>)
+fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<f32>)
+fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
-fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x2<f32>) {
+fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
tint_symbol_6(buffer, (offset + 0u), value[0u]);
tint_symbol_6(buffer, (offset + 8u), value[1u]);
}
-fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x3<f32>) {
+fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
tint_symbol_9(buffer, (offset + 0u), value[0u]);
tint_symbol_9(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x4<f32>) {
+fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
tint_symbol_12(buffer, (offset + 0u), value[0u]);
tint_symbol_12(buffer, (offset + 16u), value[1u]);
}
-fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x2<f32>) {
+fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f32>) {
tint_symbol_6(buffer, (offset + 0u), value[0u]);
tint_symbol_6(buffer, (offset + 8u), value[1u]);
tint_symbol_6(buffer, (offset + 16u), value[2u]);
}
-fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x3<f32>) {
+fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f32>) {
tint_symbol_9(buffer, (offset + 0u), value[0u]);
tint_symbol_9(buffer, (offset + 16u), value[1u]);
tint_symbol_9(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x4<f32>) {
+fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
tint_symbol_12(buffer, (offset + 0u), value[0u]);
tint_symbol_12(buffer, (offset + 16u), value[1u]);
tint_symbol_12(buffer, (offset + 32u), value[2u]);
}
-fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x2<f32>) {
+fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f32>) {
tint_symbol_6(buffer, (offset + 0u), value[0u]);
tint_symbol_6(buffer, (offset + 8u), value[1u]);
tint_symbol_6(buffer, (offset + 16u), value[2u]);
tint_symbol_6(buffer, (offset + 24u), value[3u]);
}
-fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x3<f32>) {
+fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f32>) {
tint_symbol_9(buffer, (offset + 0u), value[0u]);
tint_symbol_9(buffer, (offset + 16u), value[1u]);
tint_symbol_9(buffer, (offset + 32u), value[2u]);
tint_symbol_9(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x4<f32>) {
+fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
tint_symbol_12(buffer, (offset + 0u), value[0u]);
tint_symbol_12(buffer, (offset + 16u), value[1u]);
tint_symbol_12(buffer, (offset + 32u), value[2u]);
tint_symbol_12(buffer, (offset + 48u), value[3u]);
}
-fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
+fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
var array = value;
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
tint_symbol_9(buffer, (offset + (i_1 * 16u)), array[i_1]);
}
}
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : SB) {
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : SB) {
tint_symbol_1(buffer, (offset + 0u), value.a);
tint_symbol_2(buffer, (offset + 4u), value.b);
tint_symbol_3(buffer, (offset + 8u), value.c);
@@ -1931,7 +1931,7 @@ fn tint_symbol(@internal(disable_validation__ignore_constructible_function_param
@compute @workgroup_size(1)
fn main() {
- tint_symbol(sb, 0u, SB());
+ tint_symbol(&(sb), 0u, SB());
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -2028,11 +2028,11 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@compute @workgroup_size(1)
fn main() {
- var x : f32 = tint_symbol(sb, 712u);
+ var x : f32 = tint_symbol(&(sb), 712u);
}
)";
@@ -2078,11 +2078,11 @@ struct S1 {
auto* expect = R"(
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@compute @workgroup_size(1)
fn main() {
- var x : f32 = tint_symbol(sb, 712u);
+ var x : f32 = tint_symbol(&(sb), 712u);
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -2164,14 +2164,14 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@compute @workgroup_size(1)
fn main() {
var i : i32 = 4;
var j : u32 = 1u;
var k : i32 = 2;
- var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+ var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
}
)";
@@ -2213,14 +2213,14 @@ struct S1 {
auto* expect = R"(
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@compute @workgroup_size(1)
fn main() {
var i : i32 = 4;
var j : u32 = 1u;
var k : i32 = 2;
- var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+ var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -2318,14 +2318,14 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@compute @workgroup_size(1)
fn main() {
var i : i32 = 4;
var j : u32 = 1u;
var k : i32 = 2;
- var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+ var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
}
)";
@@ -2375,14 +2375,14 @@ struct S1 {
auto* expect = R"(
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
@compute @workgroup_size(1)
fn main() {
var i : i32 = 4;
var j : u32 = 1u;
var k : i32 = 2;
- var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+ var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -2467,34 +2467,34 @@ struct SB {
@group(0) @binding(0) var<storage, read_write> sb : SB;
@internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32)
+fn tint_atomicStore(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32)
@internal(intrinsic_atomic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+fn tint_atomicLoad(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
@internal(intrinsic_atomic_add_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicAdd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_sub_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicSub(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_max_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicMax(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_min_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicMin(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_and_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicAnd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_or_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicOr(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_xor_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicXor(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_exchange_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicExchange(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
struct atomic_compare_exchange_weak_ret_type {
old_value : i32,
@@ -2502,37 +2502,37 @@ struct atomic_compare_exchange_weak_ret_type {
}
@internal(intrinsic_atomic_compare_exchange_weak_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
+fn tint_atomicCompareExchangeWeak(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
@internal(intrinsic_atomic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32)
+fn tint_atomicStore_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32)
@internal(intrinsic_atomic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+fn tint_atomicLoad_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
@internal(intrinsic_atomic_add_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicAdd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_sub_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicSub_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_max_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicMax_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_min_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicMin_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_and_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicAnd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_or_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicOr_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_xor_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicXor_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_exchange_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicExchange_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
struct atomic_compare_exchange_weak_ret_type_1 {
old_value : u32,
@@ -2540,32 +2540,32 @@ struct atomic_compare_exchange_weak_ret_type_1 {
}
@internal(intrinsic_atomic_compare_exchange_weak_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
+fn tint_atomicCompareExchangeWeak_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
@compute @workgroup_size(1)
fn main() {
- tint_atomicStore(sb, 16u, 123);
- tint_atomicLoad(sb, 16u);
- tint_atomicAdd(sb, 16u, 123);
- tint_atomicSub(sb, 16u, 123);
- tint_atomicMax(sb, 16u, 123);
- tint_atomicMin(sb, 16u, 123);
- tint_atomicAnd(sb, 16u, 123);
- tint_atomicOr(sb, 16u, 123);
- tint_atomicXor(sb, 16u, 123);
- tint_atomicExchange(sb, 16u, 123);
- tint_atomicCompareExchangeWeak(sb, 16u, 123, 345);
- tint_atomicStore_1(sb, 20u, 123u);
- tint_atomicLoad_1(sb, 20u);
- tint_atomicAdd_1(sb, 20u, 123u);
- tint_atomicSub_1(sb, 20u, 123u);
- tint_atomicMax_1(sb, 20u, 123u);
- tint_atomicMin_1(sb, 20u, 123u);
- tint_atomicAnd_1(sb, 20u, 123u);
- tint_atomicOr_1(sb, 20u, 123u);
- tint_atomicXor_1(sb, 20u, 123u);
- tint_atomicExchange_1(sb, 20u, 123u);
- tint_atomicCompareExchangeWeak_1(sb, 20u, 123u, 345u);
+ tint_atomicStore(&(sb), 16u, 123);
+ tint_atomicLoad(&(sb), 16u);
+ tint_atomicAdd(&(sb), 16u, 123);
+ tint_atomicSub(&(sb), 16u, 123);
+ tint_atomicMax(&(sb), 16u, 123);
+ tint_atomicMin(&(sb), 16u, 123);
+ tint_atomicAnd(&(sb), 16u, 123);
+ tint_atomicOr(&(sb), 16u, 123);
+ tint_atomicXor(&(sb), 16u, 123);
+ tint_atomicExchange(&(sb), 16u, 123);
+ tint_atomicCompareExchangeWeak(&(sb), 16u, 123, 345);
+ tint_atomicStore_1(&(sb), 20u, 123u);
+ tint_atomicLoad_1(&(sb), 20u);
+ tint_atomicAdd_1(&(sb), 20u, 123u);
+ tint_atomicSub_1(&(sb), 20u, 123u);
+ tint_atomicMax_1(&(sb), 20u, 123u);
+ tint_atomicMin_1(&(sb), 20u, 123u);
+ tint_atomicAnd_1(&(sb), 20u, 123u);
+ tint_atomicOr_1(&(sb), 20u, 123u);
+ tint_atomicXor_1(&(sb), 20u, 123u);
+ tint_atomicExchange_1(&(sb), 20u, 123u);
+ tint_atomicCompareExchangeWeak_1(&(sb), 20u, 123u, 345u);
}
)";
@@ -2614,34 +2614,34 @@ struct SB {
auto* expect = R"(
@internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32)
+fn tint_atomicStore(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32)
@internal(intrinsic_atomic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+fn tint_atomicLoad(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
@internal(intrinsic_atomic_add_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicAdd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_sub_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicSub(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_max_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicMax(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_min_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicMin(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_and_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicAnd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_or_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicOr(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_xor_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicXor(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
@internal(intrinsic_atomic_exchange_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+fn tint_atomicExchange(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
struct atomic_compare_exchange_weak_ret_type {
old_value : i32,
@@ -2649,37 +2649,37 @@ struct atomic_compare_exchange_weak_ret_type {
}
@internal(intrinsic_atomic_compare_exchange_weak_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
+fn tint_atomicCompareExchangeWeak(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
@internal(intrinsic_atomic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32)
+fn tint_atomicStore_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32)
@internal(intrinsic_atomic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+fn tint_atomicLoad_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
@internal(intrinsic_atomic_add_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicAdd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_sub_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicSub_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_max_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicMax_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_min_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicMin_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_and_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicAnd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_or_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicOr_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_xor_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicXor_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
@internal(intrinsic_atomic_exchange_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+fn tint_atomicExchange_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
struct atomic_compare_exchange_weak_ret_type_1 {
old_value : u32,
@@ -2687,32 +2687,32 @@ struct atomic_compare_exchange_weak_ret_type_1 {
}
@internal(intrinsic_atomic_compare_exchange_weak_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
+fn tint_atomicCompareExchangeWeak_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
@compute @workgroup_size(1)
fn main() {
- tint_atomicStore(sb, 16u, 123);
- tint_atomicLoad(sb, 16u);
- tint_atomicAdd(sb, 16u, 123);
- tint_atomicSub(sb, 16u, 123);
- tint_atomicMax(sb, 16u, 123);
- tint_atomicMin(sb, 16u, 123);
- tint_atomicAnd(sb, 16u, 123);
- tint_atomicOr(sb, 16u, 123);
- tint_atomicXor(sb, 16u, 123);
- tint_atomicExchange(sb, 16u, 123);
- tint_atomicCompareExchangeWeak(sb, 16u, 123, 345);
- tint_atomicStore_1(sb, 20u, 123u);
- tint_atomicLoad_1(sb, 20u);
- tint_atomicAdd_1(sb, 20u, 123u);
- tint_atomicSub_1(sb, 20u, 123u);
- tint_atomicMax_1(sb, 20u, 123u);
- tint_atomicMin_1(sb, 20u, 123u);
- tint_atomicAnd_1(sb, 20u, 123u);
- tint_atomicOr_1(sb, 20u, 123u);
- tint_atomicXor_1(sb, 20u, 123u);
- tint_atomicExchange_1(sb, 20u, 123u);
- tint_atomicCompareExchangeWeak_1(sb, 20u, 123u, 345u);
+ tint_atomicStore(&(sb), 16u, 123);
+ tint_atomicLoad(&(sb), 16u);
+ tint_atomicAdd(&(sb), 16u, 123);
+ tint_atomicSub(&(sb), 16u, 123);
+ tint_atomicMax(&(sb), 16u, 123);
+ tint_atomicMin(&(sb), 16u, 123);
+ tint_atomicAnd(&(sb), 16u, 123);
+ tint_atomicOr(&(sb), 16u, 123);
+ tint_atomicXor(&(sb), 16u, 123);
+ tint_atomicExchange(&(sb), 16u, 123);
+ tint_atomicCompareExchangeWeak(&(sb), 16u, 123, 345);
+ tint_atomicStore_1(&(sb), 20u, 123u);
+ tint_atomicLoad_1(&(sb), 20u);
+ tint_atomicAdd_1(&(sb), 20u, 123u);
+ tint_atomicSub_1(&(sb), 20u, 123u);
+ tint_atomicMax_1(&(sb), 20u, 123u);
+ tint_atomicMin_1(&(sb), 20u, 123u);
+ tint_atomicAnd_1(&(sb), 20u, 123u);
+ tint_atomicOr_1(&(sb), 20u, 123u);
+ tint_atomicXor_1(&(sb), 20u, 123u);
+ tint_atomicExchange_1(&(sb), 20u, 123u);
+ tint_atomicCompareExchangeWeak_1(&(sb), 20u, 123u, 345u);
}
@group(0) @binding(0) var<storage, read_write> sb : SB;
diff --git a/chromium/third_party/dawn/src/tint/transform/decompose_strided_array.cc b/chromium/third_party/dawn/src/tint/transform/decompose_strided_array.cc
index ba6252b0251..61841f62996 100644
--- a/chromium/third_party/dawn/src/tint/transform/decompose_strided_array.cc
+++ b/chromium/third_party/dawn/src/tint/transform/decompose_strided_array.cc
@@ -72,8 +72,10 @@ void DecomposeStridedArray::Run(CloneContext& ctx, const DataMap&, DataMap&) con
auto name = ctx.dst->Symbols().New("strided_arr");
auto* member_ty = ctx.Clone(ast->type);
auto* member = ctx.dst->Member(kMemberName, member_ty,
- {ctx.dst->MemberSize(arr->Stride())});
- ctx.dst->Structure(name, {member});
+ utils::Vector{
+ ctx.dst->MemberSize(arr->Stride()),
+ });
+ ctx.dst->Structure(name, utils::Vector{member});
return name;
});
auto* count = ctx.Clone(ast->count);
@@ -114,7 +116,7 @@ void DecomposeStridedArray::Run(CloneContext& ctx, const DataMap&, DataMap&) con
// ->
// `array<strided_arr, 3>(strided_arr(1), strided_arr(2), strided_arr(3))`
ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
- if (!expr->args.empty()) {
+ if (!expr->args.IsEmpty()) {
if (auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>()) {
if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
if (auto* arr = ctor->ReturnType()->As<sem::Array>()) {
@@ -130,18 +132,18 @@ void DecomposeStridedArray::Run(CloneContext& ctx, const DataMap&, DataMap&) con
target.name = ctx.Clone(expr->target.name);
}
- ast::ExpressionList args;
+ utils::Vector<const ast::Expression*, 8> args;
if (auto it = decomposed.find(arr); it != decomposed.end()) {
- args.reserve(expr->args.size());
+ args.Reserve(expr->args.Length());
for (auto* arg : expr->args) {
- args.emplace_back(ctx.dst->Call(it->second, ctx.Clone(arg)));
+ args.Push(ctx.dst->Call(it->second, ctx.Clone(arg)));
}
} else {
args = ctx.Clone(expr->args);
}
- return target.type ? ctx.dst->Construct(target.type, args)
- : ctx.dst->Call(target.name, args);
+ return target.type ? ctx.dst->Construct(target.type, std::move(args))
+ : ctx.dst->Call(target.name, std::move(args));
}
}
}
diff --git a/chromium/third_party/dawn/src/tint/transform/decompose_strided_array_test.cc b/chromium/third_party/dawn/src/tint/transform/decompose_strided_array_test.cc
index ffc66956e10..4b0a335a730 100644
--- a/chromium/third_party/dawn/src/tint/transform/decompose_strided_array_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/decompose_strided_array_test.cc
@@ -39,7 +39,7 @@ TEST_F(DecomposeStridedArrayTest, ShouldRunNonStridedArray) {
// var<private> arr : array<f32, 4u>
ProgramBuilder b;
- b.Global("arr", b.ty.array<f32, 4u>(), ast::StorageClass::kPrivate);
+ b.GlobalVar("arr", b.ty.array<f32, 4u>(), ast::StorageClass::kPrivate);
EXPECT_FALSE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
}
@@ -47,7 +47,7 @@ TEST_F(DecomposeStridedArrayTest, ShouldRunDefaultStridedArray) {
// var<private> arr : @stride(4) array<f32, 4u>
ProgramBuilder b;
- b.Global("arr", b.ty.array<f32, 4u>(4), ast::StorageClass::kPrivate);
+ b.GlobalVar("arr", b.ty.array<f32, 4u>(4), ast::StorageClass::kPrivate);
EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
}
@@ -55,7 +55,7 @@ TEST_F(DecomposeStridedArrayTest, ShouldRunExplicitStridedArray) {
// var<private> arr : @stride(16) array<f32, 4u>
ProgramBuilder b;
- b.Global("arr", b.ty.array<f32, 4u>(16), ast::StorageClass::kPrivate);
+ b.GlobalVar("arr", b.ty.array<f32, 4u>(16), ast::StorageClass::kPrivate);
EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
}
@@ -78,13 +78,13 @@ TEST_F(DecomposeStridedArrayTest, PrivateDefaultStridedArray) {
// }
ProgramBuilder b;
- b.Global("arr", b.ty.array<f32, 4u>(4), ast::StorageClass::kPrivate);
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("arr", b.ty.array<f32, 4u>(4), ast::StorageClass::kPrivate);
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.array<f32, 4u>(4), b.Expr("arr"))),
b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -114,13 +114,13 @@ TEST_F(DecomposeStridedArrayTest, PrivateStridedArray) {
// }
ProgramBuilder b;
- b.Global("arr", b.ty.array<f32, 4u>(32), ast::StorageClass::kPrivate);
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("arr", b.ty.array<f32, 4u>(32), ast::StorageClass::kPrivate);
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.Expr("arr"))),
b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -157,14 +157,14 @@ TEST_F(DecomposeStridedArrayTest, ReadUniformStridedArray) {
// let b : f32 = s.a[1];
// }
ProgramBuilder b;
- auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.MemberAccessor("s", "a"))),
b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -205,16 +205,16 @@ TEST_F(DecomposeStridedArrayTest, ReadUniformDefaultStridedArray) {
// let b : f32 = s.a[1][2];
// }
ProgramBuilder b;
- auto* S = b.Structure("S", {b.Member("a", b.ty.array(b.ty.vec4<f32>(), 4_u, 16))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array(b.ty.vec4<f32>(), 4_u, 16))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
b.Func(
- "f", {}, b.ty.void_(),
- {
+ "f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.array(b.ty.vec4<f32>(), 4_u, 16), b.MemberAccessor("s", "a"))),
b.Decl(b.Let("b", b.ty.f32(),
b.IndexAccessor(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 2_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -251,14 +251,14 @@ TEST_F(DecomposeStridedArrayTest, ReadStorageStridedArray) {
// let b : f32 = s.a[1];
// }
ProgramBuilder b;
- auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.MemberAccessor("s", "a"))),
b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -299,14 +299,14 @@ TEST_F(DecomposeStridedArrayTest, ReadStorageDefaultStridedArray) {
// let b : f32 = s.a[1];
// }
ProgramBuilder b;
- auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(4))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(4))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.array<f32, 4u>(4), b.MemberAccessor("s", "a"))),
b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -343,17 +343,17 @@ TEST_F(DecomposeStridedArrayTest, WriteStorageStridedArray) {
// s.a[1i] = 5.0;
// }
ProgramBuilder b;
- auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Assign(b.MemberAccessor("s", "a"), b.Construct(b.ty.array<f32, 4u>(32))),
b.Assign(b.MemberAccessor("s", "a"),
b.Construct(b.ty.array<f32, 4u>(32), 1_f, 2_f, 3_f, 4_f)),
b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -397,17 +397,17 @@ TEST_F(DecomposeStridedArrayTest, WriteStorageDefaultStridedArray) {
// s.a[1] = 5.0;
// }
ProgramBuilder b;
- auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(4))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(4))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Assign(b.MemberAccessor("s", "a"), b.Construct(b.ty.array<f32, 4u>(4))),
b.Assign(b.MemberAccessor("s", "a"),
b.Construct(b.ty.array<f32, 4u>(4), 1_f, 2_f, 3_f, 4_f)),
b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -449,11 +449,11 @@ TEST_F(DecomposeStridedArrayTest, ReadWriteViaPointerLets) {
// (*b)[1] = 5.0;
// }
ProgramBuilder b;
- auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", nullptr, b.AddressOf(b.MemberAccessor("s", "a")))),
b.Decl(b.Let("b", nullptr, b.AddressOf(b.Deref(b.AddressOf(b.Deref("a")))))),
b.Decl(b.Let("c", nullptr, b.Deref("b"))),
@@ -461,7 +461,7 @@ TEST_F(DecomposeStridedArrayTest, ReadWriteViaPointerLets) {
b.Assign(b.Deref("b"), b.Construct(b.ty.array<f32, 4u>(32), 1_f, 2_f, 3_f, 4_f)),
b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), 5_f),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -510,11 +510,11 @@ TEST_F(DecomposeStridedArrayTest, PrivateAliasedStridedArray) {
// }
ProgramBuilder b;
b.Alias("ARR", b.ty.array<f32, 4u>(32));
- auto* S = b.Structure("S", {b.Member("a", b.ty.type_name("ARR"))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.type_name("ARR"))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.type_name("ARR"), b.MemberAccessor("s", "a"))),
b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
b.Assign(b.MemberAccessor("s", "a"), b.Construct(b.ty.type_name("ARR"))),
@@ -522,7 +522,7 @@ TEST_F(DecomposeStridedArrayTest, PrivateAliasedStridedArray) {
b.Construct(b.ty.type_name("ARR"), 1_f, 2_f, 3_f, 4_f)),
b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -580,11 +580,11 @@ TEST_F(DecomposeStridedArrayTest, PrivateNestedStridedArray) {
b.ty.array( //
b.ty.array(b.ty.type_name("ARR_A"), 3_u, 16), //
4_u, 128));
- auto* S = b.Structure("S", {b.Member("a", b.ty.type_name("ARR_B"))});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.type_name("ARR_B"))});
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", b.ty.type_name("ARR_B"), b.MemberAccessor("s", "a"))),
b.Decl(b.Let("b", b.ty.array(b.ty.type_name("ARR_A"), 3_u, 16),
b.IndexAccessor( //
@@ -614,7 +614,7 @@ TEST_F(DecomposeStridedArrayTest, PrivateNestedStridedArray) {
1_i),
5_f),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix.cc b/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix.cc
index 4f9d6c8db9e..75c96f6602f 100644
--- a/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix.cc
+++ b/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix.cc
@@ -105,10 +105,11 @@ DecomposeStridedMatrix::~DecomposeStridedMatrix() = default;
bool DecomposeStridedMatrix::ShouldRun(const Program* program, const DataMap&) const {
bool should_run = false;
- GatherCustomStrideMatrixMembers(program, [&](const sem::StructMember*, sem::Matrix*, uint32_t) {
- should_run = true;
- return GatherResult::kStop;
- });
+ GatherCustomStrideMatrixMembers(program,
+ [&](const sem::StructMember*, const sem::Matrix*, uint32_t) {
+ should_run = true;
+ return GatherResult::kStop;
+ });
return should_run;
}
@@ -118,7 +119,7 @@ void DecomposeStridedMatrix::Run(CloneContext& ctx, const DataMap&, DataMap&) co
// and populate the `decomposed` map with the members that have been replaced.
std::unordered_map<const ast::StructMember*, MatrixInfo> decomposed;
GatherCustomStrideMatrixMembers(
- ctx.src, [&](const sem::StructMember* member, sem::Matrix* matrix, uint32_t stride) {
+ ctx.src, [&](const sem::StructMember* member, const sem::Matrix* matrix, uint32_t stride) {
// We've got ourselves a struct member of a matrix type with a custom
// stride. Replace this with an array of column vectors.
MatrixInfo info{stride, matrix};
@@ -169,16 +170,16 @@ void DecomposeStridedMatrix::Run(CloneContext& ctx, const DataMap&, DataMap&) co
auto array = [&] { return info.array(ctx.dst); };
auto mat = ctx.dst->Sym("m");
- ast::ExpressionList columns(info.matrix->columns());
- for (uint32_t i = 0; i < static_cast<uint32_t>(columns.size()); i++) {
- columns[i] = ctx.dst->IndexAccessor(mat, u32(i));
+ utils::Vector<const ast::Expression*, 4> columns;
+ for (uint32_t i = 0; i < static_cast<uint32_t>(info.matrix->columns()); i++) {
+ columns.Push(ctx.dst->IndexAccessor(mat, u32(i)));
}
ctx.dst->Func(name,
- {
+ utils::Vector{
ctx.dst->Param(mat, matrix()),
},
array(),
- {
+ utils::Vector{
ctx.dst->Return(ctx.dst->Construct(array(), columns)),
});
return name;
@@ -210,16 +211,16 @@ void DecomposeStridedMatrix::Run(CloneContext& ctx, const DataMap&, DataMap&) co
auto array = [&] { return info.array(ctx.dst); };
auto arr = ctx.dst->Sym("arr");
- ast::ExpressionList columns(info.matrix->columns());
- for (uint32_t i = 0; i < static_cast<uint32_t>(columns.size()); i++) {
- columns[i] = ctx.dst->IndexAccessor(arr, u32(i));
+ utils::Vector<const ast::Expression*, 4> columns;
+ for (uint32_t i = 0; i < static_cast<uint32_t>(info.matrix->columns()); i++) {
+ columns.Push(ctx.dst->IndexAccessor(arr, u32(i)));
}
ctx.dst->Func(name,
- {
+ utils::Vector{
ctx.dst->Param(arr, array()),
},
matrix(),
- {
+ utils::Vector{
ctx.dst->Return(ctx.dst->Construct(matrix(), columns)),
});
return name;
diff --git a/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix_test.cc b/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix_test.cc
index 06169d763d0..afb06e88212 100644
--- a/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/decompose_strided_matrix_test.cc
@@ -68,20 +68,20 @@ TEST_F(DecomposeStridedMatrixTest, ReadUniformMatrix) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(16),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(16u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -124,21 +124,21 @@ TEST_F(DecomposeStridedMatrixTest, ReadUniformColumn) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(16),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(16u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
b.Func(
- "f", {}, b.ty.void_(),
- {
+ "f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("x", b.ty.vec2<f32>(), b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -177,20 +177,20 @@ TEST_F(DecomposeStridedMatrixTest, ReadUniformMatrix_DefaultStride) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(16),
- b.create<ast::StrideAttribute>(8),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(16u),
+ b.create<ast::StrideAttribute>(8u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -230,21 +230,21 @@ TEST_F(DecomposeStridedMatrixTest, ReadStorageMatrix) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(8),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(8u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -287,22 +287,22 @@ TEST_F(DecomposeStridedMatrixTest, ReadStorageColumn) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(16),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(16u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
b.Func(
- "f", {}, b.ty.void_(),
- {
+ "f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("x", b.ty.vec2<f32>(), b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -341,22 +341,22 @@ TEST_F(DecomposeStridedMatrixTest, WriteStorageMatrix) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(8),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(8u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Assign(b.MemberAccessor("s", "m"),
b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -399,21 +399,21 @@ TEST_F(DecomposeStridedMatrixTest, WriteStorageColumn) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(8),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(8u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Assign(b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i), b.vec2<f32>(1_f, 2_f)),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -458,18 +458,18 @@ TEST_F(DecomposeStridedMatrixTest, ReadWriteViaPointerLets) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(8),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(8u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- b.GroupAndBinding(0, 0));
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(0, 0));
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("a", nullptr, b.AddressOf(b.MemberAccessor("s", "m")))),
b.Decl(b.Let("b", nullptr, b.AddressOf(b.Deref(b.AddressOf(b.Deref("a")))))),
b.Decl(b.Let("x", nullptr, b.Deref("b"))),
@@ -478,7 +478,7 @@ TEST_F(DecomposeStridedMatrixTest, ReadWriteViaPointerLets) {
b.Assign(b.Deref("b"), b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), b.vec2<f32>(5_f, 6_f)),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -529,20 +529,20 @@ TEST_F(DecomposeStridedMatrixTest, ReadPrivateMatrix) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(8),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(8u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kPrivate);
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kPrivate);
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
@@ -582,21 +582,21 @@ TEST_F(DecomposeStridedMatrixTest, WritePrivateMatrix) {
// }
ProgramBuilder b;
auto* S = b.Structure(
- "S", {
+ "S", utils::Vector{
b.Member("m", b.ty.mat2x2<f32>(),
- {
- b.create<ast::StructMemberOffsetAttribute>(8),
- b.create<ast::StrideAttribute>(32),
+ utils::Vector{
+ b.create<ast::StructMemberOffsetAttribute>(8u),
+ b.create<ast::StrideAttribute>(32u),
b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
}),
});
- b.Global("s", b.ty.Of(S), ast::StorageClass::kPrivate);
- b.Func("f", {}, b.ty.void_(),
- {
+ b.GlobalVar("s", b.ty.Of(S), ast::StorageClass::kPrivate);
+ b.Func("f", utils::Empty, b.ty.void_(),
+ utils::Vector{
b.Assign(b.MemberAccessor("s", "m"),
b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
},
- {
+ utils::Vector{
b.Stage(ast::PipelineStage::kCompute),
b.WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/transform/disable_uniformity_analysis.cc b/chromium/third_party/dawn/src/tint/transform/disable_uniformity_analysis.cc
index 7a3002377df..918b1f163a3 100644
--- a/chromium/third_party/dawn/src/tint/transform/disable_uniformity_analysis.cc
+++ b/chromium/third_party/dawn/src/tint/transform/disable_uniformity_analysis.cc
@@ -28,7 +28,7 @@ DisableUniformityAnalysis::DisableUniformityAnalysis() = default;
DisableUniformityAnalysis::~DisableUniformityAnalysis() = default;
bool DisableUniformityAnalysis::ShouldRun(const Program* program, const DataMap&) const {
- return !program->Sem().Module()->Extensions().contains(
+ return !program->Sem().Module()->Extensions().Contains(
ast::Extension::kChromiumDisableUniformityAnalysis);
}
diff --git a/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.cc b/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.cc
index 2f775ca1198..e5e953cff07 100644
--- a/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.cc
+++ b/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.cc
@@ -44,6 +44,8 @@ bool ExpandCompoundAssignment::ShouldRun(const Program* program, const DataMap&)
return false;
}
+namespace {
+
/// Internal class used to collect statement expansions during the transform.
class State {
private:
@@ -163,6 +165,8 @@ class State {
}
};
+} // namespace
+
void ExpandCompoundAssignment::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
State state(ctx);
for (auto* node : ctx.src->ASTNodes().Objects()) {
@@ -170,14 +174,8 @@ void ExpandCompoundAssignment::Run(CloneContext& ctx, const DataMap&, DataMap&)
state.Expand(assign, assign->lhs, ctx.Clone(assign->rhs), assign->op);
} else if (auto* inc_dec = node->As<ast::IncrementDecrementStatement>()) {
// For increment/decrement statements, `i++` becomes `i = i + 1`.
- // TODO(jrprice): Simplify this when we have untyped literals.
- auto* sem_lhs = ctx.src->Sem().Get(inc_dec->lhs);
- const ast::IntLiteralExpression* one =
- sem_lhs->Type()->UnwrapRef()->is_signed_integer_scalar()
- ? ctx.dst->Expr(1_i)->As<ast::IntLiteralExpression>()
- : ctx.dst->Expr(1_u)->As<ast::IntLiteralExpression>();
auto op = inc_dec->increment ? ast::BinaryOp::kAdd : ast::BinaryOp::kSubtract;
- state.Expand(inc_dec, inc_dec->lhs, one, op);
+ state.Expand(inc_dec, inc_dec->lhs, ctx.dst->Expr(1_a), op);
}
}
state.Finalize();
diff --git a/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.h b/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.h
index d38d297d144..1081df7b322 100644
--- a/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.h
+++ b/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment.h
@@ -38,7 +38,7 @@ namespace tint::transform {
///
/// This transform also handles increment and decrement statements in the same
/// manner, by replacing `i++` with `i = i + 1`.
-class ExpandCompoundAssignment : public Castable<ExpandCompoundAssignment, Transform> {
+class ExpandCompoundAssignment final : public Castable<ExpandCompoundAssignment, Transform> {
public:
/// Constructor
ExpandCompoundAssignment();
diff --git a/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment_test.cc b/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment_test.cc
index 613a13535ac..6b18b403780 100644
--- a/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/expand_compound_assignment_test.cc
@@ -473,7 +473,7 @@ fn main() {
auto* expect = R"(
fn main() {
var v : i32;
- v = (v + 1i);
+ v = (v + 1);
}
)";
@@ -493,7 +493,7 @@ fn main() {
auto* expect = R"(
fn main() {
var v : u32;
- v = (v + 1u);
+ v = (v + 1);
}
)";
@@ -513,7 +513,7 @@ fn main() {
auto* expect = R"(
fn main() {
var v : i32;
- v = (v - 1i);
+ v = (v - 1);
}
)";
@@ -533,7 +533,7 @@ fn main() {
auto* expect = R"(
fn main() {
var v : u32;
- v = (v - 1u);
+ v = (v - 1);
}
)";
@@ -556,7 +556,7 @@ fn main() {
var v : i32;
let p = &(v);
let tint_symbol = &(*(p));
- *(tint_symbol) = (*(tint_symbol) + 1i);
+ *(tint_symbol) = (*(tint_symbol) + 1);
}
)";
@@ -584,7 +584,7 @@ struct S {
fn main() {
var s : S;
- s.m = (s.m + 1i);
+ s.m = (s.m + 1);
}
)";
@@ -617,7 +617,7 @@ fn idx() -> i32 {
fn main() {
let tint_symbol = &(a[idx()]);
- *(tint_symbol) = (*(tint_symbol) + 1i);
+ *(tint_symbol) = (*(tint_symbol) + 1);
}
)";
@@ -651,7 +651,7 @@ fn idx() -> i32 {
fn main() {
let tint_symbol = &(v);
let tint_symbol_1 = idx();
- (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1i);
+ (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1);
}
)";
@@ -671,7 +671,7 @@ fn main() {
auto* expect = R"(
fn main() {
var v : vec4<i32>;
- v.y = (v.y + 1i);
+ v.y = (v.y + 1);
}
)";
@@ -727,7 +727,7 @@ fn main() {
continuing {
let tint_symbol = &(a[idx1()]);
let tint_symbol_1 = idx2();
- (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1i);
+ (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1);
}
}
}
diff --git a/chromium/third_party/dawn/src/tint/transform/first_index_offset.cc b/chromium/third_party/dawn/src/tint/transform/first_index_offset.cc
index 9d89b83acdc..a966f7ff629 100644
--- a/chromium/third_party/dawn/src/tint/transform/first_index_offset.cc
+++ b/chromium/third_party/dawn/src/tint/transform/first_index_offset.cc
@@ -79,13 +79,13 @@ void FirstIndexOffset::Run(CloneContext& ctx, const DataMap& inputs, DataMap& ou
if (auto* var = node->As<ast::Variable>()) {
for (auto* attr : var->attributes) {
if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
- ast::Builtin builtin = builtin_attr->builtin;
- if (builtin == ast::Builtin::kVertexIndex) {
+ ast::BuiltinValue builtin = builtin_attr->builtin;
+ if (builtin == ast::BuiltinValue::kVertexIndex) {
auto* sem_var = ctx.src->Sem().Get(var);
builtin_vars.emplace(sem_var, kFirstVertexName);
has_vertex_or_instance_index = true;
}
- if (builtin == ast::Builtin::kInstanceIndex) {
+ if (builtin == ast::BuiltinValue::kInstanceIndex) {
auto* sem_var = ctx.src->Sem().Get(var);
builtin_vars.emplace(sem_var, kFirstInstanceName);
has_vertex_or_instance_index = true;
@@ -96,13 +96,13 @@ void FirstIndexOffset::Run(CloneContext& ctx, const DataMap& inputs, DataMap& ou
if (auto* member = node->As<ast::StructMember>()) {
for (auto* attr : member->attributes) {
if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
- ast::Builtin builtin = builtin_attr->builtin;
- if (builtin == ast::Builtin::kVertexIndex) {
+ ast::BuiltinValue builtin = builtin_attr->builtin;
+ if (builtin == ast::BuiltinValue::kVertexIndex) {
auto* sem_mem = ctx.src->Sem().Get(member);
builtin_members.emplace(sem_mem, kFirstVertexName);
has_vertex_or_instance_index = true;
}
- if (builtin == ast::Builtin::kInstanceIndex) {
+ if (builtin == ast::BuiltinValue::kInstanceIndex) {
auto* sem_mem = ctx.src->Sem().Get(member);
builtin_members.emplace(sem_mem, kFirstInstanceName);
has_vertex_or_instance_index = true;
@@ -114,18 +114,19 @@ void FirstIndexOffset::Run(CloneContext& ctx, const DataMap& inputs, DataMap& ou
if (has_vertex_or_instance_index) {
// Add uniform buffer members and calculate byte offsets
- ast::StructMemberList members;
- members.push_back(ctx.dst->Member(kFirstVertexName, ctx.dst->ty.u32()));
- members.push_back(ctx.dst->Member(kFirstInstanceName, ctx.dst->ty.u32()));
+ utils::Vector<const ast::StructMember*, 8> members;
+ members.Push(ctx.dst->Member(kFirstVertexName, ctx.dst->ty.u32()));
+ members.Push(ctx.dst->Member(kFirstInstanceName, ctx.dst->ty.u32()));
auto* struct_ = ctx.dst->Structure(ctx.dst->Sym(), std::move(members));
// Create a global to hold the uniform buffer
Symbol buffer_name = ctx.dst->Sym();
- ctx.dst->Global(buffer_name, ctx.dst->ty.Of(struct_), ast::StorageClass::kUniform, nullptr,
- ast::AttributeList{
- ctx.dst->create<ast::BindingAttribute>(ub_binding),
- ctx.dst->create<ast::GroupAttribute>(ub_group),
- });
+ ctx.dst->GlobalVar(buffer_name, ctx.dst->ty.Of(struct_), ast::StorageClass::kUniform,
+ nullptr,
+ utils::Vector{
+ ctx.dst->create<ast::BindingAttribute>(ub_binding),
+ ctx.dst->create<ast::GroupAttribute>(ub_group),
+ });
// Fix up all references to the builtins with the offsets
ctx.ReplaceAll([=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
diff --git a/chromium/third_party/dawn/src/tint/transform/fold_trivial_single_use_lets.cc b/chromium/third_party/dawn/src/tint/transform/fold_trivial_single_use_lets.cc
index 5bcdaa49000..8a949ecc6c6 100644
--- a/chromium/third_party/dawn/src/tint/transform/fold_trivial_single_use_lets.cc
+++ b/chromium/third_party/dawn/src/tint/transform/fold_trivial_single_use_lets.cc
@@ -31,11 +31,11 @@ const ast::VariableDeclStatement* AsTrivialLetDecl(const ast::Statement* stmt) {
if (!var_decl) {
return nullptr;
}
- auto* var = var_decl->variable;
- if (!var->is_const) {
+ auto* let = var_decl->variable->As<ast::Let>();
+ if (!let) {
return nullptr;
}
- auto* ctor = var->constructor;
+ auto* ctor = let->constructor;
if (!IsAnyOf<ast::IdentifierExpression, ast::LiteralExpression>(ctor)) {
return nullptr;
}
@@ -52,7 +52,7 @@ void FoldTrivialSingleUseLets::Run(CloneContext& ctx, const DataMap&, DataMap&)
for (auto* node : ctx.src->ASTNodes().Objects()) {
if (auto* block = node->As<ast::BlockStatement>()) {
auto& stmts = block->statements;
- for (size_t stmt_idx = 0; stmt_idx < stmts.size(); stmt_idx++) {
+ for (size_t stmt_idx = 0; stmt_idx < stmts.Length(); stmt_idx++) {
auto* stmt = stmts[stmt_idx];
if (auto* let_decl = AsTrivialLetDecl(stmt)) {
auto* let = let_decl->variable;
@@ -65,7 +65,7 @@ void FoldTrivialSingleUseLets::Run(CloneContext& ctx, const DataMap&, DataMap&)
auto* user = users[0];
auto* user_stmt = user->Stmt()->Declaration();
- for (size_t i = stmt_idx; i < stmts.size(); i++) {
+ for (size_t i = stmt_idx; i < stmts.Length(); i++) {
if (user_stmt == stmts[i]) {
auto* user_expr = user->Declaration();
ctx.Remove(stmts, let_decl);
diff --git a/chromium/third_party/dawn/src/tint/transform/for_loop_to_loop.cc b/chromium/third_party/dawn/src/tint/transform/for_loop_to_loop.cc
index 8fff0a8c1be..e585790e404 100644
--- a/chromium/third_party/dawn/src/tint/transform/for_loop_to_loop.cc
+++ b/chromium/third_party/dawn/src/tint/transform/for_loop_to_loop.cc
@@ -35,7 +35,7 @@ bool ForLoopToLoop::ShouldRun(const Program* program, const DataMap&) const {
void ForLoopToLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
ctx.ReplaceAll([&](const ast::ForLoopStatement* for_loop) -> const ast::Statement* {
- ast::StatementList stmts;
+ utils::Vector<const ast::Statement*, 8> stmts;
if (auto* cond = for_loop->condition) {
// !condition
auto* not_cond =
@@ -45,10 +45,10 @@ void ForLoopToLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
auto* break_body = ctx.dst->Block(ctx.dst->create<ast::BreakStatement>());
// if (!condition) { break; }
- stmts.emplace_back(ctx.dst->If(not_cond, break_body));
+ stmts.Push(ctx.dst->If(not_cond, break_body));
}
for (auto* stmt : for_loop->body->statements) {
- stmts.emplace_back(ctx.Clone(stmt));
+ stmts.Push(ctx.Clone(stmt));
}
const ast::BlockStatement* continuing = nullptr;
diff --git a/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.cc b/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.cc
index d6cdded9a06..d43ddae79eb 100644
--- a/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.cc
+++ b/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.cc
@@ -46,7 +46,7 @@ class LocalizeStructArrayAssignment::State {
expr, b.Diagnostics(), [&](const ast::IndexAccessorExpression* ia) {
// Indexing using a runtime value?
auto* idx_sem = ctx.src->Sem().Get(ia->index);
- if (!idx_sem->ConstantValue().IsValid()) {
+ if (!idx_sem->ConstantValue()) {
// Indexing a member access expr?
if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
// That accesses an array?
@@ -98,8 +98,8 @@ class LocalizeStructArrayAssignment::State {
void Run() {
struct Shared {
bool process_nested_nodes = false;
- ast::StatementList insert_before_stmts;
- ast::StatementList insert_after_stmts;
+ utils::Vector<const ast::Statement*, 4> insert_before_stmts;
+ utils::Vector<const ast::Statement*, 4> insert_after_stmts;
} s;
ctx.ReplaceAll([&](const ast::AssignmentStatement* assign_stmt) -> const ast::Statement* {
@@ -130,10 +130,12 @@ class LocalizeStructArrayAssignment::State {
// Combine insert_before_stmts + new_assign_stmt + insert_after_stmts into
// a block and return it
- ast::StatementList stmts = std::move(s.insert_before_stmts);
- stmts.reserve(1 + s.insert_after_stmts.size());
- stmts.emplace_back(new_assign_stmt);
- stmts.insert(stmts.end(), s.insert_after_stmts.begin(), s.insert_after_stmts.end());
+ auto stmts = std::move(s.insert_before_stmts);
+ stmts.Reserve(1 + s.insert_after_stmts.Length());
+ stmts.Push(new_assign_stmt);
+ for (auto* stmt : s.insert_after_stmts) {
+ stmts.Push(stmt);
+ }
return b.Block(std::move(stmts));
});
@@ -156,7 +158,7 @@ class LocalizeStructArrayAssignment::State {
// Store the address of the member access into a let as we need to read
// the value twice e.g. let tint_symbol = &(s.a1);
auto mem_access_ptr = b.Sym();
- s.insert_before_stmts.push_back(
+ s.insert_before_stmts.Push(
b.Decl(b.Let(mem_access_ptr, nullptr, b.AddressOf(mem_access))));
// Disable further transforms when cloning
@@ -165,7 +167,7 @@ class LocalizeStructArrayAssignment::State {
// Copy entire array out of struct into local temp var
// e.g. var tint_symbol_1 = *(tint_symbol);
auto tmp_var = b.Sym();
- s.insert_before_stmts.push_back(
+ s.insert_before_stmts.Push(
b.Decl(b.Var(tmp_var, nullptr, b.Deref(mem_access_ptr))));
// Replace input index_access with a clone of itself, but with its
@@ -177,8 +179,13 @@ class LocalizeStructArrayAssignment::State {
// Assign temp var back to array
// e.g. *(tint_symbol) = tint_symbol_1;
auto* assign_rhs_to_temp = b.Assign(b.Deref(mem_access_ptr), tmp_var);
- s.insert_after_stmts.insert(s.insert_after_stmts.begin(),
- assign_rhs_to_temp); // push_front
+ {
+ utils::Vector<const ast::Statement*, 8> stmts{assign_rhs_to_temp};
+ for (auto* stmt : s.insert_after_stmts) {
+ stmts.Push(stmt);
+ }
+ s.insert_after_stmts = std::move(stmts);
+ }
return new_index_access;
});
diff --git a/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.h b/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.h
index 129c8491bb0..130f8cc107e 100644
--- a/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.h
+++ b/chromium/third_party/dawn/src/tint/transform/localize_struct_array_assignment.h
@@ -27,7 +27,8 @@ namespace tint::transform {
///
/// @note Depends on the following transforms to have been run first:
/// * SimplifyPointers
-class LocalizeStructArrayAssignment : public Castable<LocalizeStructArrayAssignment, Transform> {
+class LocalizeStructArrayAssignment final
+ : public Castable<LocalizeStructArrayAssignment, Transform> {
public:
/// Constructor
LocalizeStructArrayAssignment();
diff --git a/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.cc b/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.cc
index 3e0a4b5412e..00bf5ec5590 100644
--- a/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.cc
+++ b/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.cc
@@ -29,7 +29,7 @@ namespace tint::transform {
namespace {
bool IsBlockWithSingleBreak(const ast::BlockStatement* block) {
- if (block->statements.size() != 1) {
+ if (block->statements.Length() != 1) {
return false;
}
return block->statements[0]->Is<ast::BreakStatement>();
@@ -74,7 +74,7 @@ void LoopToForLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
// loop { if (condition) { break; } ... }
// loop { if (condition) {} else { break; } ... }
auto& stmts = loop->body->statements;
- if (stmts.empty()) {
+ if (stmts.IsEmpty()) {
return nullptr;
}
auto* if_stmt = stmts[0]->As<ast::IfStatement>();
@@ -96,7 +96,7 @@ void LoopToForLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
// function call statement.
const ast::Statement* continuing = nullptr;
if (auto* loop_cont = loop->continuing) {
- if (loop_cont->statements.size() != 1) {
+ if (loop_cont->statements.Length() != 1) {
return nullptr;
}
diff --git a/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.h b/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.h
index 0623d79b85f..0e948c80c17 100644
--- a/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.h
+++ b/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop.h
@@ -21,7 +21,7 @@ namespace tint::transform {
/// LoopToForLoop is a Transform that attempts to convert WGSL `loop {}`
/// statements into a for-loop statement.
-class LoopToForLoop : public Castable<LoopToForLoop, Transform> {
+class LoopToForLoop final : public Castable<LoopToForLoop, Transform> {
public:
/// Constructor
LoopToForLoop();
diff --git a/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop_test.cc b/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop_test.cc
index e3d7eccbef1..24e0e15e0a1 100644
--- a/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/loop_to_for_loop_test.cc
@@ -151,7 +151,7 @@ fn f() {
)";
auto* expect = R"(
-let N = 16u;
+const N = 16u;
fn f() {
var i : u32 = 0u;
diff --git a/chromium/third_party/dawn/src/tint/transform/manager.cc b/chromium/third_party/dawn/src/tint/transform/manager.cc
index e5f7682ead8..4e83320b419 100644
--- a/chromium/third_party/dawn/src/tint/transform/manager.cc
+++ b/chromium/third_party/dawn/src/tint/transform/manager.cc
@@ -49,7 +49,8 @@ Output Manager::Run(const Program* program, const DataMap& data) const {
Output out;
for (const auto& transform : transforms_) {
if (!transform->ShouldRun(in, data)) {
- TINT_IF_PRINT_PROGRAM(std::cout << "Skipping " << transform->TypeInfo().name << std::endl);
+ TINT_IF_PRINT_PROGRAM(std::cout << "Skipping " << transform->TypeInfo().name
+ << std::endl);
continue;
}
TINT_IF_PRINT_PROGRAM(print_program("Input to", transform.get()));
diff --git a/chromium/third_party/dawn/src/tint/transform/manager.h b/chromium/third_party/dawn/src/tint/transform/manager.h
index 9f5c6bcf218..04bf9fe8953 100644
--- a/chromium/third_party/dawn/src/tint/transform/manager.h
+++ b/chromium/third_party/dawn/src/tint/transform/manager.h
@@ -27,7 +27,7 @@ namespace tint::transform {
/// The inner transforms will execute in the appended order.
/// If any inner transform fails the manager will return immediately and
/// the error can be retrieved with the Output's diagnostics.
-class Manager : public Castable<Manager, Transform> {
+class Manager final : public Castable<Manager, Transform> {
public:
/// Constructor
Manager();
diff --git a/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.cc b/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.cc
index 22bcd5c1bc1..122fb3ce983 100644
--- a/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.cc
+++ b/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.cc
@@ -23,13 +23,21 @@
#include "src/tint/program_builder.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/function.h"
+#include "src/tint/sem/module.h"
#include "src/tint/sem/statement.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/utils/string.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::ModuleScopeVarToEntryPointParam);
namespace tint::transform {
namespace {
+
+using WorkgroupParameterMemberList = utils::Vector<const ast::StructMember*, 8>;
+
+// The name of the struct member for arrays that are wrapped in structures.
+const char* kWrappedArrayMemberName = "arr";
+
// Returns `true` if `type` is or contains a matrix type.
bool ContainsMatrix(const sem::Type* type) {
type = type->UnwrapRef();
@@ -83,17 +91,222 @@ struct ModuleScopeVarToEntryPointParam::State {
}
}
+ /// Process a variable `var` that is referenced in the entry point function `func`.
+ /// This will redeclare the variable as a function parameter, possibly as a pointer.
+ /// Some workgroup variables will be redeclared as a member inside a workgroup structure.
+ /// @param func the entry point function
+ /// @param var the variable
+ /// @param new_var_symbol the symbol to use for the replacement
+ /// @param workgroup_param helper function to get a symbol to a workgroup struct parameter
+ /// @param workgroup_parameter_members reference to a list of a workgroup struct members
+ /// @param is_pointer output signalling whether the replacement is a pointer
+ /// @param is_wrapped output signalling whether the replacement is wrapped in a struct
+ void ProcessVariableInEntryPoint(const ast::Function* func,
+ const sem::Variable* var,
+ Symbol new_var_symbol,
+ std::function<Symbol()> workgroup_param,
+ WorkgroupParameterMemberList& workgroup_parameter_members,
+ bool& is_pointer,
+ bool& is_wrapped) {
+ auto* var_ast = var->Declaration()->As<ast::Var>();
+ auto* ty = var->Type()->UnwrapRef();
+
+ // Helper to create an AST node for the store type of the variable.
+ auto store_type = [&]() { return CreateASTTypeFor(ctx, ty); };
+
+ ast::StorageClass sc = var->StorageClass();
+ switch (sc) {
+ case ast::StorageClass::kHandle: {
+ // For a texture or sampler variable, redeclare it as an entry point parameter.
+ // Disable entry point parameter validation.
+ auto* disable_validation =
+ ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
+ auto attrs = ctx.Clone(var->Declaration()->attributes);
+ attrs.Push(disable_validation);
+ auto* param = ctx.dst->Param(new_var_symbol, store_type(), attrs);
+ ctx.InsertFront(func->params, param);
+
+ break;
+ }
+ case ast::StorageClass::kStorage:
+ case ast::StorageClass::kUniform: {
+ // Variables into the Storage and Uniform storage classes are redeclared as entry
+ // point parameters with a pointer type.
+ auto attributes = ctx.Clone(var->Declaration()->attributes);
+ attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter));
+ attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+
+ auto* param_type = store_type();
+ if (auto* arr = ty->As<sem::Array>(); arr && arr->IsRuntimeSized()) {
+ // Wrap runtime-sized arrays in structures, so that we can declare pointers to
+ // them. Ideally we'd just emit the array itself as a pointer, but this is not
+ // representable in Tint's AST.
+ CloneStructTypes(ty);
+ auto* wrapper = ctx.dst->Structure(
+ ctx.dst->Sym(), utils::Vector{
+ ctx.dst->Member(kWrappedArrayMemberName, param_type),
+ });
+ param_type = ctx.dst->ty.Of(wrapper);
+ is_wrapped = true;
+ }
+
+ param_type = ctx.dst->ty.pointer(param_type, sc, var_ast->declared_access);
+ auto* param = ctx.dst->Param(new_var_symbol, param_type, attributes);
+ ctx.InsertFront(func->params, param);
+ is_pointer = true;
+
+ break;
+ }
+ case ast::StorageClass::kWorkgroup: {
+ if (ContainsMatrix(var->Type())) {
+ // Due to a bug in the MSL compiler, we use a threadgroup memory argument for
+ // any workgroup allocation that contains a matrix. See crbug.com/tint/938.
+ // TODO(jrprice): Do this for all other workgroup variables too.
+
+ // Create a member in the workgroup parameter struct.
+ auto member = ctx.Clone(var->Declaration()->symbol);
+ workgroup_parameter_members.Push(ctx.dst->Member(member, store_type()));
+ CloneStructTypes(var->Type()->UnwrapRef());
+
+ // Create a function-scope variable that is a pointer to the member.
+ auto* member_ptr = ctx.dst->AddressOf(
+ ctx.dst->MemberAccessor(ctx.dst->Deref(workgroup_param()), member));
+ auto* local_var = ctx.dst->Let(
+ new_var_symbol,
+ ctx.dst->ty.pointer(store_type(), ast::StorageClass::kWorkgroup),
+ member_ptr);
+ ctx.InsertFront(func->body->statements, ctx.dst->Decl(local_var));
+ is_pointer = true;
+
+ break;
+ }
+ [[fallthrough]];
+ }
+ case ast::StorageClass::kPrivate: {
+ // Variables in the Private and Workgroup storage classes are redeclared at function
+ // scope. Disable storage class validation on this variable.
+ auto* disable_validation =
+ ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass);
+ auto* constructor = ctx.Clone(var->Declaration()->constructor);
+ auto* local_var = ctx.dst->Var(new_var_symbol, store_type(), sc, constructor,
+ utils::Vector{disable_validation});
+ ctx.InsertFront(func->body->statements, ctx.dst->Decl(local_var));
+
+ break;
+ }
+ case ast::StorageClass::kPushConstant: {
+ ctx.dst->Diagnostics().add_error(
+ diag::System::Transform,
+ "unhandled module-scope storage class (" + utils::ToString(sc) + ")");
+ break;
+ }
+ default: {
+ TINT_ICE(Transform, ctx.dst->Diagnostics())
+ << "unhandled module-scope storage class (" << sc << ")";
+ break;
+ }
+ }
+ }
+
+ /// Process a variable `var` that is referenced in the user-defined function `func`.
+ /// This will redeclare the variable as a function parameter, possibly as a pointer.
+ /// @param func the user-defined function
+ /// @param var the variable
+ /// @param new_var_symbol the symbol to use for the replacement
+ /// @param is_pointer output signalling whether the replacement is a pointer or not
+ void ProcessVariableInUserFunction(const ast::Function* func,
+ const sem::Variable* var,
+ Symbol new_var_symbol,
+ bool& is_pointer) {
+ auto* var_ast = var->Declaration()->As<ast::Var>();
+ auto* ty = var->Type()->UnwrapRef();
+ auto* param_type = CreateASTTypeFor(ctx, ty);
+ auto sc = var->StorageClass();
+ switch (sc) {
+ case ast::StorageClass::kPrivate:
+ case ast::StorageClass::kStorage:
+ case ast::StorageClass::kUniform:
+ case ast::StorageClass::kHandle:
+ case ast::StorageClass::kWorkgroup:
+ break;
+ case ast::StorageClass::kPushConstant: {
+ ctx.dst->Diagnostics().add_error(
+ diag::System::Transform,
+ "unhandled module-scope storage class (" + utils::ToString(sc) + ")");
+ break;
+ }
+ default: {
+ TINT_ICE(Transform, ctx.dst->Diagnostics())
+ << "unhandled module-scope storage class (" << sc << ")";
+ }
+ }
+
+ // Use a pointer for non-handle types.
+ utils::Vector<const ast::Attribute*, 2> attributes;
+ if (!ty->is_handle()) {
+ param_type = ctx.dst->ty.pointer(param_type, sc, var_ast->declared_access);
+ is_pointer = true;
+
+ // Disable validation of the parameter's storage class and of arguments passed to it.
+ attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+ attributes.Push(
+ ctx.dst->Disable(ast::DisabledValidation::kIgnoreInvalidPointerArgument));
+ }
+
+ // Redeclare the variable as a parameter.
+ ctx.InsertBack(func->params,
+ ctx.dst->Param(new_var_symbol, param_type, std::move(attributes)));
+ }
+
+ /// Replace all uses of `var` in `func` with references to `new_var`.
+ /// @param func the function
+ /// @param var the variable to replace
+ /// @param new_var the symbol to use for replacement
+ /// @param is_pointer true if `new_var` is a pointer to the new variable
+ /// @param is_wrapped true if `new_var` is an array wrapped in a structure
+ void ReplaceUsesInFunction(const ast::Function* func,
+ const sem::Variable* var,
+ Symbol new_var,
+ bool is_pointer,
+ bool is_wrapped) {
+ for (auto* user : var->Users()) {
+ if (user->Stmt()->Function()->Declaration() == func) {
+ const ast::Expression* expr = ctx.dst->Expr(new_var);
+ if (is_pointer) {
+ // If this identifier is used by an address-of operator, just remove the
+ // address-of instead of adding a deref, since we already have a pointer.
+ auto* ident = user->Declaration()->As<ast::IdentifierExpression>();
+ if (ident_to_address_of_.count(ident)) {
+ ctx.Replace(ident_to_address_of_[ident], expr);
+ continue;
+ }
+
+ expr = ctx.dst->Deref(expr);
+ }
+ if (is_wrapped) {
+ // Get the member from the wrapper structure.
+ expr = ctx.dst->MemberAccessor(expr, kWrappedArrayMemberName);
+ }
+ ctx.Replace(user->Declaration(), expr);
+ }
+ }
+ }
+
/// Process the module.
void Process() {
// Predetermine the list of function calls that need to be replaced.
- using CallList = std::vector<const ast::CallExpression*>;
+ using CallList = utils::Vector<const ast::CallExpression*, 8>;
std::unordered_map<const ast::Function*, CallList> calls_to_replace;
- std::vector<const ast::Function*> functions_to_process;
+ utils::Vector<const ast::Function*, 8> functions_to_process;
+
+ // Build a list of functions that transitively reference any module-scope variables.
+ for (auto* decl : ctx.src->Sem().Module()->DependencyOrderedDeclarations()) {
+ auto* func_ast = decl->As<ast::Function>();
+ if (!func_ast) {
+ continue;
+ }
- // Build a list of functions that transitively reference any module-scope
- // variables.
- for (auto* func_ast : ctx.src->AST().Functions()) {
auto* func_sem = ctx.src->Sem().Get(func_ast);
bool needs_processing = false;
@@ -104,30 +317,28 @@ struct ModuleScopeVarToEntryPointParam::State {
}
}
if (needs_processing) {
- functions_to_process.push_back(func_ast);
+ functions_to_process.Push(func_ast);
// Find all of the calls to this function that will need to be replaced.
for (auto* call : func_sem->CallSites()) {
- calls_to_replace[call->Stmt()->Function()->Declaration()].push_back(
+ calls_to_replace[call->Stmt()->Function()->Declaration()].Push(
call->Declaration());
}
}
}
- // Build a list of `&ident` expressions. We'll use this later to avoid
- // generating expressions of the form `&*ident`, which break WGSL validation
- // rules when this expression is passed to a function.
- // TODO(jrprice): We should add support for bidirectional SEM tree traversal
- // so that we can do this on the fly instead.
- std::unordered_map<const ast::IdentifierExpression*, const ast::UnaryOpExpression*>
- ident_to_address_of;
+ // Build a list of `&ident` expressions. We'll use this later to avoid generating
+ // expressions of the form `&*ident`, which break WGSL validation rules when this expression
+ // is passed to a function.
+ // TODO(jrprice): We should add support for bidirectional SEM tree traversal so that we can
+ // do this on the fly instead.
for (auto* node : ctx.src->ASTNodes().Objects()) {
auto* address_of = node->As<ast::UnaryOpExpression>();
if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
continue;
}
if (auto* ident = address_of->expr->As<ast::IdentifierExpression>()) {
- ident_to_address_of[ident] = address_of;
+ ident_to_address_of_[ident] = address_of;
}
}
@@ -141,13 +352,12 @@ struct ModuleScopeVarToEntryPointParam::State {
bool is_pointer;
bool is_wrapped;
};
- const char* kWrappedArrayMemberName = "arr";
std::unordered_map<const sem::Variable*, NewVar> var_to_newvar;
- // We aggregate all workgroup variables into a struct to avoid hitting
- // MSL's limit for threadgroup memory arguments.
+ // We aggregate all workgroup variables into a struct to avoid hitting MSL's limit for
+ // threadgroup memory arguments.
Symbol workgroup_parameter_symbol;
- ast::StructMemberList workgroup_parameter_members;
+ WorkgroupParameterMemberList workgroup_parameter_members;
auto workgroup_param = [&]() {
if (!workgroup_parameter_symbol.IsValid()) {
workgroup_parameter_symbol = ctx.dst->Sym();
@@ -155,163 +365,77 @@ struct ModuleScopeVarToEntryPointParam::State {
return workgroup_parameter_symbol;
};
+ // Process and redeclare all variables referenced by the function.
for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
- auto sc = var->StorageClass();
- auto* ty = var->Type()->UnwrapRef();
- if (sc == ast::StorageClass::kNone) {
+ if (var->StorageClass() == ast::StorageClass::kNone) {
continue;
}
- if (sc != ast::StorageClass::kPrivate && sc != ast::StorageClass::kStorage &&
- sc != ast::StorageClass::kUniform && sc != ast::StorageClass::kHandle &&
- sc != ast::StorageClass::kWorkgroup) {
- TINT_ICE(Transform, ctx.dst->Diagnostics())
- << "unhandled module-scope storage class (" << sc << ")";
+ if (local_private_vars_.count(var)) {
+ continue;
}
- // This is the symbol for the variable that replaces the module-scope
- // var.
+ // This is the symbol for the variable that replaces the module-scope var.
auto new_var_symbol = ctx.dst->Sym();
- // Helper to create an AST node for the store type of the variable.
- auto store_type = [&]() { return CreateASTTypeFor(ctx, ty); };
-
// Track whether the new variable is a pointer or not.
bool is_pointer = false;
// Track whether the new variable was wrapped in a struct or not.
bool is_wrapped = false;
- if (is_entry_point) {
- if (var->Type()->UnwrapRef()->is_handle()) {
- // For a texture or sampler variable, redeclare it as an entry point
- // parameter. Disable entry point parameter validation.
- auto* disable_validation =
- ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
- auto attrs = ctx.Clone(var->Declaration()->attributes);
- attrs.push_back(disable_validation);
- auto* param = ctx.dst->Param(new_var_symbol, store_type(), attrs);
- ctx.InsertFront(func_ast->params, param);
- } else if (sc == ast::StorageClass::kStorage ||
- sc == ast::StorageClass::kUniform) {
- // Variables into the Storage and Uniform storage classes are
- // redeclared as entry point parameters with a pointer type.
- auto attributes = ctx.Clone(var->Declaration()->attributes);
- attributes.push_back(
- ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter));
- attributes.push_back(
- ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
-
- auto* param_type = store_type();
- if (auto* arr = ty->As<sem::Array>(); arr && arr->IsRuntimeSized()) {
- // Wrap runtime-sized arrays in structures, so that we can declare
- // pointers to them. Ideally we'd just emit the array itself as a
- // pointer, but this is not representable in Tint's AST.
- CloneStructTypes(ty);
- auto* wrapper = ctx.dst->Structure(
- ctx.dst->Sym(),
- {ctx.dst->Member(kWrappedArrayMemberName, param_type)});
- param_type = ctx.dst->ty.Of(wrapper);
- is_wrapped = true;
+ // Check if this is a private variable that is only referenced by this function.
+ bool local_private = false;
+ if (var->StorageClass() == ast::StorageClass::kPrivate) {
+ local_private = true;
+ for (auto* user : var->Users()) {
+ auto* stmt = user->Stmt();
+ if (!stmt || stmt->Function() != func_sem) {
+ local_private = false;
+ break;
}
-
- param_type = ctx.dst->ty.pointer(param_type, sc,
- var->Declaration()->declared_access);
- auto* param = ctx.dst->Param(new_var_symbol, param_type, attributes);
- ctx.InsertFront(func_ast->params, param);
- is_pointer = true;
- } else if (sc == ast::StorageClass::kWorkgroup && ContainsMatrix(var->Type())) {
- // Due to a bug in the MSL compiler, we use a threadgroup memory
- // argument for any workgroup allocation that contains a matrix.
- // See crbug.com/tint/938.
- // TODO(jrprice): Do this for all other workgroup variables too.
-
- // Create a member in the workgroup parameter struct.
- auto member = ctx.Clone(var->Declaration()->symbol);
- workgroup_parameter_members.push_back(
- ctx.dst->Member(member, store_type()));
- CloneStructTypes(var->Type()->UnwrapRef());
-
- // Create a function-scope variable that is a pointer to the member.
- auto* member_ptr = ctx.dst->AddressOf(
- ctx.dst->MemberAccessor(ctx.dst->Deref(workgroup_param()), member));
- auto* local_var = ctx.dst->Let(
- new_var_symbol,
- ctx.dst->ty.pointer(store_type(), ast::StorageClass::kWorkgroup),
- member_ptr);
- ctx.InsertFront(func_ast->body->statements, ctx.dst->Decl(local_var));
- is_pointer = true;
- } else {
- // Variables in the Private and Workgroup storage classes are
- // redeclared at function scope. Disable storage class validation on
- // this variable.
- auto* disable_validation =
- ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass);
- auto* constructor = ctx.Clone(var->Declaration()->constructor);
- auto* local_var =
- ctx.dst->Var(new_var_symbol, store_type(), sc, constructor,
- ast::AttributeList{disable_validation});
- ctx.InsertFront(func_ast->body->statements, ctx.dst->Decl(local_var));
- }
- } else {
- // For a regular function, redeclare the variable as a parameter.
- // Use a pointer for non-handle types.
- auto* param_type = store_type();
- ast::AttributeList attributes;
- if (!var->Type()->UnwrapRef()->is_handle()) {
- param_type = ctx.dst->ty.pointer(param_type, sc,
- var->Declaration()->declared_access);
- is_pointer = true;
-
- // Disable validation of the parameter's storage class and of
- // arguments passed it.
- attributes.push_back(
- ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
- attributes.push_back(ctx.dst->Disable(
- ast::DisabledValidation::kIgnoreInvalidPointerArgument));
}
- ctx.InsertBack(func_ast->params,
- ctx.dst->Param(new_var_symbol, param_type, attributes));
}
- // Replace all uses of the module-scope variable.
- // For non-entry points, dereference non-handle pointer parameters.
- for (auto* user : var->Users()) {
- if (user->Stmt()->Function()->Declaration() == func_ast) {
- const ast::Expression* expr = ctx.dst->Expr(new_var_symbol);
- if (is_pointer) {
- // If this identifier is used by an address-of operator, just
- // remove the address-of instead of adding a deref, since we
- // already have a pointer.
- auto* ident = user->Declaration()->As<ast::IdentifierExpression>();
- if (ident_to_address_of.count(ident)) {
- ctx.Replace(ident_to_address_of[ident], expr);
- continue;
- }
-
- expr = ctx.dst->Deref(expr);
- }
- if (is_wrapped) {
- // Get the member from the wrapper structure.
- expr = ctx.dst->MemberAccessor(expr, kWrappedArrayMemberName);
- }
- ctx.Replace(user->Declaration(), expr);
+ if (local_private) {
+ // Redeclare the variable at function scope.
+ auto* disable_validation =
+ ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass);
+ auto* constructor = ctx.Clone(var->Declaration()->constructor);
+ auto* local_var = ctx.dst->Var(new_var_symbol,
+ CreateASTTypeFor(ctx, var->Type()->UnwrapRef()),
+ ast::StorageClass::kPrivate, constructor,
+ utils::Vector{disable_validation});
+ ctx.InsertFront(func_ast->body->statements, ctx.dst->Decl(local_var));
+ local_private_vars_.insert(var);
+ } else {
+ // Process the variable to redeclare it as a parameter or local variable.
+ if (is_entry_point) {
+ ProcessVariableInEntryPoint(func_ast, var, new_var_symbol, workgroup_param,
+ workgroup_parameter_members, is_pointer,
+ is_wrapped);
+ } else {
+ ProcessVariableInUserFunction(func_ast, var, new_var_symbol, is_pointer);
}
+
+ // Record the replacement symbol.
+ var_to_newvar[var] = {new_var_symbol, is_pointer, is_wrapped};
}
- var_to_newvar[var] = {new_var_symbol, is_pointer, is_wrapped};
+ // Replace all uses of the module-scope variable.
+ ReplaceUsesInFunction(func_ast, var, new_var_symbol, is_pointer, is_wrapped);
}
- if (!workgroup_parameter_members.empty()) {
+ if (!workgroup_parameter_members.IsEmpty()) {
// Create the workgroup memory parameter.
- // The parameter is a struct that contains members for each workgroup
- // variable.
+ // The parameter is a struct that contains members for each workgroup variable.
auto* str =
ctx.dst->Structure(ctx.dst->Sym(), std::move(workgroup_parameter_members));
auto* param_type =
ctx.dst->ty.pointer(ctx.dst->ty.Of(str), ast::StorageClass::kWorkgroup);
auto* disable_validation =
ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
- auto* param = ctx.dst->Param(workgroup_param(), param_type, {disable_validation});
+ auto* param = ctx.dst->Param(workgroup_param(), param_type,
+ utils::Vector{disable_validation});
ctx.InsertFront(func_ast->params, param);
}
@@ -328,12 +452,18 @@ struct ModuleScopeVarToEntryPointParam::State {
continue;
}
- auto new_var = var_to_newvar[target_var];
+ auto it = var_to_newvar.find(target_var);
+ if (it == var_to_newvar.end()) {
+ // No replacement was created for this function.
+ continue;
+ }
+
+ auto new_var = it->second;
bool is_handle = target_var->Type()->UnwrapRef()->is_handle();
const ast::Expression* arg = ctx.dst->Expr(new_var.symbol);
if (new_var.is_wrapped) {
- // The variable is wrapped in a struct, so we need to pass a pointer
- // to the struct member instead.
+ // The variable is wrapped in a struct, so we need to pass a pointer to the
+ // struct member instead.
arg = ctx.dst->AddressOf(
ctx.dst->MemberAccessor(ctx.dst->Deref(arg), kWrappedArrayMemberName));
} else if (is_entry_point && !is_handle && !new_var.is_pointer) {
@@ -356,7 +486,15 @@ struct ModuleScopeVarToEntryPointParam::State {
}
private:
+ // The structures that have already been cloned by this transform.
std::unordered_set<const sem::Struct*> cloned_structs_;
+
+ // Set of a private variables that are local to a single function.
+ std::unordered_set<const sem::Variable*> local_private_vars_;
+
+ // Map from identifier expression to the address-of expression that uses it.
+ std::unordered_map<const ast::IdentifierExpression*, const ast::UnaryOpExpression*>
+ ident_to_address_of_;
};
ModuleScopeVarToEntryPointParam::ModuleScopeVarToEntryPointParam() = default;
diff --git a/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.h b/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.h
index e3a50f40135..40e6b7da6e0 100644
--- a/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.h
+++ b/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param.h
@@ -61,7 +61,7 @@ namespace tint::transform {
/// foo(&p, sptr);
/// }
/// ```
-class ModuleScopeVarToEntryPointParam
+class ModuleScopeVarToEntryPointParam final
: public Castable<ModuleScopeVarToEntryPointParam, Transform> {
public:
/// Constructor
diff --git a/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param_test.cc b/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
index 9e81d318bdc..dcf89126e53 100644
--- a/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
@@ -95,9 +95,14 @@ var<workgroup> w : f32;
fn no_uses() {
}
+fn zoo() {
+ p = p * 2.0;
+}
+
fn bar(a : f32, b : f32) {
p = a;
w = b;
+ zoo();
}
fn foo(a : f32) {
@@ -116,22 +121,27 @@ fn main() {
fn no_uses() {
}
-fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<workgroup, f32>) {
- *(tint_symbol) = a;
- *(tint_symbol_1) = b;
+fn zoo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<private, f32>) {
+ *(tint_symbol) = (*(tint_symbol) * 2.0);
+}
+
+fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<workgroup, f32>) {
+ *(tint_symbol_1) = a;
+ *(tint_symbol_2) = b;
+ zoo(tint_symbol_1);
}
-fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<workgroup, f32>) {
+fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_4 : ptr<workgroup, f32>) {
let b : f32 = 2.0;
- bar(a, b, tint_symbol_2, tint_symbol_3);
+ bar(a, b, tint_symbol_3, tint_symbol_4);
no_uses();
}
@compute @workgroup_size(1)
fn main() {
- @internal(disable_validation__ignore_storage_class) var<private> tint_symbol_4 : f32;
- @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_5 : f32;
- foo(1.0, &(tint_symbol_4), &(tint_symbol_5));
+ @internal(disable_validation__ignore_storage_class) var<private> tint_symbol_5 : f32;
+ @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_6 : f32;
+ foo(1.0, &(tint_symbol_5), &(tint_symbol_6));
}
)";
@@ -159,6 +169,11 @@ fn no_uses() {
fn bar(a : f32, b : f32) {
p = a;
w = b;
+ zoo();
+}
+
+fn zoo() {
+ p = p * 2.0;
}
var<private> p : f32;
@@ -168,23 +183,28 @@ var<workgroup> w : f32;
auto* expect = R"(
@compute @workgroup_size(1)
fn main() {
- @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
- @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_1 : f32;
- foo(1.0, &(tint_symbol), &(tint_symbol_1));
+ @internal(disable_validation__ignore_storage_class) var<private> tint_symbol_5 : f32;
+ @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_6 : f32;
+ foo(1.0, &(tint_symbol_5), &(tint_symbol_6));
}
-fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<workgroup, f32>) {
+fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_4 : ptr<workgroup, f32>) {
let b : f32 = 2.0;
- bar(a, b, tint_symbol_2, tint_symbol_3);
+ bar(a, b, tint_symbol_3, tint_symbol_4);
no_uses();
}
fn no_uses() {
}
-fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_4 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_5 : ptr<workgroup, f32>) {
- *(tint_symbol_4) = a;
- *(tint_symbol_5) = b;
+fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<workgroup, f32>) {
+ *(tint_symbol_1) = a;
+ *(tint_symbol_2) = b;
+ zoo(tint_symbol_1);
+}
+
+fn zoo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<private, f32>) {
+ *(tint_symbol) = (*(tint_symbol) * 2.0);
}
)";
@@ -307,9 +327,9 @@ fn main() {
TEST_F(ModuleScopeVarToEntryPointParamTest, FoldAddressOfDeref) {
auto* src = R"(
-var<private> v : f32;
+var<workgroup> v : f32;
-fn bar(p : ptr<private, f32>) {
+fn bar(p : ptr<workgroup, f32>) {
(*p) = 0.0;
}
@@ -324,17 +344,17 @@ fn main() {
)";
auto* expect = R"(
-fn bar(p : ptr<private, f32>) {
+fn bar(p : ptr<workgroup, f32>) {
*(p) = 0.0;
}
-fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<private, f32>) {
+fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<workgroup, f32>) {
bar(tint_symbol);
}
@compute @workgroup_size(1)
fn main() {
- @internal(disable_validation__ignore_storage_class) var<private> tint_symbol_1 : f32;
+ @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_1 : f32;
foo(&(tint_symbol_1));
}
)";
@@ -355,25 +375,25 @@ fn foo() {
bar(&v);
}
-fn bar(p : ptr<private, f32>) {
+fn bar(p : ptr<workgroup, f32>) {
(*p) = 0.0;
}
-var<private> v : f32;
+var<workgroup> v : f32;
)";
auto* expect = R"(
@compute @workgroup_size(1)
fn main() {
- @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
- foo(&(tint_symbol));
+ @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_1 : f32;
+ foo(&(tint_symbol_1));
}
-fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<private, f32>) {
- bar(tint_symbol_1);
+fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<workgroup, f32>) {
+ bar(tint_symbol);
}
-fn bar(p : ptr<private, f32>) {
+fn bar(p : ptr<workgroup, f32>) {
*(p) = 0.0;
}
)";
@@ -556,17 +576,17 @@ fn foo() {
)";
auto* expect = R"(
-struct tint_symbol_1 {
+struct tint_symbol_2 {
arr : array<f32>,
}
@compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<storage, tint_symbol_1>) {
- foo(&((*(tint_symbol)).arr));
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_1 : ptr<storage, tint_symbol_2>) {
+ foo(&((*(tint_symbol_1)).arr));
}
-fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<storage, array<f32>>) {
- _ = (*(tint_symbol_2))[0];
+fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<storage, array<f32>>) {
+ _ = (*(tint_symbol))[0];
}
)";
@@ -802,8 +822,8 @@ var<storage> s : S;
auto* expect = R"(
@compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_1 : ptr<storage, S>) {
- foo(1.0, tint_symbol, tint_symbol_1);
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_4 : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_5 : ptr<storage, S>) {
+ foo(1.0, tint_symbol_4, tint_symbol_5);
}
fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<uniform, S>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<storage, S>) {
@@ -816,9 +836,9 @@ fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(di
fn no_uses() {
}
-fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_4 : ptr<uniform, S>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_5 : ptr<storage, S>) {
- _ = *(tint_symbol_4);
- _ = *(tint_symbol_5);
+fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<uniform, S>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<storage, S>) {
+ _ = *(tint_symbol);
+ _ = *(tint_symbol_1);
}
struct S {
@@ -937,8 +957,8 @@ fn bar(a : f32, b : f32) {
auto* expect = R"(
@compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) tint_symbol : texture_2d<f32>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) tint_symbol_1 : sampler) {
- foo(1.0, tint_symbol, tint_symbol_1);
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) tint_symbol_4 : texture_2d<f32>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) tint_symbol_5 : sampler) {
+ foo(1.0, tint_symbol_4, tint_symbol_5);
}
fn foo(a : f32, tint_symbol_2 : texture_2d<f32>, tint_symbol_3 : sampler) {
@@ -951,9 +971,9 @@ fn foo(a : f32, tint_symbol_2 : texture_2d<f32>, tint_symbol_3 : sampler) {
fn no_uses() {
}
-fn bar(a : f32, b : f32, tint_symbol_4 : texture_2d<f32>, tint_symbol_5 : sampler) {
- _ = tint_symbol_4;
- _ = tint_symbol_5;
+fn bar(a : f32, b : f32, tint_symbol : texture_2d<f32>, tint_symbol_1 : sampler) {
+ _ = tint_symbol;
+ _ = tint_symbol_1;
}
)";
@@ -1152,6 +1172,81 @@ fn main() {
EXPECT_EQ(expect, str(got));
}
+// Test that a private variable that is only referenced by a single user-defined function is
+// promoted to a function scope variable, rather than passed as a parameter.
+TEST_F(ModuleScopeVarToEntryPointParamTest, PromotePrivateToFunctionScope) {
+ auto* src = R"(
+var<private> p : f32;
+
+fn foo(a : f32) -> f32 {
+ let x = p;
+ p = x * a;
+ return p;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ _ = foo(1.0);
+}
+)";
+
+ auto* expect = R"(
+fn foo(a : f32) -> f32 {
+ @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
+ let x = tint_symbol;
+ tint_symbol = (x * a);
+ return tint_symbol;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ _ = foo(1.0);
+}
+)";
+
+ auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+// Test that a private variable that is only referenced by a single user-defined function is
+// promoted to a function scope variable, rather than passed as a parameter.
+TEST_F(ModuleScopeVarToEntryPointParamTest, PromotePrivateToFunctionScope_OutOfOrder) {
+ auto* src = R"(
+var<private> p : f32;
+
+@compute @workgroup_size(1)
+fn main() {
+ _ = foo(1.0);
+}
+
+fn foo(a : f32) -> f32 {
+ let x = p;
+ p = x * a;
+ return p;
+}
+
+)";
+
+ auto* expect = R"(
+@compute @workgroup_size(1)
+fn main() {
+ _ = foo(1.0);
+}
+
+fn foo(a : f32) -> f32 {
+ @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
+ let x = tint_symbol;
+ tint_symbol = (x * a);
+ return tint_symbol;
+}
+)";
+
+ auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(ModuleScopeVarToEntryPointParamTest, EmtpyModule) {
auto* src = "";
diff --git a/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.cc b/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.cc
index 2a9e20e9a08..f68a16514b2 100644
--- a/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.cc
+++ b/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.cc
@@ -86,8 +86,8 @@ struct MultiplanarExternalTexture::State {
// binding and create two additional bindings (one texture_2d<f32> to
// represent the secondary plane and one uniform buffer for the
// ExternalTextureParams struct).
- for (auto* var : ctx.src->AST().GlobalVariables()) {
- auto* sem_var = sem.Get(var);
+ for (auto* global : ctx.src->AST().GlobalVariables()) {
+ auto* sem_var = sem.Get(global);
if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
continue;
}
@@ -95,7 +95,7 @@ struct MultiplanarExternalTexture::State {
// If the attributes are empty, then this must be a texture_external
// passed as a function parameter. These variables are transformed
// elsewhere.
- if (var->attributes.empty()) {
+ if (global->attributes.IsEmpty()) {
continue;
}
@@ -109,8 +109,8 @@ struct MultiplanarExternalTexture::State {
// provided to this transform. We fetch the new binding points by
// providing the original texture_external binding points into the
// passed map.
- BindingPoint bp = {var->BindingPoint().group->value,
- var->BindingPoint().binding->value};
+ BindingPoint bp = {global->BindingPoint().group->value,
+ global->BindingPoint().binding->value};
BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
if (it == new_binding_points->bindings_map.end()) {
@@ -129,24 +129,24 @@ struct MultiplanarExternalTexture::State {
// corresponds with the new destination bindings.
// NewBindingSymbols new_binding_syms;
auto& syms = new_binding_symbols[sem_var];
- syms.plane_0 = ctx.Clone(var->symbol);
+ syms.plane_0 = ctx.Clone(global->symbol);
syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
- b.Global(syms.plane_1, b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
- b.GroupAndBinding(bps.plane_1.group, bps.plane_1.binding));
+ b.GlobalVar(syms.plane_1, b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
+ b.GroupAndBinding(bps.plane_1.group, bps.plane_1.binding));
syms.params = b.Symbols().New("ext_tex_params");
- b.Global(syms.params, b.ty.type_name("ExternalTextureParams"),
- ast::StorageClass::kUniform,
- b.GroupAndBinding(bps.params.group, bps.params.binding));
+ b.GlobalVar(syms.params, b.ty.type_name("ExternalTextureParams"),
+ ast::StorageClass::kUniform,
+ b.GroupAndBinding(bps.params.group, bps.params.binding));
// Replace the original texture_external binding with a texture_2d<f32>
// binding.
- ast::AttributeList cloned_attributes = ctx.Clone(var->attributes);
- const ast::Expression* cloned_constructor = ctx.Clone(var->constructor);
+ auto cloned_attributes = ctx.Clone(global->attributes);
+ const ast::Expression* cloned_constructor = ctx.Clone(global->constructor);
auto* replacement =
b.Var(syms.plane_0, b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
cloned_constructor, cloned_attributes);
- ctx.Replace(var, replacement);
+ ctx.Replace(global, replacement);
}
// We must update all the texture_external parameters for user declared
@@ -187,7 +187,7 @@ struct MultiplanarExternalTexture::State {
auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>();
auto* builtin = call->Target()->As<sem::Builtin>();
- if (builtin && !builtin->Parameters().empty() &&
+ if (builtin && !builtin->Parameters().IsEmpty() &&
builtin->Parameters()[0]->Type()->Is<sem::ExternalTexture>() &&
builtin->Type() != sem::BuiltinType::kTextureDimensions) {
if (auto* var_user = sem.Get<sem::VariableUser>(expr->args[0])) {
@@ -239,7 +239,7 @@ struct MultiplanarExternalTexture::State {
/// Creates the parameter structs associated with the transform.
void createExtTexParamsStructs() {
// Create GammaTransferParams struct.
- ast::StructMemberList gamma_transfer_member_list = {
+ utils::Vector gamma_transfer_member_list{
b.Member("G", b.ty.f32()), b.Member("A", b.ty.f32()), b.Member("B", b.ty.f32()),
b.Member("C", b.ty.f32()), b.Member("D", b.ty.f32()), b.Member("E", b.ty.f32()),
b.Member("F", b.ty.f32()), b.Member("padding", b.ty.u32())};
@@ -249,8 +249,9 @@ struct MultiplanarExternalTexture::State {
b.Structure(gamma_transfer_struct_sym, gamma_transfer_member_list);
// Create ExternalTextureParams struct.
- ast::StructMemberList ext_tex_params_member_list = {
+ utils::Vector ext_tex_params_member_list{
b.Member("numPlanes", b.ty.u32()),
+ b.Member("doYuvToRgbConversionOnly", b.ty.u32()),
b.Member("yuvToRgbConversionMatrix", b.ty.mat3x4(b.ty.f32())),
b.Member("gammaDecodeParams", b.ty.type_name("GammaTransferParams")),
b.Member("gammaEncodeParams", b.ty.type_name("GammaTransferParams")),
@@ -264,42 +265,45 @@ struct MultiplanarExternalTexture::State {
/// Creates the gammaCorrection function if needed and returns a call
/// expression to it.
void createGammaCorrectionFn() {
- ast::VariableList varList = {b.Param("v", b.ty.vec3<f32>()),
- b.Param("params", b.ty.type_name(gamma_transfer_struct_sym))};
-
- ast::StatementList statementList = {
- // let cond = abs(v) < vec3(params.D);
- b.Decl(b.Let(
- "cond", nullptr,
- b.LessThan(b.Call("abs", "v"), b.vec3<f32>(b.MemberAccessor("params", "D"))))),
- // let t = sign(v) * ((params.C * abs(v)) + params.F);
- b.Decl(b.Let("t", nullptr,
- b.Mul(b.Call("sign", "v"),
- b.Add(b.Mul(b.MemberAccessor("params", "C"), b.Call("abs", "v")),
- b.MemberAccessor("params", "F"))))),
- // let f = (sign(v) * pow(((params.A * abs(v)) + params.B),
- // vec3(params.G))) + params.E;
- b.Decl(b.Let(
- "f", nullptr,
- b.Mul(b.Call("sign", "v"),
- b.Add(b.Call("pow",
- b.Add(b.Mul(b.MemberAccessor("params", "A"), b.Call("abs", "v")),
- b.MemberAccessor("params", "B")),
- b.vec3<f32>(b.MemberAccessor("params", "G"))),
- b.MemberAccessor("params", "E"))))),
- // return select(f, t, cond);
- b.Return(b.Call("select", "f", "t", "cond"))};
-
gamma_correction_sym = b.Symbols().New("gammaCorrection");
- b.Func(gamma_correction_sym, varList, b.ty.vec3<f32>(), statementList, {});
+ b.Func(
+ gamma_correction_sym,
+ utils::Vector{
+ b.Param("v", b.ty.vec3<f32>()),
+ b.Param("params", b.ty.type_name(gamma_transfer_struct_sym)),
+ },
+ b.ty.vec3<f32>(),
+ utils::Vector{
+ // let cond = abs(v) < vec3(params.D);
+ b.Decl(b.Let(
+ "cond", nullptr,
+ b.LessThan(b.Call("abs", "v"), b.vec3<f32>(b.MemberAccessor("params", "D"))))),
+ // let t = sign(v) * ((params.C * abs(v)) + params.F);
+ b.Decl(b.Let("t", nullptr,
+ b.Mul(b.Call("sign", "v"),
+ b.Add(b.Mul(b.MemberAccessor("params", "C"), b.Call("abs", "v")),
+ b.MemberAccessor("params", "F"))))),
+ // let f = (sign(v) * pow(((params.A * abs(v)) + params.B),
+ // vec3(params.G))) + params.E;
+ b.Decl(b.Let("f", nullptr,
+ b.Mul(b.Call("sign", "v"),
+ b.Add(b.Call("pow",
+ b.Add(b.Mul(b.MemberAccessor("params", "A"),
+ b.Call("abs", "v")),
+ b.MemberAccessor("params", "B")),
+ b.vec3<f32>(b.MemberAccessor("params", "G"))),
+ b.MemberAccessor("params", "E"))))),
+ // return select(f, t, cond);
+ b.Return(b.Call("select", "f", "t", "cond")),
+ });
}
/// Constructs a StatementList containing all the statements making up the
/// bodies of the textureSampleExternal and textureLoadExternal functions.
/// @param call_type determines which function body to generate
/// @returns a statement list that makes of the body of the chosen function
- ast::StatementList createTexFnExtStatementList(sem::BuiltinType call_type) {
+ auto createTexFnExtStatementList(sem::BuiltinType call_type) {
const ast::CallExpression* single_plane_call = nullptr;
const ast::CallExpression* plane_0_call = nullptr;
const ast::CallExpression* plane_1_call = nullptr;
@@ -321,7 +325,7 @@ struct MultiplanarExternalTexture::State {
TINT_ICE(Transform, b.Diagnostics()) << "unhandled builtin: " << call_type;
}
- return {
+ return utils::Vector{
// var color: vec3<f32>;
b.Decl(b.Var("color", b.ty.vec3(b.ty.f32()))),
// if ((params.numPlanes == 1u))
@@ -337,14 +341,20 @@ struct MultiplanarExternalTexture::State {
b.Mul(b.vec4<f32>(b.MemberAccessor(plane_0_call, "r"),
b.MemberAccessor(plane_1_call, "rg"), 1_f),
b.MemberAccessor("params", "yuvToRgbConversionMatrix")))))),
- // color = gammaConversion(color, gammaDecodeParams);
- b.Assign("color", b.Call("gammaCorrection", "color",
- b.MemberAccessor("params", "gammaDecodeParams"))),
- // color = (params.gamutConversionMatrix * color);
- b.Assign("color", b.Mul(b.MemberAccessor("params", "gamutConversionMatrix"), "color")),
- // color = gammaConversion(color, gammaEncodeParams);
- b.Assign("color", b.Call("gammaCorrection", "color",
- b.MemberAccessor("params", "gammaEncodeParams"))),
+ // if (params.doYuvToRgbConversionOnly == 0u)
+ b.If(b.create<ast::BinaryExpression>(
+ ast::BinaryOp::kEqual, b.MemberAccessor("params", "doYuvToRgbConversionOnly"),
+ b.Expr(0_u)),
+ b.Block(
+ // color = gammaConversion(color, gammaDecodeParams);
+ b.Assign("color", b.Call("gammaCorrection", "color",
+ b.MemberAccessor("params", "gammaDecodeParams"))),
+ // color = (params.gamutConversionMatrix * color);
+ b.Assign("color",
+ b.Mul(b.MemberAccessor("params", "gamutConversionMatrix"), "color")),
+ // color = gammaConversion(color, gammaEncodeParams);
+ b.Assign("color", b.Call("gammaCorrection", "color",
+ b.MemberAccessor("params", "gammaEncodeParams"))))),
// return vec4<f32>(color, 1.f);
b.Return(b.vec4<f32>("color", 1_f))};
}
@@ -356,13 +366,12 @@ struct MultiplanarExternalTexture::State {
/// @returns a call expression to textureSampleExternal
const ast::CallExpression* createTexSmpExt(const ast::CallExpression* expr,
NewBindingSymbols syms) {
- ast::ExpressionList params;
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
- if (expr->args.size() != 3) {
+ if (expr->args.Length() != 3) {
TINT_ICE(Transform, b.Diagnostics()) << "expected textureSampleLevel call with a "
"texture_external to have 3 parameters, found "
- << expr->args.size() << " parameters";
+ << expr->args.Length() << " parameters";
}
// TextureSampleExternal calls the gammaCorrection function, so ensure it
@@ -375,23 +384,29 @@ struct MultiplanarExternalTexture::State {
texture_sample_external_sym = b.Symbols().New("textureSampleExternal");
// Emit the textureSampleExternal function.
- ast::VariableList varList = {
- b.Param("plane0", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
- b.Param("plane1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
- b.Param("smp", b.ty.sampler(ast::SamplerKind::kSampler)),
- b.Param("coord", b.ty.vec2(b.ty.f32())),
- b.Param("params", b.ty.type_name(params_struct_sym))};
-
- ast::StatementList statementList =
- createTexFnExtStatementList(sem::BuiltinType::kTextureSampleLevel);
-
- b.Func(texture_sample_external_sym, varList, b.ty.vec4(b.ty.f32()), statementList, {});
+ b.Func(
+ texture_sample_external_sym,
+ utils::Vector{
+ b.Param("plane0", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+ b.Param("plane1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+ b.Param("smp", b.ty.sampler(ast::SamplerKind::kSampler)),
+ b.Param("coord", b.ty.vec2(b.ty.f32())),
+ b.Param("params", b.ty.type_name(params_struct_sym)),
+ },
+ b.ty.vec4(b.ty.f32()),
+ utils::Vector{
+ createTexFnExtStatementList(sem::BuiltinType::kTextureSampleLevel),
+ });
}
const ast::IdentifierExpression* exp = b.Expr(texture_sample_external_sym);
- params = {plane_0_binding_param, b.Expr(syms.plane_1), ctx.Clone(expr->args[1]),
- ctx.Clone(expr->args[2]), b.Expr(syms.params)};
- return b.Call(exp, params);
+ return b.Call(exp, utils::Vector{
+ plane_0_binding_param,
+ b.Expr(syms.plane_1),
+ ctx.Clone(expr->args[1]),
+ ctx.Clone(expr->args[2]),
+ b.Expr(syms.params),
+ });
}
/// Creates the textureLoadExternal function if needed and returns a call
@@ -401,14 +416,13 @@ struct MultiplanarExternalTexture::State {
/// @returns a call expression to textureLoadExternal
const ast::CallExpression* createTexLdExt(const ast::CallExpression* expr,
NewBindingSymbols syms) {
- ast::ExpressionList params;
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
- if (expr->args.size() != 2) {
+ if (expr->args.Length() != 2) {
TINT_ICE(Transform, b.Diagnostics())
<< "expected textureLoad call with a texture_external "
"to have 2 parameters, found "
- << expr->args.size() << " parameters";
+ << expr->args.Length() << " parameters";
}
// TextureLoadExternal calls the gammaCorrection function, so ensure it
@@ -421,22 +435,22 @@ struct MultiplanarExternalTexture::State {
texture_load_external_sym = b.Symbols().New("textureLoadExternal");
// Emit the textureLoadExternal function.
- ast::VariableList var_list = {
- b.Param("plane0", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
- b.Param("plane1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
- b.Param("coord", b.ty.vec2(b.ty.i32())),
- b.Param("params", b.ty.type_name(params_struct_sym))};
-
- ast::StatementList statement_list =
- createTexFnExtStatementList(sem::BuiltinType::kTextureLoad);
-
- b.Func(texture_load_external_sym, var_list, b.ty.vec4(b.ty.f32()), statement_list, {});
+ b.Func(
+ texture_load_external_sym,
+ utils::Vector{
+ b.Param("plane0", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+ b.Param("plane1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+ b.Param("coord", b.ty.vec2(b.ty.i32())),
+ b.Param("params", b.ty.type_name(params_struct_sym)),
+ },
+ b.ty.vec4(b.ty.f32()),
+ utils::Vector{
+ createTexFnExtStatementList(sem::BuiltinType::kTextureLoad),
+ });
}
- const ast::IdentifierExpression* exp = b.Expr(texture_load_external_sym);
- params = {plane_0_binding_param, b.Expr(syms.plane_1), ctx.Clone(expr->args[1]),
- b.Expr(syms.params)};
- return b.Call(exp, params);
+ return b.Call(texture_load_external_sym, plane_0_binding_param, syms.plane_1,
+ ctx.Clone(expr->args[1]), syms.params);
}
};
diff --git a/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.h b/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.h
index 88cbc981826..afd15a17017 100644
--- a/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.h
+++ b/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture.h
@@ -46,8 +46,11 @@ struct BindingPoints {
/// textureSampleLevel that contain a texture_external parameter will be
/// transformed into a newly generated version of the function, which can
/// perform the desired operation on a single RGBA plane or on seperate Y and UV
-/// planes.
-class MultiplanarExternalTexture : public Castable<MultiplanarExternalTexture, Transform> {
+/// planes, and do colorspace conversions including yuv->rgb conversion, gamma
+/// decoding, gamut conversion, and gamma encoding steps. Specifically
+// for BT.709 to SRGB conversion, it takes the fast path only doing the yuv->rgb
+// step and skipping all other steps.
+class MultiplanarExternalTexture final : public Castable<MultiplanarExternalTexture, Transform> {
public:
/// BindingsMap is a map where the key is the binding location of a
/// texture_external and the value is a struct containing the desired
@@ -57,7 +60,7 @@ class MultiplanarExternalTexture : public Castable<MultiplanarExternalTexture, T
/// NewBindingPoints is consumed by the MultiplanarExternalTexture transform.
/// Data holds information about location of each texture_external binding and
/// which binding slots it should expand into.
- struct NewBindingPoints : public Castable<Data, transform::Data> {
+ struct NewBindingPoints final : public Castable<Data, transform::Data> {
/// Constructor
/// @param bm a map to the new binding slots to use.
explicit NewBindingPoints(BindingsMap bm);
diff --git a/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture_test.cc b/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture_test.cc
index 63d12f1c21d..79f9fddef05 100644
--- a/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/multiplanar_external_texture_test.cc
@@ -118,6 +118,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -172,6 +173,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -225,6 +227,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -253,9 +256,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -298,6 +303,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -322,9 +328,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -370,6 +378,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -396,9 +405,11 @@ fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord
} else {
color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -440,6 +451,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -464,9 +476,11 @@ fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord
} else {
color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -512,6 +526,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -540,9 +555,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -553,9 +570,11 @@ fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord
} else {
color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -599,6 +618,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -623,9 +643,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -636,9 +658,11 @@ fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord
} else {
color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -688,6 +712,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -734,9 +759,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -788,6 +815,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -812,9 +840,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -870,6 +900,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -899,9 +930,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -952,6 +985,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -976,9 +1010,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -1036,6 +1072,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -1064,9 +1101,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -1129,6 +1168,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -1162,9 +1202,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -1223,6 +1265,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -1247,9 +1290,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -1313,6 +1358,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -1337,9 +1383,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -1391,6 +1439,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -1441,6 +1490,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -1467,9 +1517,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
@@ -1526,6 +1578,7 @@ struct GammaTransferParams {
struct ExternalTextureParams {
numPlanes : u32,
+ doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
@@ -1555,9 +1608,11 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
- color = gammaCorrection(color, params.gammaDecodeParams);
- color = (params.gamutConversionMatrix * color);
- color = gammaCorrection(color, params.gammaEncodeParams);
+ if ((params.doYuvToRgbConversionOnly == 0u)) {
+ color = gammaCorrection(color, params.gammaDecodeParams);
+ color = (params.gamutConversionMatrix * color);
+ color = gammaCorrection(color, params.gammaEncodeParams);
+ }
return vec4<f32>(color, 1.0f);
}
diff --git a/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.cc b/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.cc
index 0bb1518544d..b9476f23035 100644
--- a/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.cc
+++ b/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.cc
@@ -52,7 +52,7 @@ NumWorkgroupsFromUniform::~NumWorkgroupsFromUniform() = default;
bool NumWorkgroupsFromUniform::ShouldRun(const Program* program, const DataMap&) const {
for (auto* node : program->ASTNodes().Objects()) {
if (auto* attr = node->As<ast::BuiltinAttribute>()) {
- if (attr->builtin == ast::Builtin::kNumWorkgroups) {
+ if (attr->builtin == ast::BuiltinValue::kNumWorkgroups) {
return true;
}
}
@@ -89,7 +89,7 @@ void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, Dat
for (auto* member : str->Members()) {
auto* builtin =
ast::GetAttribute<ast::BuiltinAttribute>(member->Declaration()->attributes);
- if (!builtin || builtin->builtin != ast::Builtin::kNumWorkgroups) {
+ if (!builtin || builtin->builtin != ast::BuiltinValue::kNumWorkgroups) {
continue;
}
@@ -121,7 +121,9 @@ void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, Dat
if (!num_workgroups_ubo) {
auto* num_workgroups_struct = ctx.dst->Structure(
ctx.dst->Sym(),
- {ctx.dst->Member(kNumWorkgroupsMemberName, ctx.dst->ty.vec3(ctx.dst->ty.u32()))});
+ utils::Vector{
+ ctx.dst->Member(kNumWorkgroupsMemberName, ctx.dst->ty.vec3(ctx.dst->ty.u32())),
+ });
uint32_t group, binding;
if (cfg->ubo_binding.has_value()) {
@@ -133,8 +135,8 @@ void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, Dat
// plus 1, or group 0 if no resource bound.
group = 0;
- for (auto* var : ctx.src->AST().GlobalVariables()) {
- if (auto binding_point = var->BindingPoint()) {
+ for (auto* global : ctx.src->AST().GlobalVariables()) {
+ if (auto binding_point = global->BindingPoint()) {
if (binding_point.group->value >= group) {
group = binding_point.group->value + 1;
}
@@ -144,9 +146,9 @@ void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, Dat
binding = 0;
}
- num_workgroups_ubo = ctx.dst->Global(
+ num_workgroups_ubo = ctx.dst->GlobalVar(
ctx.dst->Sym(), ctx.dst->ty.Of(num_workgroups_struct), ast::StorageClass::kUniform,
- ast::AttributeList{ctx.dst->GroupAndBinding(group, binding)});
+ ctx.dst->GroupAndBinding(group, binding));
}
return num_workgroups_ubo;
};
diff --git a/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.h b/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.h
index 9f0b6c1a7e5..292c823bc49 100644
--- a/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.h
+++ b/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform.h
@@ -15,7 +15,7 @@
#ifndef SRC_TINT_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
#define SRC_TINT_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
-#include <optional> // NOLINT(build/include_order)
+#include <optional>
#include "src/tint/sem/binding_point.h"
#include "src/tint/transform/transform.h"
@@ -44,7 +44,7 @@ namespace tint::transform {
///
/// @note Depends on the following transforms to have been run first:
/// * CanonicalizeEntryPointIO
-class NumWorkgroupsFromUniform : public Castable<NumWorkgroupsFromUniform, Transform> {
+class NumWorkgroupsFromUniform final : public Castable<NumWorkgroupsFromUniform, Transform> {
public:
/// Constructor
NumWorkgroupsFromUniform();
@@ -52,7 +52,7 @@ class NumWorkgroupsFromUniform : public Castable<NumWorkgroupsFromUniform, Trans
~NumWorkgroupsFromUniform() override;
/// Configuration options for the NumWorkgroupsFromUniform transform.
- struct Config : public Castable<Data, transform::Data> {
+ struct Config final : public Castable<Data, transform::Data> {
/// Constructor
/// @param ubo_bp the binding point to use for the generated uniform buffer. If ubo_bp
/// contains no value, a free binding point will be used to ensure the generated program is
diff --git a/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform_test.cc b/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform_test.cc
index 8562c01d2a1..093081c6e70 100644
--- a/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/num_workgroups_from_uniform_test.cc
@@ -568,7 +568,7 @@ struct S1 {
@group(3) @binding(0) var g5 : texture_depth_cube_array;
@group(4) @binding(0) var g6 : texture_external;
-@group(0) @binding(1) var<storage, write> g8 : S0;
+@group(0) @binding(1) var<storage, read_write> g8 : S0;
@group(1) @binding(3) var<storage, read> g9 : S0;
@group(3) @binding(2) var<storage, read_write> g10 : S0;
@@ -634,7 +634,7 @@ struct S1 {
@group(4) @binding(0) var g6 : texture_external;
-@group(0) @binding(1) var<storage, write> g8 : S0;
+@group(0) @binding(1) var<storage, read_write> g8 : S0;
@group(1) @binding(3) var<storage, read> g9 : S0;
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var.cc b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var.cc
deleted file mode 100644
index 6e0ba55ccc0..00000000000
--- a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2022 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/transform/promote_initializers_to_const_var.h"
-#include "src/tint/program_builder.h"
-#include "src/tint/sem/call.h"
-#include "src/tint/sem/statement.h"
-#include "src/tint/sem/type_constructor.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteInitializersToConstVar);
-
-namespace tint::transform {
-
-PromoteInitializersToConstVar::PromoteInitializersToConstVar() = default;
-
-PromoteInitializersToConstVar::~PromoteInitializersToConstVar() = default;
-
-void PromoteInitializersToConstVar::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
- HoistToDeclBefore hoist_to_decl_before(ctx);
-
- // Hoists array and structure initializers to a constant variable, declared
- // just before the statement of usage.
- auto type_ctor_to_let = [&](const ast::CallExpression* expr) {
- auto* ctor = ctx.src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::Call>();
- if (!ctor->Target()->Is<sem::TypeConstructor>()) {
- return true;
- }
- auto* sem_stmt = ctor->Stmt();
- if (!sem_stmt) {
- // Expression is outside of a statement. This usually means the
- // expression is part of a global (module-scope) constant declaration.
- // These must be constexpr, and so cannot contain the type of
- // expressions that must be sanitized.
- return true;
- }
-
- auto* stmt = sem_stmt->Declaration();
-
- if (auto* src_var_decl = stmt->As<ast::VariableDeclStatement>()) {
- if (src_var_decl->variable->constructor == expr) {
- // This statement is just a variable declaration with the
- // initializer as the constructor value. This is what we're
- // attempting to transform to, and so ignore.
- return true;
- }
- }
-
- auto* src_ty = ctor->Type();
- if (!src_ty->IsAnyOf<sem::Array, sem::Struct>()) {
- // We only care about array and struct initializers
- return true;
- }
-
- return hoist_to_decl_before.Add(ctor, expr, true);
- };
-
- for (auto* node : ctx.src->ASTNodes().Objects()) {
- if (auto* call_expr = node->As<ast::CallExpression>()) {
- if (!type_ctor_to_let(call_expr)) {
- return;
- }
- }
- }
-
- hoist_to_decl_before.Apply();
- ctx.Clone();
-}
-
-} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var_test.cc b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var_test.cc
deleted file mode 100644
index f322478ce0c..00000000000
--- a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var_test.cc
+++ /dev/null
@@ -1,625 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/transform/promote_initializers_to_const_var.h"
-
-#include "src/tint/transform/test_helper.h"
-
-namespace tint::transform {
-namespace {
-
-using PromoteInitializersToConstVarTest = TransformTest;
-
-TEST_F(PromoteInitializersToConstVarTest, EmptyModule) {
- auto* src = "";
- auto* expect = "";
-
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, BasicArray) {
- auto* src = R"(
-fn f() {
- var f0 = 1.0;
- var f1 = 2.0;
- var f2 = 3.0;
- var f3 = 4.0;
- var i = array<f32, 4u>(f0, f1, f2, f3)[2];
-}
-)";
-
- auto* expect = R"(
-fn f() {
- var f0 = 1.0;
- var f1 = 2.0;
- var f2 = 3.0;
- var f3 = 4.0;
- let tint_symbol = array<f32, 4u>(f0, f1, f2, f3);
- var i = tint_symbol[2];
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, BasicStruct) {
- auto* src = R"(
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-};
-
-fn f() {
- var x = S(1, 2.0, vec3<f32>()).b;
-}
-)";
-
- auto* expect = R"(
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-}
-
-fn f() {
- let tint_symbol = S(1, 2.0, vec3<f32>());
- var x = tint_symbol.b;
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, BasicStruct_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var x = S(1, 2.0, vec3<f32>()).b;
-}
-
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-};
-)";
-
- auto* expect = R"(
-fn f() {
- let tint_symbol = S(1, 2.0, vec3<f32>());
- var x = tint_symbol.b;
-}
-
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopInit) {
- auto* src = R"(
-fn f() {
- var insert_after = 1;
- for(var i = array<f32, 4u>(0.0, 1.0, 2.0, 3.0)[2]; ; ) {
- break;
- }
-}
-)";
-
- auto* expect = R"(
-fn f() {
- var insert_after = 1;
- let tint_symbol = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
- for(var i = tint_symbol[2]; ; ) {
- break;
- }
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, StructInForLoopInit) {
- auto* src = R"(
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-};
-
-fn f() {
- var insert_after = 1;
- for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
- break;
- }
-}
-)";
-
- auto* expect = R"(
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-}
-
-fn f() {
- var insert_after = 1;
- let tint_symbol = S(1, 2.0, vec3<f32>());
- for(var x = tint_symbol.b; ; ) {
- break;
- }
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, StructInForLoopInit_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var insert_after = 1;
- for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
- break;
- }
-}
-
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-};
-)";
-
- auto* expect = R"(
-fn f() {
- var insert_after = 1;
- let tint_symbol = S(1, 2.0, vec3<f32>());
- for(var x = tint_symbol.b; ; ) {
- break;
- }
-}
-
-struct S {
- a : i32,
- b : f32,
- c : vec3<f32>,
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopCond) {
- auto* src = R"(
-fn f() {
- var f = 1.0;
- for(; f == array<f32, 1u>(f)[0]; f = f + 1.0) {
- var marker = 1;
- }
-}
-)";
-
- auto* expect = R"(
-fn f() {
- var f = 1.0;
- loop {
- let tint_symbol = array<f32, 1u>(f);
- if (!((f == tint_symbol[0]))) {
- break;
- }
- {
- var marker = 1;
- }
-
- continuing {
- f = (f + 1.0);
- }
- }
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopCont) {
- auto* src = R"(
-fn f() {
- var f = 0.0;
- for(; f < 10.0; f = f + array<f32, 1u>(1.0)[0]) {
- var marker = 1;
- }
-}
-)";
-
- auto* expect = R"(
-fn f() {
- var f = 0.0;
- loop {
- if (!((f < 10.0))) {
- break;
- }
- {
- var marker = 1;
- }
-
- continuing {
- let tint_symbol = array<f32, 1u>(1.0);
- f = (f + tint_symbol[0]);
- }
- }
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopInitCondCont) {
- auto* src = R"(
-fn f() {
- for(var f = array<f32, 1u>(0.0)[0];
- f < array<f32, 1u>(1.0)[0];
- f = f + array<f32, 1u>(2.0)[0]) {
- var marker = 1;
- }
-}
-)";
-
- auto* expect = R"(
-fn f() {
- let tint_symbol = array<f32, 1u>(0.0);
- {
- var f = tint_symbol[0];
- loop {
- let tint_symbol_1 = array<f32, 1u>(1.0);
- if (!((f < tint_symbol_1[0]))) {
- break;
- }
- {
- var marker = 1;
- }
-
- continuing {
- let tint_symbol_2 = array<f32, 1u>(2.0);
- f = (f + tint_symbol_2[0]);
- }
- }
- }
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, ArrayInElseIf) {
- auto* src = R"(
-fn f() {
- var f = 1.0;
- if (true) {
- var marker = 0;
- } else if (f == array<f32, 2u>(f, f)[0]) {
- var marker = 1;
- }
-}
-)";
-
- auto* expect = R"(
-fn f() {
- var f = 1.0;
- if (true) {
- var marker = 0;
- } else {
- let tint_symbol = array<f32, 2u>(f, f);
- if ((f == tint_symbol[0])) {
- var marker = 1;
- }
- }
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, ArrayInElseIfChain) {
- auto* src = R"(
-fn f() {
- var f = 1.0;
- if (true) {
- var marker = 0;
- } else if (true) {
- var marker = 1;
- } else if (f == array<f32, 2u>(f, f)[0]) {
- var marker = 2;
- } else if (f == array<f32, 2u>(f, f)[1]) {
- var marker = 3;
- } else if (true) {
- var marker = 4;
- } else {
- var marker = 5;
- }
-}
-)";
-
- auto* expect = R"(
-fn f() {
- var f = 1.0;
- if (true) {
- var marker = 0;
- } else if (true) {
- var marker = 1;
- } else {
- let tint_symbol = array<f32, 2u>(f, f);
- if ((f == tint_symbol[0])) {
- var marker = 2;
- } else {
- let tint_symbol_1 = array<f32, 2u>(f, f);
- if ((f == tint_symbol_1[1])) {
- var marker = 3;
- } else if (true) {
- var marker = 4;
- } else {
- var marker = 5;
- }
- }
- }
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, ArrayInArrayArray) {
- auto* src = R"(
-fn f() {
- var i = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0))[0][1];
-}
-)";
-
- auto* expect = R"(
-fn f() {
- let tint_symbol = array<f32, 2u>(1.0, 2.0);
- let tint_symbol_1 = array<f32, 2u>(3.0, 4.0);
- let tint_symbol_2 = array<array<f32, 2u>, 2u>(tint_symbol, tint_symbol_1);
- var i = tint_symbol_2[0][1];
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, StructNested) {
- auto* src = R"(
-struct S1 {
- a : i32,
-};
-
-struct S2 {
- a : i32,
- b : S1,
- c : i32,
-};
-
-struct S3 {
- a : S2,
-};
-
-fn f() {
- var x = S3(S2(1, S1(2), 3)).a.b.a;
-}
-)";
-
- auto* expect = R"(
-struct S1 {
- a : i32,
-}
-
-struct S2 {
- a : i32,
- b : S1,
- c : i32,
-}
-
-struct S3 {
- a : S2,
-}
-
-fn f() {
- let tint_symbol = S1(2);
- let tint_symbol_1 = S2(1, tint_symbol, 3);
- let tint_symbol_2 = S3(tint_symbol_1);
- var x = tint_symbol_2.a.b.a;
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, Mixed) {
- auto* src = R"(
-struct S1 {
- a : i32,
-};
-
-struct S2 {
- a : array<S1, 3u>,
-};
-
-fn f() {
- var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
-}
-)";
-
- auto* expect = R"(
-struct S1 {
- a : i32,
-}
-
-struct S2 {
- a : array<S1, 3u>,
-}
-
-fn f() {
- let tint_symbol = S1(1);
- let tint_symbol_1 = S1(2);
- let tint_symbol_2 = S1(3);
- let tint_symbol_3 = array<S1, 3u>(tint_symbol, tint_symbol_1, tint_symbol_2);
- let tint_symbol_4 = S2(tint_symbol_3);
- var x = tint_symbol_4.a[1].a;
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, Mixed_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
-}
-
-struct S2 {
- a : array<S1, 3u>,
-};
-
-struct S1 {
- a : i32,
-};
-)";
-
- auto* expect = R"(
-fn f() {
- let tint_symbol = S1(1);
- let tint_symbol_1 = S1(2);
- let tint_symbol_2 = S1(3);
- let tint_symbol_3 = array<S1, 3u>(tint_symbol, tint_symbol_1, tint_symbol_2);
- let tint_symbol_4 = S2(tint_symbol_3);
- var x = tint_symbol_4.a[1].a;
-}
-
-struct S2 {
- a : array<S1, 3u>,
-}
-
-struct S1 {
- a : i32,
-}
-)";
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl) {
- auto* src = R"(
-struct S {
- a : i32,
- b : f32,
- c : i32,
-}
-
-fn f() {
- var local_arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
- var local_str = S(1, 2.0, 3);
-}
-
-let module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
-
-let module_str : S = S(1, 2.0, 3);
-)";
-
- auto* expect = src;
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var local_arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
- var local_str = S(1, 2.0, 3);
-}
-
-let module_str : S = S(1, 2.0, 3);
-
-struct S {
- a : i32,
- b : f32,
- c : i32,
-}
-
-let module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
-)";
-
- auto* expect = src;
-
- DataMap data;
- auto got = Run<PromoteInitializersToConstVar>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-} // namespace
-} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.cc b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.cc
new file mode 100644
index 00000000000..ec7ba9523b9
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.cc
@@ -0,0 +1,109 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/promote_initializers_to_let.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/call.h"
+#include "src/tint/sem/statement.h"
+#include "src/tint/sem/type_constructor.h"
+#include "src/tint/transform/utils/hoist_to_decl_before.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteInitializersToLet);
+
+namespace tint::transform {
+
+PromoteInitializersToLet::PromoteInitializersToLet() = default;
+
+PromoteInitializersToLet::~PromoteInitializersToLet() = default;
+
+void PromoteInitializersToLet::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+ HoistToDeclBefore hoist_to_decl_before(ctx);
+
+ // Hoists array and structure initializers to a constant variable, declared
+ // just before the statement of usage.
+ auto promote = [&](const sem::Expression* expr) {
+ auto* sem_stmt = expr->Stmt();
+ if (!sem_stmt) {
+ // Expression is outside of a statement. This usually means the
+ // expression is part of a global (module-scope) constant declaration.
+ // These must be constexpr, and so cannot contain the type of
+ // expressions that must be sanitized.
+ return true;
+ }
+
+ auto* stmt = sem_stmt->Declaration();
+
+ if (auto* src_var_decl = stmt->As<ast::VariableDeclStatement>()) {
+ if (src_var_decl->variable->constructor == expr->Declaration()) {
+ // This statement is just a variable declaration with the
+ // initializer as the constructor value. This is what we're
+ // attempting to transform to, and so ignore.
+ return true;
+ }
+ }
+
+ auto* src_ty = expr->Type();
+ if (!src_ty->IsAnyOf<sem::Array, sem::Struct>()) {
+ // We only care about array and struct initializers
+ return true;
+ }
+
+ return hoist_to_decl_before.Add(expr, expr->Declaration(), true);
+ };
+
+ for (auto* node : ctx.src->ASTNodes().Objects()) {
+ bool ok = Switch(
+ node, //
+ [&](const ast::CallExpression* expr) {
+ if (auto* sem = ctx.src->Sem().Get(expr)) {
+ auto* ctor = sem->UnwrapMaterialize()->As<sem::Call>();
+ if (ctor->Target()->Is<sem::TypeConstructor>()) {
+ return promote(sem);
+ }
+ }
+ return true;
+ },
+ [&](const ast::IdentifierExpression* expr) {
+ if (auto* sem = ctx.src->Sem().Get(expr)) {
+ if (auto* user = sem->UnwrapMaterialize()->As<sem::VariableUser>()) {
+ // Identifier resolves to a variable
+ if (auto* stmt = user->Stmt()) {
+ if (auto* decl = stmt->Declaration()->As<ast::VariableDeclStatement>();
+ decl && decl->variable->Is<ast::Const>()) {
+ // The identifier is used on the RHS of a 'const' declaration.
+ // Ignore.
+ return true;
+ }
+ }
+ if (user->Variable()->Declaration()->Is<ast::Const>()) {
+ // The identifier resolves to a 'const' variable, but isn't used to
+ // initialize another 'const'. This needs promoting.
+ return promote(user);
+ }
+ }
+ }
+ return true;
+ },
+ [&](Default) { return true; });
+
+ if (!ok) {
+ return;
+ }
+ }
+
+ hoist_to_decl_before.Apply();
+ ctx.Clone();
+}
+
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.h b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.h
new file mode 100644
index 00000000000..226c7d83828
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let.h
@@ -0,0 +1,48 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
+#define SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
+
+#include "src/tint/transform/transform.h"
+
+namespace tint::transform {
+
+/// A transform that hoists array and structure constructors, and identifiers resolving to a
+/// 'const' array to a 'let' variable, declared just before the statement of usage.
+/// This transform is used by backends that do not support expressions that operate on an immediate
+/// array or structure. For example, the following is not immediately expressable for HLSL:
+/// `array<i32, 2>(1, 2)[0]`
+/// @see crbug.com/tint/406
+class PromoteInitializersToLet final : public Castable<PromoteInitializersToLet, Transform> {
+ public:
+ /// Constructor
+ PromoteInitializersToLet();
+
+ /// Destructor
+ ~PromoteInitializersToLet() override;
+
+ protected:
+ /// Runs the transform using the CloneContext built for transforming a
+ /// program. Run() is responsible for calling Clone() on the CloneContext.
+ /// @param ctx the CloneContext primed with the input program and
+ /// ProgramBuilder
+ /// @param inputs optional extra transform-specific input data
+ /// @param outputs optional extra transform-specific output data
+ void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
+};
+
+} // namespace tint::transform
+
+#endif // SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let_test.cc b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let_test.cc
new file mode 100644
index 00000000000..536d04a29e3
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_let_test.cc
@@ -0,0 +1,1256 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/promote_initializers_to_let.h"
+
+#include "src/tint/transform/test_helper.h"
+
+namespace tint::transform {
+namespace {
+
+using PromoteInitializersToLetTest = TransformTest;
+
+TEST_F(PromoteInitializersToLetTest, EmptyModule) {
+ auto* src = "";
+ auto* expect = "";
+
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, BasicArray) {
+ auto* src = R"(
+fn f() {
+ var f0 = 1.0;
+ var f1 = 2.0;
+ var f2 = 3.0;
+ var f3 = 4.0;
+ var i = array<f32, 4u>(f0, f1, f2, f3)[2];
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var f0 = 1.0;
+ var f1 = 2.0;
+ var f2 = 3.0;
+ var f3 = 4.0;
+ let tint_symbol = array<f32, 4u>(f0, f1, f2, f3);
+ var i = tint_symbol[2];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, BasicStruct) {
+ auto* src = R"(
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+};
+
+fn f() {
+ var x = S(1, 2.0, vec3<f32>()).b;
+}
+)";
+
+ auto* expect = R"(
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+}
+
+fn f() {
+ let tint_symbol = S(1, 2.0, vec3<f32>());
+ var x = tint_symbol.b;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, BasicStruct_OutOfOrder) {
+ auto* src = R"(
+fn f() {
+ var x = S(1, 2.0, vec3<f32>()).b;
+}
+
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+};
+)";
+
+ auto* expect = R"(
+fn f() {
+ let tint_symbol = S(1, 2.0, vec3<f32>());
+ var x = tint_symbol.b;
+}
+
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstBasicArray) {
+ auto* src = R"(
+const f0 = 1.0;
+
+const f1 = 2.0;
+
+const C = array<f32, 2u>(f0, f1);
+
+fn f() {
+ var f0 = 100.0;
+ var f1 = 100.0;
+ var i = C[1];
+}
+)";
+
+ auto* expect = R"(
+const f0 = 1.0;
+
+const f1 = 2.0;
+
+const C = array<f32, 2u>(f0, f1);
+
+fn f() {
+ var f0 = 100.0;
+ var f1 = 100.0;
+ let tint_symbol = C;
+ var i = tint_symbol[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstArrayDynamicIndex) {
+ auto* src = R"(
+const TRI_VERTICES = array(
+ vec4(0., 0., 0., 1.),
+ vec4(0., 1., 0., 1.),
+ vec4(1., 1., 0., 1.),
+);
+
+@vertex
+fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
+ // note: TRI_VERTICES requires a materialize before the dynamic index.
+ return TRI_VERTICES[in_vertex_index];
+}
+)";
+
+ auto* expect = R"(
+const TRI_VERTICES = array(vec4(0.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), vec4(1.0, 1.0, 0.0, 1.0));
+
+@vertex
+fn vs_main(@builtin(vertex_index) in_vertex_index : u32) -> @builtin(position) vec4<f32> {
+ let tint_symbol = TRI_VERTICES;
+ return tint_symbol[in_vertex_index];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstBasicArray_OutOfOrder) {
+ auto* src = R"(
+fn f() {
+ var f0 = 100.0;
+ var f1 = 100.0;
+ var i = C[1];
+}
+
+const C = array<f32, 2u>(f0, f1);
+
+const f0 = 1.0;
+
+const f1 = 2.0;
+)";
+
+ auto* expect = R"(
+fn f() {
+ var f0 = 100.0;
+ var f1 = 100.0;
+ let tint_symbol = C;
+ var i = tint_symbol[1];
+}
+
+const C = array<f32, 2u>(f0, f1);
+
+const f0 = 1.0;
+
+const f1 = 2.0;
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, LocalConstBasicArray) {
+ auto* src = R"(
+fn f() {
+ const f0 = 1.0;
+ const f1 = 2.0;
+ const C = array<f32, 2u>(f0, f1);
+ var i = C[1];
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ const f0 = 1.0;
+ const f1 = 2.0;
+ const C = array<f32, 2u>(f0, f1);
+ let tint_symbol = C;
+ var i = tint_symbol[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ArrayInForLoopInit) {
+ auto* src = R"(
+fn f() {
+ var insert_after = 1;
+ for(var i = array<f32, 4u>(0.0, 1.0, 2.0, 3.0)[2]; ; ) {
+ break;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var insert_after = 1;
+ let tint_symbol = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+ for(var i = tint_symbol[2]; ; ) {
+ break;
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopInit) {
+ auto* src = R"(
+fn f() {
+ const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+ var insert_after = 1;
+ for(var i = arr[2]; ; ) {
+ break;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+ var insert_after = 1;
+ let tint_symbol = arr;
+ for(var i = tint_symbol[2]; ; ) {
+ break;
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopInit) {
+ auto* src = R"(
+const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+
+fn f() {
+ var insert_after = 1;
+ for(var i = arr[2]; ; ) {
+ break;
+ }
+}
+)";
+
+ auto* expect = R"(
+const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+
+fn f() {
+ var insert_after = 1;
+ let tint_symbol = arr;
+ for(var i = tint_symbol[2]; ; ) {
+ break;
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, StructInForLoopInit) {
+ auto* src = R"(
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+};
+
+fn f() {
+ var insert_after = 1;
+ for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
+ break;
+ }
+}
+)";
+
+ auto* expect = R"(
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+}
+
+fn f() {
+ var insert_after = 1;
+ let tint_symbol = S(1, 2.0, vec3<f32>());
+ for(var x = tint_symbol.b; ; ) {
+ break;
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, StructInForLoopInit_OutOfOrder) {
+ auto* src = R"(
+fn f() {
+ var insert_after = 1;
+ for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
+ break;
+ }
+}
+
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+};
+)";
+
+ auto* expect = R"(
+fn f() {
+ var insert_after = 1;
+ let tint_symbol = S(1, 2.0, vec3<f32>());
+ for(var x = tint_symbol.b; ; ) {
+ break;
+ }
+}
+
+struct S {
+ a : i32,
+ b : f32,
+ c : vec3<f32>,
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ArrayInForLoopCond) {
+ auto* src = R"(
+fn f() {
+ var f = 1.0;
+ for(; f == array<f32, 1u>(f)[0]; f = f + 1.0) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var f = 1.0;
+ loop {
+ let tint_symbol = array<f32, 1u>(f);
+ if (!((f == tint_symbol[0]))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ f = (f + 1.0);
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopCond) {
+ auto* src = R"(
+fn f() {
+ const f = 1.0;
+ const arr = array<f32, 1u>(f);
+ for(var i = f; i == arr[0]; i = i + 1.0) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ const f = 1.0;
+ const arr = array<f32, 1u>(f);
+ {
+ var i = f;
+ loop {
+ let tint_symbol = arr;
+ if (!((i == tint_symbol[0]))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ i = (i + 1.0);
+ }
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopCond) {
+ auto* src = R"(
+const f = 1.0;
+
+const arr = array<f32, 1u>(f);
+
+fn F() {
+ for(var i = f; i == arr[0]; i = i + 1.0) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+const f = 1.0;
+
+const arr = array<f32, 1u>(f);
+
+fn F() {
+ {
+ var i = f;
+ loop {
+ let tint_symbol = arr;
+ if (!((i == tint_symbol[0]))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ i = (i + 1.0);
+ }
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ArrayInForLoopCont) {
+ auto* src = R"(
+fn f() {
+ var f = 0.0;
+ for(; f < 10.0; f = f + array<f32, 1u>(1.0)[0]) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var f = 0.0;
+ loop {
+ if (!((f < 10.0))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ let tint_symbol = array<f32, 1u>(1.0);
+ f = (f + tint_symbol[0]);
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopCont) {
+ auto* src = R"(
+fn f() {
+ const arr = array<f32, 1u>(1.0);
+ var f = 0.0;
+ for(; f < 10.0; f = f + arr[0]) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ const arr = array<f32, 1u>(1.0);
+ var f = 0.0;
+ loop {
+ if (!((f < 10.0))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ let tint_symbol = arr;
+ f = (f + tint_symbol[0]);
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopCont) {
+ auto* src = R"(
+const arr = array<f32, 1u>(1.0);
+
+fn f() {
+ var f = 0.0;
+ for(; f < 10.0; f = f + arr[0]) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+const arr = array<f32, 1u>(1.0);
+
+fn f() {
+ var f = 0.0;
+ loop {
+ if (!((f < 10.0))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ let tint_symbol = arr;
+ f = (f + tint_symbol[0]);
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ArrayInForLoopInitCondCont) {
+ auto* src = R"(
+fn f() {
+ for(var f = array<f32, 1u>(0.0)[0];
+ f < array<f32, 1u>(1.0)[0];
+ f = f + array<f32, 1u>(2.0)[0]) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ let tint_symbol = array<f32, 1u>(0.0);
+ {
+ var f = tint_symbol[0];
+ loop {
+ let tint_symbol_1 = array<f32, 1u>(1.0);
+ if (!((f < tint_symbol_1[0]))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ let tint_symbol_2 = array<f32, 1u>(2.0);
+ f = (f + tint_symbol_2[0]);
+ }
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopInitCondCont) {
+ auto* src = R"(
+fn f() {
+ const arr_a = array<f32, 1u>(0.0);
+ const arr_b = array<f32, 1u>(1.0);
+ const arr_c = array<f32, 1u>(2.0);
+ for(var f = arr_a[0]; f < arr_b[0]; f = f + arr_c[0]) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ const arr_a = array<f32, 1u>(0.0);
+ const arr_b = array<f32, 1u>(1.0);
+ const arr_c = array<f32, 1u>(2.0);
+ let tint_symbol = arr_a;
+ {
+ var f = tint_symbol[0];
+ loop {
+ let tint_symbol_1 = arr_b;
+ if (!((f < tint_symbol_1[0]))) {
+ break;
+ }
+ {
+ var marker = 1;
+ }
+
+ continuing {
+ let tint_symbol_2 = arr_c;
+ f = (f + tint_symbol_2[0]);
+ }
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ArrayInElseIf) {
+ auto* src = R"(
+fn f() {
+ var f = 1.0;
+ if (true) {
+ var marker = 0;
+ } else if (f == array<f32, 2u>(f, f)[0]) {
+ var marker = 1;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var f = 1.0;
+ if (true) {
+ var marker = 0;
+ } else {
+ let tint_symbol = array<f32, 2u>(f, f);
+ if ((f == tint_symbol[0])) {
+ var marker = 1;
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ArrayInElseIfChain) {
+ auto* src = R"(
+fn f() {
+ var f = 1.0;
+ if (true) {
+ var marker = 0;
+ } else if (true) {
+ var marker = 1;
+ } else if (f == array<f32, 2u>(f, f)[0]) {
+ var marker = 2;
+ } else if (f == array<f32, 2u>(f, f)[1]) {
+ var marker = 3;
+ } else if (true) {
+ var marker = 4;
+ } else {
+ var marker = 5;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var f = 1.0;
+ if (true) {
+ var marker = 0;
+ } else if (true) {
+ var marker = 1;
+ } else {
+ let tint_symbol = array<f32, 2u>(f, f);
+ if ((f == tint_symbol[0])) {
+ var marker = 2;
+ } else {
+ let tint_symbol_1 = array<f32, 2u>(f, f);
+ if ((f == tint_symbol_1[1])) {
+ var marker = 3;
+ } else if (true) {
+ var marker = 4;
+ } else {
+ var marker = 5;
+ }
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, LocalConstArrayInElseIfChain) {
+ auto* src = R"(
+fn f() {
+ const f = 1.0;
+ const arr = array<f32, 2u>(f, f);
+ if (true) {
+ var marker = 0;
+ } else if (true) {
+ var marker = 1;
+ } else if (f == arr[0]) {
+ var marker = 2;
+ } else if (f == arr[1]) {
+ var marker = 3;
+ } else if (true) {
+ var marker = 4;
+ } else {
+ var marker = 5;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ const f = 1.0;
+ const arr = array<f32, 2u>(f, f);
+ if (true) {
+ var marker = 0;
+ } else if (true) {
+ var marker = 1;
+ } else {
+ let tint_symbol = arr;
+ if ((f == tint_symbol[0])) {
+ var marker = 2;
+ } else {
+ let tint_symbol_1 = arr;
+ if ((f == tint_symbol_1[1])) {
+ var marker = 3;
+ } else if (true) {
+ var marker = 4;
+ } else {
+ var marker = 5;
+ }
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInElseIfChain) {
+ auto* src = R"(
+const f = 1.0;
+
+const arr = array<f32, 2u>(f, f);
+
+fn F() {
+ if (true) {
+ var marker = 0;
+ } else if (true) {
+ var marker = 1;
+ } else if (f == arr[0]) {
+ var marker = 2;
+ } else if (f == arr[1]) {
+ var marker = 3;
+ } else if (true) {
+ var marker = 4;
+ } else {
+ var marker = 5;
+ }
+}
+)";
+
+ auto* expect = R"(
+const f = 1.0;
+
+const arr = array<f32, 2u>(f, f);
+
+fn F() {
+ if (true) {
+ var marker = 0;
+ } else if (true) {
+ var marker = 1;
+ } else {
+ let tint_symbol = arr;
+ if ((f == tint_symbol[0])) {
+ var marker = 2;
+ } else {
+ let tint_symbol_1 = arr;
+ if ((f == tint_symbol_1[1])) {
+ var marker = 3;
+ } else if (true) {
+ var marker = 4;
+ } else {
+ var marker = 5;
+ }
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ArrayInArrayArray) {
+ auto* src = R"(
+fn f() {
+ var i = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0))[0][1];
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ let tint_symbol = array<f32, 2u>(1.0, 2.0);
+ let tint_symbol_1 = array<f32, 2u>(3.0, 4.0);
+ let tint_symbol_2 = array<array<f32, 2u>, 2u>(tint_symbol, tint_symbol_1);
+ var i = tint_symbol_2[0][1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, LocalConstArrayInArrayArray) {
+ auto* src = R"(
+fn f() {
+ const arr_0 = array<f32, 2u>(1.0, 2.0);
+ const arr_1 = array<f32, 2u>(3.0, 4.0);
+ const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
+ var i = arr_2[0][1];
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ const arr_0 = array<f32, 2u>(1.0, 2.0);
+ const arr_1 = array<f32, 2u>(3.0, 4.0);
+ const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
+ let tint_symbol = arr_2;
+ var i = tint_symbol[0][1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInArrayArray) {
+ auto* src = R"(
+const arr_0 = array<f32, 2u>(1.0, 2.0);
+
+const arr_1 = array<f32, 2u>(3.0, 4.0);
+
+const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
+
+fn f() {
+ var i = arr_2[0][1];
+}
+)";
+
+ auto* expect = R"(
+const arr_0 = array<f32, 2u>(1.0, 2.0);
+
+const arr_1 = array<f32, 2u>(3.0, 4.0);
+
+const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
+
+fn f() {
+ let tint_symbol = arr_2;
+ var i = tint_symbol[0][1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, StructNested) {
+ auto* src = R"(
+struct S1 {
+ a : i32,
+};
+
+struct S2 {
+ a : i32,
+ b : S1,
+ c : i32,
+};
+
+struct S3 {
+ a : S2,
+};
+
+fn f() {
+ var x = S3(S2(1, S1(2), 3)).a.b.a;
+}
+)";
+
+ auto* expect = R"(
+struct S1 {
+ a : i32,
+}
+
+struct S2 {
+ a : i32,
+ b : S1,
+ c : i32,
+}
+
+struct S3 {
+ a : S2,
+}
+
+fn f() {
+ let tint_symbol = S1(2);
+ let tint_symbol_1 = S2(1, tint_symbol, 3);
+ let tint_symbol_2 = S3(tint_symbol_1);
+ var x = tint_symbol_2.a.b.a;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, Mixed) {
+ auto* src = R"(
+struct S1 {
+ a : i32,
+};
+
+struct S2 {
+ a : array<S1, 3u>,
+};
+
+fn f() {
+ var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
+}
+)";
+
+ auto* expect = R"(
+struct S1 {
+ a : i32,
+}
+
+struct S2 {
+ a : array<S1, 3u>,
+}
+
+fn f() {
+ let tint_symbol = S1(1);
+ let tint_symbol_1 = S1(2);
+ let tint_symbol_2 = S1(3);
+ let tint_symbol_3 = array<S1, 3u>(tint_symbol, tint_symbol_1, tint_symbol_2);
+ let tint_symbol_4 = S2(tint_symbol_3);
+ var x = tint_symbol_4.a[1].a;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, Mixed_OutOfOrder) {
+ auto* src = R"(
+fn f() {
+ var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
+}
+
+struct S2 {
+ a : array<S1, 3u>,
+};
+
+struct S1 {
+ a : i32,
+};
+)";
+
+ auto* expect = R"(
+fn f() {
+ let tint_symbol = S1(1);
+ let tint_symbol_1 = S1(2);
+ let tint_symbol_2 = S1(3);
+ let tint_symbol_3 = array<S1, 3u>(tint_symbol, tint_symbol_1, tint_symbol_2);
+ let tint_symbol_4 = S2(tint_symbol_3);
+ var x = tint_symbol_4.a[1].a;
+}
+
+struct S2 {
+ a : array<S1, 3u>,
+}
+
+struct S1 {
+ a : i32,
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, NoChangeOnVarDecl) {
+ auto* src = R"(
+type F = f32;
+
+fn f() {
+ var local_arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+ var local_str = F(3.0);
+}
+
+const module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+
+const module_str : F = F(2.0);
+)";
+
+ auto* expect = src;
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, NoChangeOnVarDecl_OutOfOrder) {
+ auto* src = R"(
+fn f() {
+ var local_arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+ var local_str = F(3.0);
+}
+
+const module_str : F = F(2.0);
+
+type F = f32;
+
+const module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+)";
+
+ auto* expect = src;
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PromoteInitializersToLetTest, ForLoopShadowing) {
+ auto* src = R"(
+fn X() {
+ var i = 10;
+ for(var f = 0; f < 10; f = f + array<i32, 1u>(i)[0]) {
+ var i = 20;
+ }
+}
+
+fn Y() {
+ var i = 10;
+ for(var f = 0; f < array<i32, 1u>(i)[0]; f = f + 1) {
+ var i = 20;
+ }
+}
+
+fn Z() {
+ var i = 10;
+ for(var f = array<i32, 1u>(i)[0]; f < 10; f = f + 1) {
+ var i = 20;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn X() {
+ var i = 10;
+ {
+ var f = 0;
+ loop {
+ if (!((f < 10))) {
+ break;
+ }
+ {
+ var i = 20;
+ }
+
+ continuing {
+ let tint_symbol = array<i32, 1u>(i);
+ f = (f + tint_symbol[0]);
+ }
+ }
+ }
+}
+
+fn Y() {
+ var i = 10;
+ {
+ var f = 0;
+ loop {
+ let tint_symbol_1 = array<i32, 1u>(i);
+ if (!((f < tint_symbol_1[0]))) {
+ break;
+ }
+ {
+ var i = 20;
+ }
+
+ continuing {
+ f = (f + 1);
+ }
+ }
+ }
+}
+
+fn Z() {
+ var i = 10;
+ let tint_symbol_2 = array<i32, 1u>(i);
+ for(var f = tint_symbol_2[0]; (f < 10); f = (f + 1)) {
+ var i = 20;
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteInitializersToLet>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.cc b/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.cc
index 6f1cc4c7974..46e8f462557 100644
--- a/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.cc
+++ b/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.cc
@@ -27,6 +27,7 @@
#include "src/tint/sem/if_statement.h"
#include "src/tint/sem/member_accessor_expression.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/sem/while_statement.h"
#include "src/tint/transform/manager.h"
#include "src/tint/transform/utils/get_insertion_point.h"
#include "src/tint/transform/utils/hoist_to_decl_before.h"
@@ -179,11 +180,12 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
}
// Hoists any expressions in `maybe_hoist` and clears it
- void Flush(ast::ExpressionList& maybe_hoist) {
+ template <size_t N>
+ void Flush(tint::utils::Vector<const ast::Expression*, N>& maybe_hoist) {
for (auto* m : maybe_hoist) {
Hoist(m);
}
- maybe_hoist.clear();
+ maybe_hoist.Clear();
}
// Recursive function that processes expressions for side-effects. It
@@ -196,7 +198,9 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
// * For index and member accessor expressions, special care is taken to not
// over-hoist the lhs expressions, as these may be be chained to refer to a
// single memory location.
- bool ProcessExpression(const ast::Expression* expr, ast::ExpressionList& maybe_hoist) {
+ template <size_t N>
+ bool ProcessExpression(const ast::Expression* expr,
+ tint::utils::Vector<const ast::Expression*, N>& maybe_hoist) {
auto process = [&](const ast::Expression* e) -> bool {
return ProcessExpression(e, maybe_hoist);
};
@@ -204,7 +208,7 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
auto default_process = [&](const ast::Expression* e) {
auto maybe = process(e);
if (maybe) {
- maybe_hoist.emplace_back(e);
+ maybe_hoist.Push(e);
}
if (HasSideEffects(e)) {
Flush(maybe_hoist);
@@ -239,7 +243,7 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
// for "v[a][b][c] + g()" we want to hoist all of "v[a][b][c]", not "t1 =
// v[a]", then "t2 = t1[b]" then "t3 = t2[c]").
if (maybe && HasSideEffects(lhs)) {
- maybe_hoist.emplace_back(lhs);
+ maybe_hoist.Push(lhs);
Flush(maybe_hoist);
maybe = false;
}
@@ -274,7 +278,7 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
if (auto* sem_e = sem.Get(e)) {
if (auto* var_user = sem_e->As<sem::VariableUser>()) {
// Don't hoist constants.
- if (var_user->ConstantValue().IsValid()) {
+ if (var_user->ConstantValue()) {
return false;
}
// Don't hoist read-only variables as they cannot receive
@@ -336,7 +340,7 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
return;
}
- ast::ExpressionList maybe_hoist;
+ tint::utils::Vector<const ast::Expression*, 8> maybe_hoist;
ProcessExpression(expr, maybe_hoist);
}
@@ -344,9 +348,9 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
// evaluate the rhs before the lhs, and possibly hoist the rhs expression.
void ProcessAssignment(const ast::Expression* lhs, const ast::Expression* rhs) {
// Evaluate rhs before lhs
- ast::ExpressionList maybe_hoist;
+ tint::utils::Vector<const ast::Expression*, 8> maybe_hoist;
if (ProcessExpression(rhs, maybe_hoist)) {
- maybe_hoist.emplace_back(rhs);
+ maybe_hoist.Push(rhs);
}
// If the rhs has side-effects, it may affect the lhs, so hoist it right
@@ -383,6 +387,7 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
ProcessStatement(s->expr);
},
[&](const ast::ForLoopStatement* s) { ProcessStatement(s->condition); },
+ [&](const ast::WhileStatement* s) { ProcessStatement(s->condition); },
[&](const ast::IfStatement* s) { //
ProcessStatement(s->condition);
},
@@ -412,7 +417,9 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
}
// Recursive function used to decompose an expression for short-circuit eval.
- const ast::Expression* Decompose(const ast::Expression* expr, ast::StatementList* curr_stmts) {
+ template <size_t N>
+ const ast::Expression* Decompose(const ast::Expression* expr,
+ tint::utils::Vector<const ast::Statement*, N>* curr_stmts) {
// Helper to avoid passing in same args.
auto decompose = [&](auto& e) { return Decompose(e, curr_stmts); };
@@ -422,7 +429,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
auto name = b.Symbols().New();
auto* v = b.Let(name, nullptr, ctx.Clone(e));
auto* decl = b.Decl(v);
- curr_stmts->push_back(decl);
+ curr_stmts->Push(decl);
return b.Expr(name);
}
return ctx.Clone(e);
@@ -469,7 +476,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
// let r = temp;
auto name = b.Sym();
- curr_stmts->push_back(b.Decl(b.Var(name, nullptr, decompose(bin_expr->lhs))));
+ curr_stmts->Push(b.Decl(b.Var(name, nullptr, decompose(bin_expr->lhs))));
const ast::Expression* if_cond = nullptr;
if (bin_expr->IsLogicalOr()) {
@@ -480,14 +487,14 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
const ast::BlockStatement* if_body = nullptr;
{
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, N> stmts;
TINT_SCOPED_ASSIGNMENT(curr_stmts, &stmts);
auto* new_rhs = decompose(bin_expr->rhs);
- curr_stmts->push_back(b.Assign(name, new_rhs));
+ curr_stmts->Push(b.Assign(name, new_rhs));
if_body = b.Block(std::move(*curr_stmts));
}
- curr_stmts->push_back(b.If(if_cond, if_body));
+ curr_stmts->Push(b.If(if_cond, if_body));
return b.Expr(name);
},
@@ -535,8 +542,10 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
}
// Inserts statements in `stmts` before `stmt`
- void InsertBefore(const ast::StatementList& stmts, const ast::Statement* stmt) {
- if (!stmts.empty()) {
+ template <size_t N>
+ void InsertBefore(tint::utils::Vector<const ast::Statement*, N>& stmts,
+ const ast::Statement* stmt) {
+ if (!stmts.IsEmpty()) {
auto ip = utils::GetInsertionPoint(ctx, stmt);
for (auto* s : stmts) {
ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, s);
@@ -554,7 +563,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
return nullptr;
}
// rhs before lhs
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
ctx.Replace(s->rhs, Decompose(s->rhs, &stmts));
ctx.Replace(s->lhs, Decompose(s->lhs, &stmts));
InsertBefore(stmts, s);
@@ -564,7 +573,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
if (!sem.Get(s->expr)->HasSideEffects()) {
return nullptr;
}
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
ctx.Replace(s->expr, Decompose(s->expr, &stmts));
InsertBefore(stmts, s);
return ctx.CloneWithoutTransform(s);
@@ -573,7 +582,16 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
if (!s->condition || !sem.Get(s->condition)->HasSideEffects()) {
return nullptr;
}
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
+ ctx.Replace(s->condition, Decompose(s->condition, &stmts));
+ InsertBefore(stmts, s);
+ return ctx.CloneWithoutTransform(s);
+ },
+ [&](const ast::WhileStatement* s) -> const ast::Statement* {
+ if (!sem.Get(s->condition)->HasSideEffects()) {
+ return nullptr;
+ }
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
ctx.Replace(s->condition, Decompose(s->condition, &stmts));
InsertBefore(stmts, s);
return ctx.CloneWithoutTransform(s);
@@ -582,7 +600,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
if (!sem.Get(s->condition)->HasSideEffects()) {
return nullptr;
}
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
ctx.Replace(s->condition, Decompose(s->condition, &stmts));
InsertBefore(stmts, s);
return ctx.CloneWithoutTransform(s);
@@ -591,7 +609,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
if (!s->value || !sem.Get(s->value)->HasSideEffects()) {
return nullptr;
}
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
ctx.Replace(s->value, Decompose(s->value, &stmts));
InsertBefore(stmts, s);
return ctx.CloneWithoutTransform(s);
@@ -600,7 +618,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
if (!sem.Get(s->condition)) {
return nullptr;
}
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
ctx.Replace(s->condition, Decompose(s->condition, &stmts));
InsertBefore(stmts, s);
return ctx.CloneWithoutTransform(s);
@@ -610,7 +628,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
if (!var->constructor || !sem.Get(var->constructor)->HasSideEffects()) {
return nullptr;
}
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 8> stmts;
ctx.Replace(var->constructor, Decompose(var->constructor, &stmts));
InsertBefore(stmts, s);
return b.Decl(ctx.CloneWithoutTransform(var));
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.h b/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.h
index 1e629b344f2..d5d1126133b 100644
--- a/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.h
+++ b/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl.h
@@ -23,7 +23,7 @@ namespace tint::transform {
/// declarations before the statement of usage with the goal of ensuring
/// left-to-right order of evaluation, while respecting short-circuit
/// evaluation.
-class PromoteSideEffectsToDecl : public Castable<PromoteSideEffectsToDecl, Transform> {
+class PromoteSideEffectsToDecl final : public Castable<PromoteSideEffectsToDecl, Transform> {
public:
/// Constructor
PromoteSideEffectsToDecl();
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl_test.cc b/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl_test.cc
index 9d9115fe19e..937b59e44c5 100644
--- a/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/promote_side_effects_to_decl_test.cc
@@ -999,6 +999,45 @@ fn f() {
EXPECT_EQ(expect, str(got));
}
+TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InWhileCond) {
+ auto* src = R"(
+fn a(i : i32) -> i32 {
+ return i;
+}
+
+fn f() {
+ var b = 1;
+ while(a(0) + b > 0) {
+ var marker = 0;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn a(i : i32) -> i32 {
+ return i;
+}
+
+fn f() {
+ var b = 1;
+ loop {
+ let tint_symbol = a(0);
+ if (!(((tint_symbol + b) > 0))) {
+ break;
+ }
+ {
+ var marker = 0;
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InElseIf) {
auto* src = R"(
fn a(i : i32) -> i32 {
@@ -2299,6 +2338,48 @@ fn f() {
EXPECT_EQ(expect, str(got));
}
+TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InWhileCond) {
+ auto* src = R"(
+fn a(i : i32) -> bool {
+ return true;
+}
+
+fn f() {
+ var b = true;
+ while(a(0) && b) {
+ var marker = 0;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn a(i : i32) -> bool {
+ return true;
+}
+
+fn f() {
+ var b = true;
+ loop {
+ var tint_symbol = a(0);
+ if (tint_symbol) {
+ tint_symbol = b;
+ }
+ if (!(tint_symbol)) {
+ break;
+ }
+ {
+ var marker = 0;
+ }
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InElseIf) {
auto* src = R"(
fn a(i : i32) -> bool {
diff --git a/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.cc b/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.cc
index 5c2413e1d47..e5df23fa4d2 100644
--- a/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.cc
+++ b/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.cc
@@ -25,6 +25,7 @@
#include "src/tint/sem/for_loop_statement.h"
#include "src/tint/sem/loop_statement.h"
#include "src/tint/sem/switch_statement.h"
+#include "src/tint/sem/while_statement.h"
#include "src/tint/transform/utils/get_insertion_point.h"
#include "src/tint/utils/map.h"
@@ -49,7 +50,7 @@ class State {
// Find whether first parent is a switch or a loop
auto* sem_stmt = sem.Get(cont);
auto* sem_parent = sem_stmt->FindFirstParent<sem::SwitchStatement, sem::LoopBlockStatement,
- sem::ForLoopStatement>();
+ sem::ForLoopStatement, sem::WhileStatement>();
if (!sem_parent) {
return nullptr;
}
diff --git a/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.h b/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.h
index e7062255008..9e5a4d51adc 100644
--- a/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.h
+++ b/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch.h
@@ -23,7 +23,7 @@ namespace tint::transform {
/// bool variable, and checking if the variable is set after the switch to
/// continue. It is necessary to work around FXC "error X3708: continue cannot
/// be used in a switch". See crbug.com/tint/1080.
-class RemoveContinueInSwitch : public Castable<RemoveContinueInSwitch, Transform> {
+class RemoveContinueInSwitch final : public Castable<RemoveContinueInSwitch, Transform> {
public:
/// Constructor
RemoveContinueInSwitch();
diff --git a/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch_test.cc b/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch_test.cc
index a1e7b6e1e1d..0b52457c3c3 100644
--- a/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/remove_continue_in_switch_test.cc
@@ -559,5 +559,59 @@ fn f() {
EXPECT_EQ(expect, str(got));
}
+TEST_F(RemoveContinueInSwitchTest, While) {
+ auto* src = R"(
+fn f() {
+ var i = 0;
+ while (i < 4) {
+ let marker1 = 0;
+ switch(i) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ let marker2 = 0;
+ break;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var i = 0;
+ while((i < 4)) {
+ let marker1 = 0;
+ var tint_continue : bool = false;
+ switch(i) {
+ case 0: {
+ {
+ tint_continue = true;
+ break;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ let marker2 = 0;
+ break;
+ }
+}
+)";
+
+ DataMap data;
+ auto got = Run<RemoveContinueInSwitch>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
} // namespace
} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/remove_phonies.cc b/chromium/third_party/dawn/src/tint/transform/remove_phonies.cc
index 7ca11944874..5e642522e5e 100644
--- a/chromium/third_party/dawn/src/tint/transform/remove_phonies.cc
+++ b/chromium/third_party/dawn/src/tint/transform/remove_phonies.cc
@@ -72,6 +72,11 @@ bool RemovePhonies::ShouldRun(const Program* program, const DataMap&) const {
if (node->Is<ast::PhonyExpression>()) {
return true;
}
+ if (auto* stmt = node->As<ast::CallStatement>()) {
+ if (program->Sem().Get(stmt->expr)->ConstantValue() != nullptr) {
+ return true;
+ }
+ }
}
return false;
}
@@ -82,73 +87,86 @@ void RemovePhonies::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
std::unordered_map<SinkSignature, Symbol, SinkSignature::Hasher> sinks;
for (auto* node : ctx.src->ASTNodes().Objects()) {
- if (auto* stmt = node->As<ast::AssignmentStatement>()) {
- if (stmt->lhs->Is<ast::PhonyExpression>()) {
- std::vector<const ast::Expression*> side_effects;
- if (!ast::TraverseExpressions(
- stmt->rhs, ctx.dst->Diagnostics(), [&](const ast::CallExpression* expr) {
- // ast::CallExpression may map to a function or builtin call
- // (both may have side-effects), or a type constructor or
- // type conversion (both do not have side effects).
- auto* call = sem.Get<sem::Call>(expr);
- if (!call) {
- // Semantic node must be a Materialize, in which case the expression
- // was creation-time (compile time), so could not have side effects.
- // Just skip.
- return ast::TraverseAction::Skip;
- }
- if (call->Target()->IsAnyOf<sem::Function, sem::Builtin>()) {
- side_effects.push_back(expr);
- return ast::TraverseAction::Skip;
- }
- return ast::TraverseAction::Descend;
- })) {
- return;
- }
-
- if (side_effects.empty()) {
- // Phony assignment with no side effects.
- // Just remove it.
- RemoveStatement(ctx, stmt);
- continue;
- }
+ Switch(
+ node,
+ [&](const ast::AssignmentStatement* stmt) {
+ if (stmt->lhs->Is<ast::PhonyExpression>()) {
+ std::vector<const ast::Expression*> side_effects;
+ if (!ast::TraverseExpressions(
+ stmt->rhs, ctx.dst->Diagnostics(),
+ [&](const ast::CallExpression* expr) {
+ // ast::CallExpression may map to a function or builtin call
+ // (both may have side-effects), or a type constructor or
+ // type conversion (both do not have side effects).
+ auto* call = sem.Get<sem::Call>(expr);
+ if (!call) {
+ // Semantic node must be a Materialize, in which case the
+ // expression was creation-time (compile time), so could not
+ // have side effects. Just skip.
+ return ast::TraverseAction::Skip;
+ }
+ if (call->Target()->IsAnyOf<sem::Function, sem::Builtin>() &&
+ call->HasSideEffects()) {
+ side_effects.push_back(expr);
+ return ast::TraverseAction::Skip;
+ }
+ return ast::TraverseAction::Descend;
+ })) {
+ return;
+ }
- if (side_effects.size() == 1) {
- if (auto* call = side_effects[0]->As<ast::CallExpression>()) {
- // Phony assignment with single call side effect.
- // Replace phony assignment with call.
- ctx.Replace(stmt, [&, call] { return ctx.dst->CallStmt(ctx.Clone(call)); });
- continue;
+ if (side_effects.empty()) {
+ // Phony assignment with no side effects.
+ // Just remove it.
+ RemoveStatement(ctx, stmt);
+ return;
}
- }
- // Phony assignment with multiple side effects.
- // Generate a call to a placeholder function with the side
- // effects as arguments.
- ctx.Replace(stmt, [&, side_effects] {
- SinkSignature sig;
- for (auto* arg : side_effects) {
- sig.types.push_back(sem.Get(arg)->Type()->UnwrapRef());
+ if (side_effects.size() == 1) {
+ if (auto* call = side_effects[0]->As<ast::CallExpression>()) {
+ // Phony assignment with single call side effect.
+ // Replace phony assignment with call.
+ ctx.Replace(stmt,
+ [&, call] { return ctx.dst->CallStmt(ctx.Clone(call)); });
+ return;
+ }
}
- auto sink = utils::GetOrCreate(sinks, sig, [&] {
- auto name = ctx.dst->Symbols().New("phony_sink");
- ast::VariableList params;
- for (auto* ty : sig.types) {
- auto* ast_ty = CreateASTTypeFor(ctx, ty);
- params.push_back(
- ctx.dst->Param("p" + std::to_string(params.size()), ast_ty));
+
+ // Phony assignment with multiple side effects.
+ // Generate a call to a placeholder function with the side
+ // effects as arguments.
+ ctx.Replace(stmt, [&, side_effects] {
+ SinkSignature sig;
+ for (auto* arg : side_effects) {
+ sig.types.push_back(sem.Get(arg)->Type()->UnwrapRef());
}
- ctx.dst->Func(name, params, ctx.dst->ty.void_(), {});
- return name;
+ auto sink = utils::GetOrCreate(sinks, sig, [&] {
+ auto name = ctx.dst->Symbols().New("phony_sink");
+ utils::Vector<const ast::Parameter*, 8> params;
+ for (auto* ty : sig.types) {
+ auto* ast_ty = CreateASTTypeFor(ctx, ty);
+ params.Push(
+ ctx.dst->Param("p" + std::to_string(params.Length()), ast_ty));
+ }
+ ctx.dst->Func(name, params, ctx.dst->ty.void_(), {});
+ return name;
+ });
+ utils::Vector<const ast::Expression*, 8> args;
+ for (auto* arg : side_effects) {
+ args.Push(ctx.Clone(arg));
+ }
+ return ctx.dst->CallStmt(ctx.dst->Call(sink, args));
});
- ast::ExpressionList args;
- for (auto* arg : side_effects) {
- args.push_back(ctx.Clone(arg));
- }
- return ctx.dst->CallStmt(ctx.dst->Call(sink, args));
- });
- }
- }
+ }
+ },
+ [&](const ast::CallStatement* stmt) {
+ // Remove call statements to const value-returning functions.
+ // TODO(crbug.com/tint/1637): Remove if `stmt->expr` has no side-effects.
+ auto* sem_expr = sem.Get(stmt->expr);
+ if ((sem_expr->ConstantValue() != nullptr) && !sem_expr->HasSideEffects()) {
+ ctx.Remove(sem.Get(stmt)->Block()->Declaration()->statements, stmt);
+ }
+ });
}
ctx.Clone();
diff --git a/chromium/third_party/dawn/src/tint/transform/remove_phonies.h b/chromium/third_party/dawn/src/tint/transform/remove_phonies.h
index 20128a0e4ec..daa181270e9 100644
--- a/chromium/third_party/dawn/src/tint/transform/remove_phonies.h
+++ b/chromium/third_party/dawn/src/tint/transform/remove_phonies.h
@@ -24,8 +24,8 @@ namespace tint::transform {
/// RemovePhonies is a Transform that removes all phony-assignment statements,
/// while preserving function call expressions in the RHS of the assignment that
-/// may have side-effects.
-class RemovePhonies : public Castable<RemovePhonies, Transform> {
+/// may have side-effects. It also removes calls to builtins that return a constant value.
+class RemovePhonies final : public Castable<RemovePhonies, Transform> {
public:
/// Constructor
RemovePhonies();
diff --git a/chromium/third_party/dawn/src/tint/transform/remove_phonies_test.cc b/chromium/third_party/dawn/src/tint/transform/remove_phonies_test.cc
index 220f1db4649..a072e517d74 100644
--- a/chromium/third_party/dawn/src/tint/transform/remove_phonies_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/remove_phonies_test.cc
@@ -65,6 +65,10 @@ fn f() {
_ = vec2<f32>(5.0);
_ = vec3<i32>(6, 7, 8);
_ = mat2x2<f32>(9.0, 10.0, 11.0, 12.0);
+ _ = atan2(1.0, 2.0);
+ _ = clamp(1.0, 2.0, 3.0);
+ atan2(1.0, 2.0);
+ clamp(1.0, 2.0, 3.0);
}
)";
diff --git a/chromium/third_party/dawn/src/tint/transform/remove_unreachable_statements.h b/chromium/third_party/dawn/src/tint/transform/remove_unreachable_statements.h
index c75da3d45f6..7f8b9472ada 100644
--- a/chromium/third_party/dawn/src/tint/transform/remove_unreachable_statements.h
+++ b/chromium/third_party/dawn/src/tint/transform/remove_unreachable_statements.h
@@ -24,7 +24,7 @@ namespace tint::transform {
/// RemoveUnreachableStatements is a Transform that removes all statements
/// marked as unreachable.
-class RemoveUnreachableStatements : public Castable<RemoveUnreachableStatements, Transform> {
+class RemoveUnreachableStatements final : public Castable<RemoveUnreachableStatements, Transform> {
public:
/// Constructor
RemoveUnreachableStatements();
diff --git a/chromium/third_party/dawn/src/tint/transform/renamer.h b/chromium/third_party/dawn/src/tint/transform/renamer.h
index 354acdade18..000aee9ca22 100644
--- a/chromium/third_party/dawn/src/tint/transform/renamer.h
+++ b/chromium/third_party/dawn/src/tint/transform/renamer.h
@@ -23,11 +23,11 @@
namespace tint::transform {
/// Renamer is a Transform that renames all the symbols in a program.
-class Renamer : public Castable<Renamer, Transform> {
+class Renamer final : public Castable<Renamer, Transform> {
public:
/// Data is outputted by the Renamer transform.
/// Data holds information about shader usage and constant buffer offsets.
- struct Data : public Castable<Data, transform::Data> {
+ struct Data final : public Castable<Data, transform::Data> {
/// Remappings is a map of old symbol name to new symbol name
using Remappings = std::unordered_map<std::string, std::string>;
@@ -59,7 +59,7 @@ class Renamer : public Castable<Renamer, Transform> {
/// Optional configuration options for the transform.
/// If omitted, then the renamer will use Target::kAll.
- struct Config : public Castable<Config, transform::Data> {
+ struct Config final : public Castable<Config, transform::Data> {
/// Constructor
/// @param tgt the targets to rename
/// @param keep_unicode if false, symbols with non-ascii code-points are
diff --git a/chromium/third_party/dawn/src/tint/transform/renamer_test.cc b/chromium/third_party/dawn/src/tint/transform/renamer_test.cc
index 516b164af7b..c57dea31055 100644
--- a/chromium/third_party/dawn/src/tint/transform/renamer_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/renamer_test.cc
@@ -328,234 +328,234 @@ fn frag_main() {
INSTANTIATE_TEST_SUITE_P(RenamerTestGlsl,
RenamerTestGlsl,
- testing::Values("active",
- // "asm", // WGSL keyword
- "atomic_uint",
- "attribute",
- // "bool", // WGSL keyword
- // "break", // WGSL keyword
- "buffer",
- "bvec2",
- "bvec3",
- "bvec4",
- // "case", // WGSL keyword
- "cast",
- "centroid",
- "class",
- "coherent",
- "common",
- // "const", // WGSL keyword
- // "continue", // WGSL keyword
- // "default", // WGSL keyword
- // "discard", // WGSL keyword
- "dmat2",
- "dmat2x2",
- "dmat2x3",
- "dmat2x4",
- "dmat3",
- "dmat3x2",
- "dmat3x3",
- "dmat3x4",
- "dmat4",
- "dmat4x2",
- "dmat4x3",
- "dmat4x4",
- // "do", // WGSL keyword
- "double",
- "dvec2",
- "dvec3",
- "dvec4",
- // "else" // WGSL keyword
- // "enum", // WGSL keyword
- "extern",
- "external",
- // "false", // WGSL keyword
- "filter",
- "fixed",
- "flat",
- "float",
- // "for", // WGSL keyword
- "fvec2",
- "fvec3",
- "fvec4",
- "gl_BaseInstance",
- "gl_BaseVertex",
- "gl_ClipDistance",
- "gl_DepthRangeParameters",
- "gl_DrawID",
- "gl_FragCoord",
- "gl_FragDepth",
- "gl_FrontFacing",
- "gl_GlobalInvocationID",
- "gl_InstanceID",
- "gl_LocalInvocationID",
- "gl_LocalInvocationIndex",
- "gl_NumSamples",
- "gl_NumWorkGroups",
- "gl_PerVertex",
- "gl_PointCoord",
- "gl_PointSize",
- "gl_Position",
- "gl_PrimitiveID",
- "gl_SampleID",
- "gl_SampleMask",
- "gl_SampleMaskIn",
- "gl_SamplePosition",
- "gl_VertexID",
- "gl_WorkGroupID",
- "gl_WorkGroupSize",
- "goto",
- "half",
- "highp",
- "hvec2",
- "hvec3",
- "hvec4",
- // "if", // WGSL keyword
- "iimage1D",
- "iimage1DArray",
- "iimage2D",
- "iimage2DArray",
- "iimage2DMS",
- "iimage2DMSArray",
- "iimage2DRect",
- "iimage3D",
- "iimageBuffer",
- "iimageCube",
- "iimageCubeArray",
- "image1D",
- "image1DArray",
- "image2D",
- "image2DArray",
- "image2DMS",
- "image2DMSArray",
- "image2DRect",
- "image3D",
- "imageBuffer",
- "imageCube",
- "imageCubeArray",
- "in",
- "inline",
- "inout",
- "input",
- "int",
- "interface",
- "invariant",
- "isampler1D",
- "isampler1DArray",
- "isampler2D",
- "isampler2DArray",
- "isampler2DMS",
- "isampler2DMSArray",
- "isampler2DRect",
- "isampler3D",
- "isamplerBuffer",
- "isamplerCube",
- "isamplerCubeArray",
- "ivec2",
- "ivec3",
- "ivec4",
- "layout",
- "long",
- "lowp",
- // "mat2x2", // WGSL keyword
- // "mat2x3", // WGSL keyword
- // "mat2x4", // WGSL keyword
- // "mat2",
- "mat3",
- // "mat3x2", // WGSL keyword
- // "mat3x3", // WGSL keyword
- // "mat3x4", // WGSL keyword
- "mat4",
- // "mat4x2", // WGSL keyword
- // "mat4x3", // WGSL keyword
- // "mat4x4", // WGSL keyword
- "mediump",
- "namespace",
- "noinline",
- "noperspective",
- "out",
- "output",
- "partition",
- "patch",
- "precise",
- "precision",
- "public",
- "readonly",
- "resource",
- "restrict",
- // "return", // WGSL keyword
- "sample",
- "sampler1D",
- "sampler1DArray",
- "sampler1DArrayShadow",
- "sampler1DShadow",
- "sampler2D",
- "sampler2DArray",
- "sampler2DArrayShadow",
- "sampler2DMS",
- "sampler2DMSArray",
- "sampler2DRect",
- "sampler2DRectShadow",
- "sampler2DShadow",
- "sampler3D",
- "sampler3DRect",
- "samplerBuffer",
- "samplerCube",
- "samplerCubeArray",
- "samplerCubeArrayShadow",
- "samplerCubeShadow",
- "shared",
- "short",
- "sizeof",
- "smooth",
- "static",
- // "struct", // WGSL keyword
- "subroutine",
- "superp",
- // "switch", // WGSL keyword
- "template",
- "this",
- // "true", // WGSL keyword
- // "typedef", // WGSL keyword
- "uimage1D",
- "uimage1DArray",
- "uimage2D",
- "uimage2DArray",
- "uimage2DMS",
- "uimage2DMSArray",
- "uimage2DRect",
- "uimage3D",
- "uimageBuffer",
- "uimageCube",
- "uimageCubeArray",
- "uint",
- // "uniform", // WGSL keyword
- "union",
- "unsigned",
- "usampler1D",
- "usampler1DArray",
- "usampler2D",
- "usampler2DArray",
- "usampler2DMS",
- "usampler2DMSArray",
- "usampler2DRect",
- "usampler3D",
- "usamplerBuffer",
- "usamplerCube",
- "usamplerCubeArray",
- // "using", // WGSL keyword
- "uvec2",
- "uvec3",
- "uvec4",
- "varying",
- // "vec2", // WGSL keyword
- // "vec3", // WGSL keyword
- // "vec4", // WGSL keyword
- // "void", // WGSL keyword
- "volatile",
- // "while", // WGSL keyword
- "writeonly",
- kUnicodeIdentifier));
+ testing::Values( // "active", // Also reserved in WGSL
+ // "asm", // WGSL keyword
+ "atomic_uint",
+ // "attribute", // Also reserved in WGSL
+ // "bool", // WGSL keyword
+ // "break", // WGSL keyword
+ "buffer",
+ "bvec2",
+ "bvec3",
+ "bvec4",
+ // "case", // WGSL keyword
+ // "cast", // Also reserved in WGSL
+ "centroid",
+ // "class", // Also reserved in WGSL
+ // "coherent", // Also reserved in WGSL
+ // "common", // Also reserved in WGSL
+ // "const", // WGSL keyword
+ // "continue", // WGSL keyword
+ // "default", // WGSL keyword
+ // "discard", // WGSL keyword
+ "dmat2",
+ "dmat2x2",
+ "dmat2x3",
+ "dmat2x4",
+ "dmat3",
+ "dmat3x2",
+ "dmat3x3",
+ "dmat3x4",
+ "dmat4",
+ "dmat4x2",
+ "dmat4x3",
+ "dmat4x4",
+ // "do", // WGSL keyword
+ "double",
+ "dvec2",
+ "dvec3",
+ "dvec4",
+ // "else" // WGSL keyword
+ // "enum", // WGSL keyword
+ // "extern", // Also reserved in WGSL
+ // "external", // Also reserved in WGSL
+ // "false", // WGSL keyword
+ // "filter", // Also reserved in WGSL
+ "fixed",
+ "flat",
+ "float",
+ // "for", // WGSL keyword
+ "fvec2",
+ "fvec3",
+ "fvec4",
+ "gl_BaseInstance",
+ "gl_BaseVertex",
+ "gl_ClipDistance",
+ "gl_DepthRangeParameters",
+ "gl_DrawID",
+ "gl_FragCoord",
+ "gl_FragDepth",
+ "gl_FrontFacing",
+ "gl_GlobalInvocationID",
+ "gl_InstanceID",
+ "gl_LocalInvocationID",
+ "gl_LocalInvocationIndex",
+ "gl_NumSamples",
+ "gl_NumWorkGroups",
+ "gl_PerVertex",
+ "gl_PointCoord",
+ "gl_PointSize",
+ "gl_Position",
+ "gl_PrimitiveID",
+ "gl_SampleID",
+ "gl_SampleMask",
+ "gl_SampleMaskIn",
+ "gl_SamplePosition",
+ "gl_VertexID",
+ "gl_WorkGroupID",
+ "gl_WorkGroupSize",
+ // "goto", // Also reserved in WGSL
+ "half",
+ // "highp", // Also reserved in WGSL
+ "hvec2",
+ "hvec3",
+ "hvec4",
+ // "if", // WGSL keyword
+ "iimage1D",
+ "iimage1DArray",
+ "iimage2D",
+ "iimage2DArray",
+ "iimage2DMS",
+ "iimage2DMSArray",
+ "iimage2DRect",
+ "iimage3D",
+ "iimageBuffer",
+ "iimageCube",
+ "iimageCubeArray",
+ "image1D",
+ "image1DArray",
+ "image2D",
+ "image2DArray",
+ "image2DMS",
+ "image2DMSArray",
+ "image2DRect",
+ "image3D",
+ "imageBuffer",
+ "imageCube",
+ "imageCubeArray",
+ "in",
+ // "inline", // Also reserved in WGSL
+ // "inout", // Also reserved in WGSL
+ "input",
+ "int",
+ // "interface", // Also reserved in WGSL
+ // "invariant", // Also reserved in WGSL
+ "isampler1D",
+ "isampler1DArray",
+ "isampler2D",
+ "isampler2DArray",
+ "isampler2DMS",
+ "isampler2DMSArray",
+ "isampler2DRect",
+ "isampler3D",
+ "isamplerBuffer",
+ "isamplerCube",
+ "isamplerCubeArray",
+ "ivec2",
+ "ivec3",
+ "ivec4",
+ // "layout", // Also reserved in WGSL
+ "long",
+ // "lowp", // Also reserved in WGSL
+ // "mat2x2", // WGSL keyword
+ // "mat2x3", // WGSL keyword
+ // "mat2x4", // WGSL keyword
+ // "mat2",
+ "mat3",
+ // "mat3x2", // WGSL keyword
+ // "mat3x3", // WGSL keyword
+ // "mat3x4", // WGSL keyword
+ "mat4",
+ // "mat4x2", // WGSL keyword
+ // "mat4x3", // WGSL keyword
+ // "mat4x4", // WGSL keyword
+ // "mediump", // Also reserved in WGSL
+ // "namespace", // Also reserved in WGSL
+ // "noinline", // Also reserved in WGSL
+ // "noperspective", // Also reserved in WGSL
+ "out",
+ "output",
+ // "partition", // Also reserved in WGSL
+ // "patch", // Also reserved in WGSL
+ // "precise", // Also reserved in WGSL
+ // "precision", // Also reserved in WGSL
+ // "public", // Also reserved in WGSL
+ // "readonly", // Also reserved in WGSL
+ // "resource", // Also reserved in WGSL
+ // "restrict", // Also reserved in WGSL
+ // "return", // WGSL keyword
+ "sample",
+ "sampler1D",
+ "sampler1DArray",
+ "sampler1DArrayShadow",
+ "sampler1DShadow",
+ "sampler2D",
+ "sampler2DArray",
+ "sampler2DArrayShadow",
+ "sampler2DMS",
+ "sampler2DMSArray",
+ "sampler2DRect",
+ "sampler2DRectShadow",
+ "sampler2DShadow",
+ "sampler3D",
+ "sampler3DRect",
+ "samplerBuffer",
+ "samplerCube",
+ "samplerCubeArray",
+ "samplerCubeArrayShadow",
+ "samplerCubeShadow",
+ // "shared" // Also reserved in WGSL,
+ "short",
+ // "sizeof", // Also reserved in WGSL
+ // "smooth", // Also reserved in WGSL
+ // "static", // Also reserved in WGSL
+ // "struct", // WGSL keyword
+ // "subroutine", // Also reserved in WGSL
+ "superp",
+ // "switch", // WGSL keyword
+ // "template", // Also reserved in WGSL
+ // "this", // Also reserved in WGSL
+ // "true", // WGSL keyword
+ // "typedef", // WGSL keyword
+ "uimage1D",
+ "uimage1DArray",
+ "uimage2D",
+ "uimage2DArray",
+ "uimage2DMS",
+ "uimage2DMSArray",
+ "uimage2DRect",
+ "uimage3D",
+ "uimageBuffer",
+ "uimageCube",
+ "uimageCubeArray",
+ "uint",
+ // "uniform", // WGSL keyword
+ // "union", // Also reserved in WGSL
+ "unsigned",
+ "usampler1D",
+ "usampler1DArray",
+ "usampler2D",
+ "usampler2DArray",
+ "usampler2DMS",
+ "usampler2DMSArray",
+ "usampler2DRect",
+ "usampler3D",
+ "usamplerBuffer",
+ "usamplerCube",
+ "usamplerCubeArray",
+ // "using", // WGSL keyword
+ "uvec2",
+ "uvec3",
+ "uvec4",
+ // "varying", // Also reserved in WGSL
+ // "vec2", // WGSL keyword
+ // "vec3", // WGSL keyword
+ // "vec4", // WGSL keyword
+ // "void", // WGSL keyword
+ // "volatile", // Also reserved in WGSL
+ // "while", // WGSL keyword
+ // "writeonly", // Also reserved in WGSL
+ kUnicodeIdentifier));
INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
RenamerTestHlsl,
@@ -575,8 +575,8 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"COLOR",
"CheckAccessFullyMapped",
"ComparisonFunc",
- "CompileShader",
- "ComputeShader",
+ // "CompileShader", // Also reserved in WGSL
+ // "ComputeShader", // Also reserved in WGSL
"ConsumeStructuredBuffer",
"D3DCOLORtoUBYTE4",
"DEPTH",
@@ -584,18 +584,18 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"DepthStencilView",
"DeviceMemoryBarrier",
"DeviceMemroyBarrierWithGroupSync",
- "DomainShader",
+ // "DomainShader", // Also reserved in WGSL
"EvaluateAttributeAtCentroid",
"EvaluateAttributeAtSample",
"EvaluateAttributeSnapped",
"FOG",
"Filter",
- "GeometryShader",
+ // "GeometryShader", // Also reserved in WGSL
"GetRenderTargetSampleCount",
"GetRenderTargetSamplePosition",
"GroupMemoryBarrier",
"GroupMemroyBarrierWithGroupSync",
- "Hullshader",
+ // "Hullshader", // Also reserved in WGSL
"InputPatch",
"InterlockedAdd",
"InterlockedAnd",
@@ -612,7 +612,7 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"MinLOD",
"MipLODBias",
"NORMAL",
- "NULL",
+ // "NULL", // Also reserved in WGSL
"Normal",
"OutputPatch",
"POSITION",
@@ -703,11 +703,11 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
// "asin", // WGSL builtin
"asint",
// "asm", // WGSL keyword
- "asm_fragment",
+ // "asm_fragment", // Also reserved in WGSL
"asuint",
// "atan", // WGSL builtin
// "atan2", // WGSL builtin
- "auto",
+ // "auto", // Also reserved in WGSL
// "bool", // WGSL keyword
"bool1",
"bool1x1",
@@ -733,19 +733,19 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
// "break", // WGSL keyword
// "call", // WGSL builtin
// "case", // WGSL keyword
- "catch",
+ // "catch", // Also reserved in WGSL
"cbuffer",
// "ceil", // WGSL builtin
"centroid",
"char",
// "clamp", // WGSL builtin
- "class",
+ // "class", // Also reserved in WGSL
"clip",
- "column_major",
- "compile",
- "compile_fragment",
+ // "column_major", // Also reserved in WGSL
+ // "compile", // Also reserved in WGSL
+ // "compile_fragment", // Also reserved in WGSL
// "const", // WGSL keyword
- "const_cast",
+ // "const_cast", // Also reserved in WGSL
// "continue", // WGSL keyword
// "cos", // WGSL builtin
// "cosh", // WGSL builtin
@@ -759,7 +759,7 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"ddy_fine",
// "default", // WGSL keyword
"degrees",
- "delete",
+ // "delete", // Also reserved in WGSL
// "determinant", // WGSL builtin
// "discard", // WGSL keyword
// "distance", // WGSL builtin
@@ -808,15 +808,15 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"dword4x2",
"dword4x3",
"dword4x4",
- "dynamic_cast",
+ // "dynamic_cast", // Also reserved in WGSL
// "else", // WGSL keyword
// "enum", // WGSL keyword
"errorf",
// "exp", // WGSL builtin
// "exp2", // WGSL builtin
- "explicit",
- "export",
- "extern",
+ // "explicit", // Also reserved in WGSL
+ // "export", // Also reserved in WGSL
+ // "extern", // Also reserved in WGSL
"f16to32",
"f32tof16",
// "faceforward", // WGSL builtin
@@ -853,11 +853,11 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"forcecase",
"frac",
// "frexp", // WGSL builtin
- "friend",
+ // "friend", // Also reserved in WGSL
// "fwidth", // WGSL builtin
- "fxgroup",
- "goto",
- "groupshared",
+ // "fxgroup", // Also reserved in WGSL
+ // "goto", // Also reserved in WGSL
+ // "groupshared", // Also reserved in WGSL
"half",
"half1",
"half1x1",
@@ -881,8 +881,8 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"half4x4",
// "if", // WGSL keyword
// "in", // WGSL keyword
- "inline",
- "inout",
+ // "inline", // Also reserved in WGSL
+ // "inout", // Also reserved in WGSL
"int",
"int1",
"int1x1",
@@ -904,15 +904,15 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"int4x2",
"int4x3",
"int4x4",
- "interface",
+ // "interface", // Also reserved in WGSL
"isfinite",
"isinf",
"isnan",
// "ldexp", // WGSL builtin
// "length", // WGSL builtin
"lerp",
- "line",
- "lineadj",
+ // "line", // Also reserved in WGSL
+ // "lineadj", // Also reserved in WGSL
"linear",
"lit",
// "log", // WGSL builtin
@@ -1032,33 +1032,33 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
// "modf", // WGSL builtin
"msad4",
"mul",
- "mutable",
- "namespace",
- "new",
- "nointerpolation",
+ // "mutable", // Also reserved in WGSL
+ // "namespace", // Also reserved in WGSL
+ // "new", // Also reserved in WGSL
+ // "nointerpolation", // Also reserved in WGSL
"noise",
- "noperspective",
+ // "noperspective", // Also reserved in WGSL
// "normalize", // WGSL builtin
"numthreads",
- "operator",
+ // "operator", // Also reserved in WGSL
// "out", // WGSL keyword
- "packoffset",
- "pass",
- "pixelfragment",
+ // "packoffset", // Also reserved in WGSL
+ // "pass", // Also reserved in WGSL
+ // "pixelfragment", // Also reserved in WGSL
"pixelshader",
- "point",
+ // "point", // Also reserved in WGSL
// "pow", // WGSL builtin
- "precise",
+ // "precise", // Also reserved in WGSL
"printf",
// "private", // WGSL keyword
- "protected",
- "public",
+ // "protected", // Also reserved in WGSL
+ // "public", // Also reserved in WGSL
"radians",
"rcp",
// "reflect", // WGSL builtin
"refract",
- "register",
- "reinterpret_cast",
+ // "register", // Also reserved in WGSL
+ // "reinterpret_cast", // Also reserved in WGSL
// "return", // WGSL keyword
// "reversebits", // WGSL builtin
// "round", // WGSL builtin
@@ -1071,21 +1071,21 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"samplerCUBE",
"sampler_state",
"saturate",
- "shared",
+ // "shared", // Also reserved in WGSL
"short",
// "sign", // WGSL builtin
- "signed",
+ // "signed", // Also reserved in WGSL
// "sin", // WGSL builtin
"sincos",
// "sinh", // WGSL builtin
- "sizeof",
+ // "sizeof", // Also reserved in WGSL
// "smoothstep", // WGSL builtin
- "snorm",
+ // "snorm", // Also reserved in WGSL
// "sqrt", // WGSL builtin
"stateblock",
"stateblock_state",
- "static",
- "static_cast",
+ // "static", // Also reserved in WGSL
+ // "static_cast", // Also reserved in WGSL
// "step", // WGSL builtin
"string",
// "struct", // WGSL keyword
@@ -1096,7 +1096,7 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"technique",
"technique10",
"technique11",
- "template",
+ // "template", // Also reserved in WGSL
"tex1D",
"tex1Dbias",
"tex1Dgrad",
@@ -1127,16 +1127,16 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"texture3D",
"textureCube",
"textureCubeArray",
- "this",
- "throw",
+ // "this", // Also reserved in WGSL
+ // "throw", // Also reserved in WGSL
"transpose",
"triangle",
"triangleadj",
// "true", // WGSL keyword
// "trunc", // WGSL builtin
- "try",
+ // "try", // Also reserved in WGSL
// "typedef", // WGSL keyword
- "typename",
+ // "typename", // Also reserved in WGSL
"uint",
"uint1",
"uint1x1",
@@ -1159,17 +1159,17 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestHlsl,
"uint4x3",
"uint4x4",
// "uniform", // WGSL keyword
- "union",
- "unorm",
+ // "union", // Also reserved in WGSL
+ // "unorm", // Also reserved in WGSL
"unroll",
"unsigned",
// "using", // WGSL reserved keyword
"vector",
"vertexfragment",
"vertexshader",
- "virtual",
+ // "virtual", // Also reserved in WGSL
// "void", // WGSL keyword
- "volatile",
+ // "volatile", // Also reserved in WGSL
// "while" // WGSL reserved keyword
kUnicodeIdentifier));
@@ -1178,87 +1178,87 @@ INSTANTIATE_TEST_SUITE_P(
RenamerTestMsl,
testing::Values(
// c++14 spec
- "alignas",
- "alignof",
+ // "alignas", // Also reserved in WGSL
+ // "alignof", // Also reserved in WGSL
"and",
"and_eq",
// "asm", // Also reserved in WGSL
- "auto",
+ // "auto", // Also reserved in WGSL
"bitand",
"bitor",
// "bool", // Also used in WGSL
// "break", // Also used in WGSL
// "case", // Also used in WGSL
- "catch",
+ // "catch", // Also reserved in WGSL
"char",
"char16_t",
"char32_t",
- "class",
+ // "class", // Also reserved in WGSL
"compl",
// "const", // Also used in WGSL
- "const_cast",
- "constexpr",
+ // "const_cast", // Also reserved in WGSL
+ // "constexpr", // Also reserved in WGSL
// "continue", // Also used in WGSL
- "decltype",
+ // "decltype", // Also reserved in WGSL
// "default", // Also used in WGSL
- "delete",
+ // "delete", // Also reserved in WGSL
// "do", // Also used in WGSL
"double",
- "dynamic_cast",
+ // "dynamic_cast", // Also reserved in WGSL
// "else", // Also used in WGSL
// "enum", // Also used in WGSL
- "explicit",
- "extern",
+ // "explicit", // Also reserved in WGSL
+ // "extern", // Also reserved in WGSL
// "false", // Also used in WGSL
- "final",
+ // "final", // Also reserved in WGSL
"float",
// "for", // Also used in WGSL
- "friend",
- "goto",
+ // "friend", // Also reserved in WGSL
+ // "goto", // Also reserved in WGSL
// "if", // Also used in WGSL
- "inline",
+ // "inline", // Also reserved in WGSL
"int",
"long",
- "mutable",
- "namespace",
- "new",
- "noexcept",
+ // "mutable", // Also reserved in WGSL
+ // "namespace", // Also reserved in WGSL
+ // "new", // Also reserved in WGSL
+ // "noexcept", // Also reserved in WGSL
"not",
"not_eq",
- "nullptr",
- "operator",
+ // "nullptr", // Also reserved in WGSL
+ // "operator", // Also reserved in WGSL
"or",
"or_eq",
// "override", // Also used in WGSL
// "private", // Also used in WGSL
- "protected",
- "public",
- "register",
- "reinterpret_cast",
+ // "protected", // Also reserved in WGSL
+ // "public", // Also reserved in WGSL
+ // "register", // Also reserved in WGSL
+ // "reinterpret_cast", // Also reserved in WGSL
// "return", // Also used in WGSL
"short",
- "signed",
- "sizeof",
- "static",
- "static_assert",
- "static_cast",
+ // "signed", // Also reserved in WGSL
+ // "sizeof", // Also reserved in WGSL
+ // "static", // Also reserved in WGSL
+ // "static_assert", // Also reserved in WGSL
+ // "static_cast", // Also reserved in WGSL
// "struct", // Also used in WGSL
// "switch", // Also used in WGSL
- "template",
- "this",
- "thread_local",
- "throw",
+ // "template", // Also reserved in WGSL
+ // "this", // Also reserved in WGSL
+ // "thread_local", // Also reserved in WGSL
+ // "throw", // Also reserved in WGSL
// "true", // Also used in WGSL
- "try",
+ // "try", // Also reserved in WGSL
// "typedef", // Also used in WGSL
- "typeid",
- "typename",
- "union",
+ // "typeid", // Also reserved in WGSL
+ // "typename", // Also reserved in WGSL
+ // "union", // Also reserved in WGSL
"unsigned",
// "using", // WGSL reserved keyword
- "virtual",
+ // "virtual", // Also reserved in WGSL
// "void", // Also used in WGSL
- "volatile",
+ // "volatile", // Also reserved in WGSL
"wchar_t",
// "while", // WGSL reserved keyword
"xor",
diff --git a/chromium/third_party/dawn/src/tint/transform/robustness.cc b/chromium/third_party/dawn/src/tint/transform/robustness.cc
index aab1e0cc00b..beb11082f1b 100644
--- a/chromium/third_party/dawn/src/tint/transform/robustness.cc
+++ b/chromium/third_party/dawn/src/tint/transform/robustness.cc
@@ -120,17 +120,18 @@ struct Robustness::State {
return nullptr;
}
- if (auto idx_constant = idx_sem->ConstantValue()) {
+ if (auto* idx_constant = idx_sem->ConstantValue()) {
// Constant value index
- if (idx_constant.Type()->Is<sem::I32>()) {
- idx.i32 = static_cast<int32_t>(idx_constant.Element<AInt>(0).value);
+ auto val = std::get<AInt>(idx_constant->Value());
+ if (idx_constant->Type()->Is<sem::I32>()) {
+ idx.i32 = static_cast<int32_t>(val);
idx.is_signed = true;
- } else if (idx_constant.Type()->Is<sem::U32>()) {
- idx.u32 = static_cast<uint32_t>(idx_constant.Element<AInt>(0).value);
+ } else if (idx_constant->Type()->Is<sem::U32>()) {
+ idx.u32 = static_cast<uint32_t>(val);
idx.is_signed = false;
} else {
TINT_ICE(Transform, b.Diagnostics()) << "unsupported constant value for accessor "
- << idx_constant.Type()->TypeInfo().name;
+ << idx_constant->Type()->TypeInfo().name;
return nullptr;
}
} else {
@@ -223,9 +224,9 @@ struct Robustness::State {
auto array_idx = signature.IndexOf(sem::ParameterUsage::kArrayIndex);
auto level_idx = signature.IndexOf(sem::ParameterUsage::kLevel);
- auto* texture_arg = expr->args[texture_idx];
- auto* coords_arg = expr->args[coords_idx];
- auto* coords_ty = builtin->Parameters()[coords_idx]->Type();
+ auto* texture_arg = expr->args[static_cast<size_t>(texture_idx)];
+ auto* coords_arg = expr->args[static_cast<size_t>(coords_idx)];
+ auto* coords_ty = builtin->Parameters()[static_cast<size_t>(coords_idx)]->Type();
// If the level is provided, then we need to clamp this. As the level is
// used by textureDimensions() and the texture[Load|Store]() calls, we need
@@ -235,7 +236,7 @@ struct Robustness::State {
std::function<const ast::Expression*()> level_arg;
if (level_idx >= 0) {
level_arg = [&] {
- auto* arg = expr->args[level_idx];
+ auto* arg = expr->args[static_cast<size_t>(level_idx)];
auto* num_levels = b.Call("textureNumLevels", ctx.Clone(texture_arg));
auto* zero = b.Expr(0_i);
auto* max = ctx.dst->Sub(num_levels, 1_i);
@@ -258,7 +259,7 @@ struct Robustness::State {
// Clamp the array_index argument, if provided
if (array_idx >= 0) {
- auto* arg = expr->args[array_idx];
+ auto* arg = expr->args[static_cast<size_t>(array_idx)];
auto* num_layers = b.Call("textureNumLayers", ctx.Clone(texture_arg));
auto* zero = b.Expr(0_i);
auto* max = ctx.dst->Sub(num_layers, 1_i);
@@ -268,7 +269,7 @@ struct Robustness::State {
// Clamp the level argument, if provided
if (level_idx >= 0) {
- auto* arg = expr->args[level_idx];
+ auto* arg = expr->args[static_cast<size_t>(level_idx)];
ctx.Replace(arg, level_arg ? level_arg() : ctx.dst->Expr(0_i));
}
diff --git a/chromium/third_party/dawn/src/tint/transform/robustness.h b/chromium/third_party/dawn/src/tint/transform/robustness.h
index 138b48cec3d..549b666bb78 100644
--- a/chromium/third_party/dawn/src/tint/transform/robustness.h
+++ b/chromium/third_party/dawn/src/tint/transform/robustness.h
@@ -31,7 +31,7 @@ namespace tint::transform {
/// the bounds of the array. Any access before the start of the array will clamp
/// to zero and any access past the end of the array will clamp to
/// (array length - 1).
-class Robustness : public Castable<Robustness, Transform> {
+class Robustness final : public Castable<Robustness, Transform> {
public:
/// Storage class to be skipped in the transform
enum class StorageClass {
@@ -40,7 +40,7 @@ class Robustness : public Castable<Robustness, Transform> {
};
/// Configuration options for the transform
- struct Config : public Castable<Config, Data> {
+ struct Config final : public Castable<Config, Data> {
/// Constructor
Config();
diff --git a/chromium/third_party/dawn/src/tint/transform/robustness_test.cc b/chromium/third_party/dawn/src/tint/transform/robustness_test.cc
index fb0e5a40a6f..8dab5957258 100644
--- a/chromium/third_party/dawn/src/tint/transform/robustness_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/robustness_test.cc
@@ -21,7 +21,7 @@ namespace {
using RobustnessTest = TransformTest;
-TEST_F(RobustnessTest, Array_Idx_Clamp) {
+TEST_F(RobustnessTest, Array_Let_Idx_Clamp) {
auto* src = R"(
var<private> a : array<f32, 3>;
@@ -35,7 +35,7 @@ fn f() {
auto* expect = R"(
var<private> a : array<f32, 3>;
-let c : u32 = 1u;
+const c : u32 = 1u;
fn f() {
let b : f32 = a[1u];
@@ -47,7 +47,33 @@ fn f() {
EXPECT_EQ(expect, str(got));
}
-TEST_F(RobustnessTest, Array_Idx_Clamp_OutOfOrder) {
+TEST_F(RobustnessTest, Array_Const_Idx_Clamp) {
+ auto* src = R"(
+var<private> a : array<f32, 3>;
+
+const c : u32 = 1u;
+
+fn f() {
+ let b : f32 = a[c];
+}
+)";
+
+ auto* expect = R"(
+var<private> a : array<f32, 3>;
+
+const c : u32 = 1u;
+
+fn f() {
+ let b : f32 = a[1u];
+}
+)";
+
+ auto got = Run<Robustness>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RobustnessTest, Array_Let_Idx_Clamp_OutOfOrder) {
auto* src = R"(
fn f() {
let b : f32 = a[c];
@@ -63,7 +89,33 @@ fn f() {
let b : f32 = a[1u];
}
-let c : u32 = 1u;
+const c : u32 = 1u;
+
+var<private> a : array<f32, 3>;
+)";
+
+ auto got = Run<Robustness>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RobustnessTest, Array_Const_Idx_Clamp_OutOfOrder) {
+ auto* src = R"(
+fn f() {
+ let b : f32 = a[c];
+}
+
+const c : u32 = 1u;
+
+var<private> a : array<f32, 3>;
+)";
+
+ auto* expect = R"(
+fn f() {
+ let b : f32 = a[1u];
+}
+
+const c : u32 = 1u;
var<private> a : array<f32, 3>;
)";
@@ -1392,7 +1444,7 @@ struct S {
@group(0) @binding(0) var<storage, read> s : S;
-let c : u32 = 1u;
+const c : u32 = 1u;
fn f() {
let b : f32 = s.b[c];
@@ -1409,7 +1461,7 @@ struct S {
@group(0) @binding(0) var<storage, read> s : S;
-let c : u32 = 1u;
+const c : u32 = 1u;
fn f() {
let b : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
diff --git a/chromium/third_party/dawn/src/tint/transform/simplify_pointers.cc b/chromium/third_party/dawn/src/tint/transform/simplify_pointers.cc
index b8f82bc49a5..4190312f512 100644
--- a/chromium/third_party/dawn/src/tint/transform/simplify_pointers.cc
+++ b/chromium/third_party/dawn/src/tint/transform/simplify_pointers.cc
@@ -109,8 +109,8 @@ struct SimplifyPointers::State {
}
if (auto* user = ctx.src->Sem().Get<sem::VariableUser>(op.expr)) {
auto* var = user->Variable();
- if (var->Is<sem::LocalVariable>() && //
- var->Declaration()->is_const && //
+ if (var->Is<sem::LocalVariable>() && //
+ var->Declaration()->Is<ast::Let>() && //
var->Type()->Is<sem::Pointer>()) {
op.expr = var->Declaration()->constructor;
continue;
@@ -161,7 +161,7 @@ struct SimplifyPointers::State {
// permitted.
for (auto* node : ctx.src->ASTNodes().Objects()) {
if (auto* let = node->As<ast::VariableDeclStatement>()) {
- if (!let->variable->is_const) {
+ if (!let->variable->Is<ast::Let>()) {
continue; // Not a `let` declaration. Ignore.
}
diff --git a/chromium/third_party/dawn/src/tint/transform/simplify_pointers.h b/chromium/third_party/dawn/src/tint/transform/simplify_pointers.h
index 267b7b2d323..787c7d815f8 100644
--- a/chromium/third_party/dawn/src/tint/transform/simplify_pointers.h
+++ b/chromium/third_party/dawn/src/tint/transform/simplify_pointers.h
@@ -31,7 +31,7 @@ namespace tint::transform {
///
/// @note Depends on the following transforms to have been run first:
/// * Unshadow
-class SimplifyPointers : public Castable<SimplifyPointers, Transform> {
+class SimplifyPointers final : public Castable<SimplifyPointers, Transform> {
public:
/// Constructor
SimplifyPointers();
diff --git a/chromium/third_party/dawn/src/tint/transform/single_entry_point.cc b/chromium/third_party/dawn/src/tint/transform/single_entry_point.cc
index 82324c77453..133c836e073 100644
--- a/chromium/third_party/dawn/src/tint/transform/single_entry_point.cc
+++ b/chromium/third_party/dawn/src/tint/transform/single_entry_point.cc
@@ -64,38 +64,43 @@ void SingleEntryPoint::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) c
referenced_vars.emplace(var->Declaration());
}
- // Clone any module-scope variables, types, and functions that are statically
- // referenced by the target entry point.
+ // Clone any module-scope variables, types, and functions that are statically referenced by the
+ // target entry point.
for (auto* decl : ctx.src->AST().GlobalDeclarations()) {
- if (auto* ty = decl->As<ast::TypeDecl>()) {
- // TODO(jrprice): Strip unused types.
- ctx.dst->AST().AddTypeDecl(ctx.Clone(ty));
- } else if (auto* var = decl->As<ast::Variable>()) {
- if (referenced_vars.count(var)) {
- if (var->is_overridable) {
- // It is an overridable constant
- if (!ast::HasAttribute<ast::IdAttribute>(var->attributes)) {
- // If the constant doesn't already have an @id() attribute, add one
+ Switch(
+ decl, //
+ [&](const ast::TypeDecl* ty) {
+ // TODO(jrprice): Strip unused types.
+ ctx.dst->AST().AddTypeDecl(ctx.Clone(ty));
+ },
+ [&](const ast::Override* override) {
+ if (referenced_vars.count(override)) {
+ if (!ast::HasAttribute<ast::IdAttribute>(override->attributes)) {
+ // If the override doesn't already have an @id() attribute, add one
// so that its allocated ID so that it won't be affected by other
- // stripped away constants
- auto* global = sem.Get(var)->As<sem::GlobalVariable>();
- const auto* id = ctx.dst->Id(global->ConstantId());
- ctx.InsertFront(var->attributes, id);
+ // stripped away overrides
+ auto* global = sem.Get(override);
+ const auto* id = ctx.dst->Id(global->OverrideId());
+ ctx.InsertFront(override->attributes, id);
}
+ ctx.dst->AST().AddGlobalVariable(ctx.Clone(override));
}
- ctx.dst->AST().AddGlobalVariable(ctx.Clone(var));
- }
- } else if (auto* func = decl->As<ast::Function>()) {
- if (sem.Get(func)->HasAncestorEntryPoint(entry_point->symbol)) {
- ctx.dst->AST().AddFunction(ctx.Clone(func));
- }
- } else if (auto* ext = decl->As<ast::Enable>()) {
- ctx.dst->AST().AddEnable(ctx.Clone(ext));
- } else {
- TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
- << "unhandled global declaration: " << decl->TypeInfo().name;
- return;
- }
+ },
+ [&](const ast::Variable* v) { // var, let
+ if (referenced_vars.count(v)) {
+ ctx.dst->AST().AddGlobalVariable(ctx.Clone(v));
+ }
+ },
+ [&](const ast::Function* func) {
+ if (sem.Get(func)->HasAncestorEntryPoint(entry_point->symbol)) {
+ ctx.dst->AST().AddFunction(ctx.Clone(func));
+ }
+ },
+ [&](const ast::Enable* ext) { ctx.dst->AST().AddEnable(ctx.Clone(ext)); },
+ [&](Default) {
+ TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
+ << "unhandled global declaration: " << decl->TypeInfo().name;
+ });
}
// Clone the entry point.
diff --git a/chromium/third_party/dawn/src/tint/transform/single_entry_point.h b/chromium/third_party/dawn/src/tint/transform/single_entry_point.h
index 0a922a78d03..59aa021466f 100644
--- a/chromium/third_party/dawn/src/tint/transform/single_entry_point.h
+++ b/chromium/third_party/dawn/src/tint/transform/single_entry_point.h
@@ -25,10 +25,10 @@ namespace tint::transform {
///
/// All module-scope variables, types, and functions that are not used by the
/// target entry point will also be removed.
-class SingleEntryPoint : public Castable<SingleEntryPoint, Transform> {
+class SingleEntryPoint final : public Castable<SingleEntryPoint, Transform> {
public:
/// Configuration options for the transform
- struct Config : public Castable<Config, Data> {
+ struct Config final : public Castable<Config, Data> {
/// Constructor
/// @param entry_point the name of the entry point to keep
explicit Config(std::string entry_point = "");
diff --git a/chromium/third_party/dawn/src/tint/transform/single_entry_point_test.cc b/chromium/third_party/dawn/src/tint/transform/single_entry_point_test.cc
index 8445f61f013..020bd65c444 100644
--- a/chromium/third_party/dawn/src/tint/transform/single_entry_point_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/single_entry_point_test.cc
@@ -186,13 +186,13 @@ fn comp_main1() {
TEST_F(SingleEntryPointTest, GlobalConstants) {
auto* src = R"(
-let a : f32 = 1.0;
+const a : f32 = 1.0;
-let b : f32 = 1.0;
+const b : f32 = 1.0;
-let c : f32 = 1.0;
+const c : f32 = 1.0;
-let d : f32 = 1.0;
+const d : f32 = 1.0;
@vertex
fn vert_main() -> @builtin(position) vec4<f32> {
@@ -217,7 +217,7 @@ fn comp_main2() {
)";
auto* expect = R"(
-let c : f32 = 1.0;
+const c : f32 = 1.0;
@compute @workgroup_size(1)
fn comp_main1() {
@@ -243,6 +243,32 @@ fn main() {
}
)";
+ auto* expect = R"(
+const size : i32 = 1;
+
+@compute @workgroup_size(size)
+fn main() {
+}
+)";
+
+ SingleEntryPoint::Config cfg("main");
+
+ DataMap data;
+ data.Add<SingleEntryPoint::Config>(cfg);
+ auto got = Run<SingleEntryPoint>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SingleEntryPointTest, WorkgroupSizeConstPreserved) {
+ auto* src = R"(
+const size : i32 = 1;
+
+@compute @workgroup_size(size)
+fn main() {
+}
+)";
+
auto* expect = src;
SingleEntryPoint::Config cfg("main");
diff --git a/chromium/third_party/dawn/src/tint/transform/spirv_atomic.cc b/chromium/third_party/dawn/src/tint/transform/spirv_atomic.cc
new file mode 100644
index 00000000000..bece2d65385
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/spirv_atomic.cc
@@ -0,0 +1,302 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/spirv_atomic.h"
+
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/block_statement.h"
+#include "src/tint/sem/function.h"
+#include "src/tint/sem/index_accessor_expression.h"
+#include "src/tint/sem/member_accessor_expression.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/statement.h"
+#include "src/tint/utils/map.h"
+#include "src/tint/utils/unique_vector.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::transform::SpirvAtomic);
+TINT_INSTANTIATE_TYPEINFO(tint::transform::SpirvAtomic::Stub);
+
+namespace tint::transform {
+
+/// Private implementation of transform
+struct SpirvAtomic::State {
+ private:
+ /// A struct that has been forked because a subset of members were made atomic.
+ struct ForkedStruct {
+ Symbol name;
+ std::unordered_set<size_t> atomic_members;
+ };
+
+ CloneContext& ctx;
+ ProgramBuilder& b = *ctx.dst;
+ std::unordered_map<const ast::Struct*, ForkedStruct> forked_structs;
+ std::unordered_set<const sem::Variable*> atomic_variables;
+ utils::UniqueVector<const sem::Expression*, 8> atomic_expressions;
+
+ public:
+ /// Constructor
+ /// @param c the clone context
+ explicit State(CloneContext& c) : ctx(c) {}
+
+ /// Runs the transform
+ void Run() {
+ // Look for stub functions generated by the SPIR-V reader, which are used as placeholders
+ // for atomic builtin calls.
+ for (auto* fn : ctx.src->AST().Functions()) {
+ if (auto* stub = ast::GetAttribute<Stub>(fn->attributes)) {
+ auto* sem = ctx.src->Sem().Get(fn);
+
+ for (auto* call : sem->CallSites()) {
+ // The first argument is always the atomic.
+ // The stub passes this by value, whereas the builtin wants a pointer.
+ // Take the address of the atomic argument.
+ auto& args = call->Declaration()->args;
+ auto out_args = ctx.Clone(args);
+ out_args[0] = b.AddressOf(out_args[0]);
+
+ // Replace all callsites of this stub to a call to the real builtin
+ if (stub->builtin == sem::BuiltinType::kAtomicCompareExchangeWeak) {
+ // atomicCompareExchangeWeak returns a struct, so insert a call to it above
+ // the current statement, and replace the current call with the struct's
+ // `old_value` member.
+ auto* block = call->Stmt()->Block()->Declaration();
+ auto old_value = b.Symbols().New("old_value");
+ auto old_value_decl = b.Decl(b.Let(
+ old_value, nullptr,
+ b.MemberAccessor(b.Call(sem::str(stub->builtin), std::move(out_args)),
+ b.Expr("old_value"))));
+ ctx.InsertBefore(block->statements, call->Stmt()->Declaration(),
+ old_value_decl);
+ ctx.Replace(call->Declaration(), b.Expr(old_value));
+ } else {
+ ctx.Replace(call->Declaration(),
+ b.Call(sem::str(stub->builtin), std::move(out_args)));
+ }
+
+ // Keep track of this expression. We'll need to modify the source variable /
+ // structure to be atomic.
+ atomic_expressions.Add(ctx.src->Sem().Get(args[0]));
+ }
+
+ // Remove the stub from the output program
+ ctx.Remove(ctx.src->AST().GlobalDeclarations(), fn);
+ }
+ }
+
+ // Transform all variables and structure members that were used in atomic operations as
+ // atomic types. This propagates up originating expression chains.
+ ProcessAtomicExpressions();
+
+ // If we need to change structure members, then fork them.
+ if (!forked_structs.empty()) {
+ ctx.ReplaceAll([&](const ast::Struct* str) {
+ // Always emit the original structure. This allows unrelated usage of the structure
+ // to continue working.
+ // auto* original = ctx.CloneWithoutTransform(str);
+
+ // Is `str` a structure we need to fork?
+ if (auto it = forked_structs.find(str); it != forked_structs.end()) {
+ const auto& forked = it->second;
+
+ // Re-create the structure swapping in the atomic-flavoured members
+ utils::Vector<const ast::StructMember*, 8> members;
+ members.Reserve(str->members.Length());
+ for (size_t i = 0; i < str->members.Length(); i++) {
+ auto* member = str->members[i];
+ if (forked.atomic_members.count(i)) {
+ auto* type = AtomicTypeFor(ctx.src->Sem().Get(member)->Type());
+ auto name = ctx.src->Symbols().NameFor(member->symbol);
+ members.Push(b.Member(name, type, ctx.Clone(member->attributes)));
+ } else {
+ members.Push(ctx.Clone(member));
+ }
+ }
+ b.Structure(forked.name, std::move(members));
+ }
+
+ // return original;
+ return nullptr;
+ });
+ }
+
+ // Replace assignments and decls from atomic variables with atomicLoads, and assignments to
+ // atomic variables with atomicStores.
+ ReplaceLoadsAndStores();
+
+ ctx.Clone();
+ }
+
+ private:
+ ForkedStruct& Fork(const ast::Struct* str) {
+ auto& forked = forked_structs[str];
+ if (!forked.name.IsValid()) {
+ forked.name = b.Symbols().New(ctx.src->Symbols().NameFor(str->name) + "_atomic");
+ }
+ return forked;
+ }
+
+ void ProcessAtomicExpressions() {
+ for (size_t i = 0; i < atomic_expressions.Length(); i++) {
+ Switch(
+ atomic_expressions[i], //
+ [&](const sem::VariableUser* user) {
+ auto* v = user->Variable()->Declaration();
+ if (v->type && atomic_variables.emplace(user->Variable()).second) {
+ ctx.Replace(v->type, AtomicTypeFor(user->Variable()->Type()));
+ }
+ if (auto* ctor = user->Variable()->Constructor()) {
+ atomic_expressions.Add(ctor);
+ }
+ },
+ [&](const sem::StructMemberAccess* access) {
+ // Fork the struct (the first time) and mark member(s) that need to be made
+ // atomic.
+ auto* member = access->Member();
+ Fork(member->Struct()->Declaration()).atomic_members.emplace(member->Index());
+ atomic_expressions.Add(access->Object());
+ },
+ [&](const sem::IndexAccessorExpression* index) {
+ atomic_expressions.Add(index->Object());
+ },
+ [&](const sem::Expression* e) {
+ if (auto* unary = e->Declaration()->As<ast::UnaryOpExpression>()) {
+ atomic_expressions.Add(ctx.src->Sem().Get(unary->expr));
+ }
+ });
+ }
+ }
+
+ const ast::Type* AtomicTypeFor(const sem::Type* ty) {
+ return Switch(
+ ty, //
+ [&](const sem::I32*) { return b.ty.atomic(CreateASTTypeFor(ctx, ty)); },
+ [&](const sem::U32*) { return b.ty.atomic(CreateASTTypeFor(ctx, ty)); },
+ [&](const sem::Struct* str) { return b.ty.type_name(Fork(str->Declaration()).name); },
+ [&](const sem::Array* arr) {
+ return arr->IsRuntimeSized()
+ ? b.ty.array(AtomicTypeFor(arr->ElemType()))
+ : b.ty.array(AtomicTypeFor(arr->ElemType()), u32(arr->Count()));
+ },
+ [&](const sem::Pointer* ptr) {
+ return b.ty.pointer(AtomicTypeFor(ptr->StoreType()), ptr->StorageClass(),
+ ptr->Access());
+ },
+ [&](const sem::Reference* ref) { return AtomicTypeFor(ref->StoreType()); },
+ [&](Default) {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "unhandled type: " << ty->FriendlyName(ctx.src->Symbols());
+ return nullptr;
+ });
+ }
+
+ void ReplaceLoadsAndStores() {
+ // Returns true if 'e' is a reference to an atomic variable or struct member
+ auto is_ref_to_atomic_var = [&](const sem::Expression* e) {
+ if (tint::Is<sem::Reference>(e->Type()) && e->SourceVariable() &&
+ (atomic_variables.count(e->SourceVariable()) != 0)) {
+ // If it's a struct member, make sure it's one we marked as atomic
+ if (auto* ma = e->As<sem::StructMemberAccess>()) {
+ auto it = forked_structs.find(ma->Member()->Struct()->Declaration());
+ if (it != forked_structs.end()) {
+ auto& forked = it->second;
+ return forked.atomic_members.count(ma->Member()->Index()) != 0;
+ }
+ }
+ return true;
+ }
+ return false;
+ };
+
+ // Look for loads and stores via assignments and decls of atomic variables we've collected
+ // so far, and replace them with atomicLoad and atomicStore.
+ for (auto* atomic_var : atomic_variables) {
+ for (auto* vu : atomic_var->Users()) {
+ Switch(
+ vu->Stmt()->Declaration(),
+ [&](const ast::AssignmentStatement* assign) {
+ auto* sem_lhs = ctx.src->Sem().Get(assign->lhs);
+ if (is_ref_to_atomic_var(sem_lhs)) {
+ ctx.Replace(assign, [=] {
+ auto* lhs = ctx.CloneWithoutTransform(assign->lhs);
+ auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
+ auto* call = b.Call(sem::str(sem::BuiltinType::kAtomicStore),
+ b.AddressOf(lhs), rhs);
+ return b.CallStmt(call);
+ });
+ return;
+ }
+
+ auto sem_rhs = ctx.src->Sem().Get(assign->rhs);
+ if (is_ref_to_atomic_var(sem_rhs)) {
+ ctx.Replace(assign->rhs, [=] {
+ auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
+ return b.Call(sem::str(sem::BuiltinType::kAtomicLoad),
+ b.AddressOf(rhs));
+ });
+ return;
+ }
+ },
+ [&](const ast::VariableDeclStatement* decl) {
+ auto* var = decl->variable;
+ if (auto* sem_ctor = ctx.src->Sem().Get(var->constructor)) {
+ if (is_ref_to_atomic_var(sem_ctor)) {
+ ctx.Replace(var->constructor, [=] {
+ auto* rhs = ctx.CloneWithoutTransform(var->constructor);
+ return b.Call(sem::str(sem::BuiltinType::kAtomicLoad),
+ b.AddressOf(rhs));
+ });
+ return;
+ }
+ }
+ });
+ }
+ }
+ }
+};
+
+SpirvAtomic::SpirvAtomic() = default;
+SpirvAtomic::~SpirvAtomic() = default;
+
+SpirvAtomic::Stub::Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType b)
+ : Base(pid, nid), builtin(b) {}
+SpirvAtomic::Stub::~Stub() = default;
+std::string SpirvAtomic::Stub::InternalName() const {
+ return "@internal(spirv-atomic " + std::string(sem::str(builtin)) + ")";
+}
+
+const SpirvAtomic::Stub* SpirvAtomic::Stub::Clone(CloneContext* ctx) const {
+ return ctx->dst->ASTNodes().Create<SpirvAtomic::Stub>(ctx->dst->ID(),
+ ctx->dst->AllocateNodeID(), builtin);
+}
+
+bool SpirvAtomic::ShouldRun(const Program* program, const DataMap&) const {
+ for (auto* fn : program->AST().Functions()) {
+ if (ast::HasAttribute<Stub>(fn->attributes)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SpirvAtomic::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+ State{ctx}.Run();
+}
+
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/spirv_atomic.h b/chromium/third_party/dawn/src/tint/transform/spirv_atomic.h
new file mode 100644
index 00000000000..e1311c59520
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/spirv_atomic.h
@@ -0,0 +1,85 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_TRANSFORM_SPIRV_ATOMIC_H_
+#define SRC_TINT_TRANSFORM_SPIRV_ATOMIC_H_
+
+#include <string>
+
+#include "src/tint/ast/internal_attribute.h"
+#include "src/tint/sem/builtin_type.h"
+#include "src/tint/transform/transform.h"
+
+// Forward declarations
+namespace tint {
+class CloneContext;
+} // namespace tint
+
+namespace tint::transform {
+
+/// SpirvAtomic is a transform that replaces calls to stub functions created by the SPIR-V reader
+/// with calls to the WGSL atomic builtin. It also makes sure to replace variable declarations that
+/// are the target of the atomic operations with an atomic declaration of the same type. For
+/// structs, it creates a copy of the original struct with atomic members.
+class SpirvAtomic final : public Castable<SpirvAtomic, Transform> {
+ public:
+ /// Constructor
+ SpirvAtomic();
+ /// Destructor
+ ~SpirvAtomic() override;
+
+ /// Stub is an attribute applied to stub SPIR-V reader generated functions that need to be
+ /// translated to an atomic builtin.
+ class Stub final : public Castable<Stub, ast::InternalAttribute> {
+ public:
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param builtin the atomic builtin this stub represents
+ Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType builtin);
+ /// Destructor
+ ~Stub() override;
+
+ /// @return a short description of the internal attribute which will be
+ /// displayed as `@internal(<name>)`
+ std::string InternalName() const override;
+
+ /// Performs a deep clone of this object using the CloneContext `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned object
+ const Stub* Clone(CloneContext* ctx) const override;
+
+ /// The type of the intrinsic
+ const sem::BuiltinType builtin;
+ };
+
+ /// @param program the program to inspect
+ /// @param data optional extra transform-specific input data
+ /// @returns true if this transform should be run for the given program
+ bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
+
+ protected:
+ struct State;
+
+ /// Runs the transform using the CloneContext built for transforming a
+ /// program. Run() is responsible for calling Clone() on the CloneContext.
+ /// @param ctx the CloneContext primed with the input program and
+ /// ProgramBuilder
+ /// @param inputs optional extra transform-specific input data
+ /// @param outputs optional extra transform-specific output data
+ void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
+};
+
+} // namespace tint::transform
+
+#endif // SRC_TINT_TRANSFORM_SPIRV_ATOMIC_H_
diff --git a/chromium/third_party/dawn/src/tint/transform/spirv_atomic_test.cc b/chromium/third_party/dawn/src/tint/transform/spirv_atomic_test.cc
new file mode 100644
index 00000000000..7f6db34e16f
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/spirv_atomic_test.cc
@@ -0,0 +1,1410 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/spirv_atomic.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "src/tint/reader/wgsl/parser_impl.h"
+#include "src/tint/transform/test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::transform {
+namespace {
+
+class SpirvAtomicTest : public TransformTest {
+ public:
+ Output Run(std::string in) {
+ auto file = std::make_unique<Source::File>("test", std::move(in));
+ auto parser = reader::wgsl::ParserImpl(file.get());
+ parser.Parse();
+
+ auto& b = parser.builder();
+
+ sem::BuiltinType two_params[] = {
+ sem::BuiltinType::kAtomicExchange, sem::BuiltinType::kAtomicAdd,
+ sem::BuiltinType::kAtomicSub, sem::BuiltinType::kAtomicMin,
+ sem::BuiltinType::kAtomicMax, sem::BuiltinType::kAtomicAnd,
+ sem::BuiltinType::kAtomicOr, sem::BuiltinType::kAtomicXor,
+ };
+ for (auto& a : two_params) {
+ b.Func(std::string{"stub_"} + sem::str(a) + "_u32",
+ utils::Vector{
+ b.Param("p0", b.ty.u32()),
+ b.Param("p1", b.ty.u32()),
+ },
+ b.ty.u32(),
+ utils::Vector{
+ b.Return(0_u),
+ },
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(), a),
+ });
+ b.Func(std::string{"stub_"} + sem::str(a) + "_i32",
+ utils::Vector{
+ b.Param("p0", b.ty.i32()),
+ b.Param("p1", b.ty.i32()),
+ },
+ b.ty.i32(),
+ utils::Vector{
+ b.Return(0_i),
+ },
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(), a),
+ });
+ }
+
+ b.Func("stub_atomicLoad_u32",
+ utils::Vector{
+ b.Param("p0", b.ty.u32()),
+ },
+ b.ty.u32(),
+ utils::Vector{
+ b.Return(0_u),
+ },
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
+ sem::BuiltinType::kAtomicLoad),
+ });
+ b.Func("stub_atomicLoad_i32",
+ utils::Vector{
+ b.Param("p0", b.ty.i32()),
+ },
+ b.ty.i32(),
+ utils::Vector{
+ b.Return(0_i),
+ },
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
+ sem::BuiltinType::kAtomicLoad),
+ });
+
+ b.Func("stub_atomicStore_u32",
+ utils::Vector{
+ b.Param("p0", b.ty.u32()),
+ b.Param("p1", b.ty.u32()),
+ },
+ b.ty.void_(), utils::Empty,
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
+ sem::BuiltinType::kAtomicStore),
+ });
+ b.Func("stub_atomicStore_i32",
+ utils::Vector{
+ b.Param("p0", b.ty.i32()),
+ b.Param("p1", b.ty.i32()),
+ },
+ b.ty.void_(), utils::Empty,
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
+ sem::BuiltinType::kAtomicStore),
+ });
+
+ b.Func("stub_atomic_compare_exchange_weak_u32",
+ utils::Vector{
+ b.Param("p0", b.ty.u32()),
+ b.Param("p1", b.ty.u32()),
+ b.Param("p2", b.ty.u32()),
+ },
+ b.ty.u32(),
+ utils::Vector{
+ b.Return(0_u),
+ },
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(
+ b.ID(), b.AllocateNodeID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
+ });
+ b.Func("stub_atomic_compare_exchange_weak_i32",
+ utils::Vector{b.Param("p0", b.ty.i32()), b.Param("p1", b.ty.i32()),
+ b.Param("p2", b.ty.i32())},
+ b.ty.i32(),
+ utils::Vector{
+ b.Return(0_i),
+ },
+ utils::Vector{
+ b.ASTNodes().Create<SpirvAtomic::Stub>(
+ b.ID(), b.AllocateNodeID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
+ });
+
+ // Keep this pointer alive after Transform() returns
+ files_.emplace_back(std::move(file));
+
+ return TransformTest::Run<SpirvAtomic>(Program(std::move(b)));
+ }
+
+ private:
+ std::vector<std::unique_ptr<Source::File>> files_;
+};
+
+TEST_F(SpirvAtomicTest, ArrayOfU32) {
+ auto* src = R"(
+var<workgroup> wg : array<u32, 4>;
+
+fn f() {
+ stub_atomicStore_u32(wg[1], 1u);
+}
+)";
+
+ auto* expect = R"(
+var<workgroup> wg : array<atomic<u32>, 4u>;
+
+fn f() {
+ atomicStore(&(wg[1]), 1u);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ArraysOfU32) {
+ auto* src = R"(
+var<workgroup> wg : array<array<array<u32, 1>, 2>, 3>;
+
+fn f() {
+ stub_atomicStore_u32(wg[2][1][0], 1u);
+}
+)";
+
+ auto* expect = R"(
+var<workgroup> wg : array<array<array<atomic<u32>, 1u>, 2u>, 3u>;
+
+fn f() {
+ atomicStore(&(wg[2][1][0]), 1u);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AliasedArraysOfU32) {
+ auto* src = R"(
+type A0 = u32;
+
+type A1 = array<A0, 1>;
+
+type A2 = array<A1, 2>;
+
+type A3 = array<A2, 3>;
+
+var<workgroup> wg : A3;
+
+fn f() {
+ stub_atomicStore_u32(wg[2][1][0], 1u);
+}
+)";
+
+ auto* expect = R"(
+type A0 = u32;
+
+type A1 = array<A0, 1>;
+
+type A2 = array<A1, 2>;
+
+type A3 = array<A2, 3>;
+
+var<workgroup> wg : array<array<array<atomic<u32>, 1u>, 2u>, 3u>;
+
+fn f() {
+ atomicStore(&(wg[2][1][0]), 1u);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, FlatStructSingleAtomic) {
+ auto* src = R"(
+struct S {
+ a : u32,
+}
+
+var<workgroup> wg : S;
+
+fn f() {
+ stub_atomicStore_u32(wg.a, 1u);
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : atomic<u32>,
+}
+
+struct S {
+ a : u32,
+}
+
+var<workgroup> wg : S_atomic;
+
+fn f() {
+ atomicStore(&(wg.a), 1u);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, FlatStructMultipleAtomic) {
+ auto* src = R"(
+struct S {
+ a : u32,
+ b : i32,
+}
+
+var<workgroup> wg : S;
+
+fn f1() {
+ stub_atomicStore_u32(wg.a, 1u);
+}
+
+fn f2() {
+ stub_atomicStore_i32(wg.b, 2i);
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : atomic<u32>,
+ b : atomic<i32>,
+}
+
+struct S {
+ a : u32,
+ b : i32,
+}
+
+var<workgroup> wg : S_atomic;
+
+fn f1() {
+ atomicStore(&(wg.a), 1u);
+}
+
+fn f2() {
+ atomicStore(&(wg.b), 2i);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, NestedStruct) {
+ auto* src = R"(
+struct S0 {
+ a : u32,
+ b : i32,
+ c : u32,
+}
+
+struct S1 {
+ a : i32,
+ b : u32,
+ c : S0,
+}
+
+struct S2 {
+ a : i32,
+ b : S1,
+ c : u32,
+}
+
+var<workgroup> wg : S2;
+
+fn f() {
+ stub_atomicStore_u32(wg.b.c.a, 1u);
+}
+)";
+
+ auto* expect = R"(
+struct S0_atomic {
+ a : atomic<u32>,
+ b : i32,
+ c : u32,
+}
+
+struct S0 {
+ a : u32,
+ b : i32,
+ c : u32,
+}
+
+struct S1_atomic {
+ a : i32,
+ b : u32,
+ c : S0_atomic,
+}
+
+struct S1 {
+ a : i32,
+ b : u32,
+ c : S0,
+}
+
+struct S2_atomic {
+ a : i32,
+ b : S1_atomic,
+ c : u32,
+}
+
+struct S2 {
+ a : i32,
+ b : S1,
+ c : u32,
+}
+
+var<workgroup> wg : S2_atomic;
+
+fn f() {
+ atomicStore(&(wg.b.c.a), 1u);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ArrayOfStruct) {
+ auto* src = R"(
+struct S {
+ a : u32,
+ b : i32,
+ c : u32,
+}
+
+@group(0) @binding(1) var<storage, read_write> arr : array<S>;
+
+fn f() {
+ stub_atomicStore_i32(arr[4].b, 1i);
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : u32,
+ b : atomic<i32>,
+ c : u32,
+}
+
+struct S {
+ a : u32,
+ b : i32,
+ c : u32,
+}
+
+@group(0) @binding(1) var<storage, read_write> arr : array<S_atomic>;
+
+fn f() {
+ atomicStore(&(arr[4].b), 1i);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, StructOfArray) {
+ auto* src = R"(
+struct S {
+ a : array<i32>,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S;
+
+fn f() {
+ stub_atomicStore_i32(s.a[4], 1i);
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : array<atomic<i32>>,
+}
+
+struct S {
+ a : array<i32>,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S_atomic;
+
+fn f() {
+ atomicStore(&(s.a[4]), 1i);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ViaPtrLet) {
+ auto* src = R"(
+struct S {
+ i : i32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S;
+
+fn f() {
+ let p0 = &(s);
+ let p1 : ptr<storage, i32, read_write> = &((*(p0)).i);
+ stub_atomicStore_i32(*p1, 1i);
+}
+)";
+
+ auto* expect =
+ R"(
+struct S_atomic {
+ i : atomic<i32>,
+}
+
+struct S {
+ i : i32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S_atomic;
+
+fn f() {
+ let p0 = &(s);
+ let p1 : ptr<storage, atomic<i32>, read_write> = &((*(p0)).i);
+ atomicStore(&(*(p1)), 1i);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, StructIsolatedMixedUsage) {
+ auto* src = R"(
+struct S {
+ i : i32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S;
+
+fn f() {
+ stub_atomicStore_i32(s.i, 1i);
+}
+
+fn another_usage() {
+ var s : S;
+ let x : i32 = s.i;
+ s.i = 3i;
+}
+)";
+
+ auto* expect =
+ R"(
+struct S_atomic {
+ i : atomic<i32>,
+}
+
+struct S {
+ i : i32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S_atomic;
+
+fn f() {
+ atomicStore(&(s.i), 1i);
+}
+
+fn another_usage() {
+ var s : S;
+ let x : i32 = s.i;
+ s.i = 3i;
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+// This sort of mixed usage isn't handled yet. Not sure if we need to just yet.
+// If we don't, then the transform should give sensible diagnostics instead of producing invalid
+// WGSL.
+// TODO(crbug.com/tint/1595)
+TEST_F(SpirvAtomicTest, DISABLED_StructComplexMixedUsage) {
+ auto* src = R"(
+struct S {
+ i : i32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S;
+
+fn f() {
+ let x : i32 = s.i;
+ stub_atomicStore_i32(s.i, 1i);
+ s.i = 3i;
+}
+)";
+
+ auto* expect =
+ R"(
+struct S_atomic {
+ i : atomic<i32>,
+}
+
+struct S {
+ i : i32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S_atomic;
+
+fn f() {
+ let x : i32 = atomicLoad(&s.i);
+ stub_atomicStore_i32(s.i, 1i);
+ atomicStore(&(s.i), 1i);
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicLoad) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicLoad_u32(wg_u32);}
+ {let r = stub_atomicLoad_i32(wg_i32);}
+ {let r = stub_atomicLoad_u32(sg_u32);}
+ {let r = stub_atomicLoad_i32(sg_i32);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicLoad(&(wg_u32));
+ }
+ {
+ let r = atomicLoad(&(wg_i32));
+ }
+ {
+ let r = atomicLoad(&(sg_u32));
+ }
+ {
+ let r = atomicLoad(&(sg_i32));
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicExchange) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicExchange_u32(wg_u32, 123u);}
+ {let r = stub_atomicExchange_i32(wg_i32, 123i);}
+ {let r = stub_atomicExchange_u32(sg_u32, 123u);}
+ {let r = stub_atomicExchange_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicExchange(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicExchange(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicExchange(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicExchange(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicAdd) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicAdd_u32(wg_u32, 123u);}
+ {let r = stub_atomicAdd_i32(wg_i32, 123i);}
+ {let r = stub_atomicAdd_u32(sg_u32, 123u);}
+ {let r = stub_atomicAdd_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicAdd(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicAdd(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicAdd(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicAdd(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicSub) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicSub_u32(wg_u32, 123u);}
+ {let r = stub_atomicSub_i32(wg_i32, 123i);}
+ {let r = stub_atomicSub_u32(sg_u32, 123u);}
+ {let r = stub_atomicSub_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicSub(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicSub(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicSub(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicSub(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicMin) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicMin_u32(wg_u32, 123u);}
+ {let r = stub_atomicMin_i32(wg_i32, 123i);}
+ {let r = stub_atomicMin_u32(sg_u32, 123u);}
+ {let r = stub_atomicMin_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicMin(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicMin(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicMin(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicMin(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicMax) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicMax_u32(wg_u32, 123u);}
+ {let r = stub_atomicMax_i32(wg_i32, 123i);}
+ {let r = stub_atomicMax_u32(sg_u32, 123u);}
+ {let r = stub_atomicMax_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicMax(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicMax(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicMax(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicMax(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicAnd) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicAnd_u32(wg_u32, 123u);}
+ {let r = stub_atomicAnd_i32(wg_i32, 123i);}
+ {let r = stub_atomicAnd_u32(sg_u32, 123u);}
+ {let r = stub_atomicAnd_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicAnd(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicAnd(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicAnd(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicAnd(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicOr) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicOr_u32(wg_u32, 123u);}
+ {let r = stub_atomicOr_i32(wg_i32, 123i);}
+ {let r = stub_atomicOr_u32(sg_u32, 123u);}
+ {let r = stub_atomicOr_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicOr(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicOr(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicOr(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicOr(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicXor) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomicXor_u32(wg_u32, 123u);}
+ {let r = stub_atomicXor_i32(wg_i32, 123i);}
+ {let r = stub_atomicXor_u32(sg_u32, 123u);}
+ {let r = stub_atomicXor_i32(sg_i32, 123i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let r = atomicXor(&(wg_u32), 123u);
+ }
+ {
+ let r = atomicXor(&(wg_i32), 123i);
+ }
+ {
+ let r = atomicXor(&(sg_u32), 123u);
+ }
+ {
+ let r = atomicXor(&(sg_i32), 123i);
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, AtomicCompareExchangeWeak) {
+ auto* src = R"(
+var<workgroup> wg_u32 : u32;
+var<workgroup> wg_i32 : i32;
+@group(0) @binding(0) var<storage, read_write> sg_u32 : u32;
+@group(0) @binding(1) var<storage, read_write> sg_i32 : i32;
+
+fn f() {
+ {let r = stub_atomic_compare_exchange_weak_u32(wg_u32, 123u, 456u);}
+ {let r = stub_atomic_compare_exchange_weak_i32(wg_i32, 123i, 456i);}
+ {let r = stub_atomic_compare_exchange_weak_u32(sg_u32, 123u, 456u);}
+ {let r = stub_atomic_compare_exchange_weak_i32(sg_i32, 123i, 456i);}
+}
+)";
+
+ auto* expect =
+ R"(
+var<workgroup> wg_u32 : atomic<u32>;
+
+var<workgroup> wg_i32 : atomic<i32>;
+
+@group(0) @binding(0) var<storage, read_write> sg_u32 : atomic<u32>;
+
+@group(0) @binding(1) var<storage, read_write> sg_i32 : atomic<i32>;
+
+fn f() {
+ {
+ let old_value = atomicCompareExchangeWeak(&(wg_u32), 123u, 456u).old_value;
+ let r = old_value;
+ }
+ {
+ let old_value_2 = atomicCompareExchangeWeak(&(wg_i32), 123i, 456i).old_value;
+ let r = old_value_2;
+ }
+ {
+ let old_value_1 = atomicCompareExchangeWeak(&(sg_u32), 123u, 456u).old_value;
+ let r = old_value_1;
+ }
+ {
+ let old_value_3 = atomicCompareExchangeWeak(&(sg_i32), 123i, 456i).old_value;
+ let r = old_value_3;
+ }
+}
+)";
+
+ auto got = Run(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_Scaler) {
+ auto* src = R"(
+var<workgroup> wg : u32;
+
+fn f() {
+ stub_atomicAdd_u32(wg, 1u);
+
+ wg = 0u;
+ let a = wg;
+ var b : u32;
+ b = wg;
+}
+)";
+
+ auto* expect = R"(
+var<workgroup> wg : atomic<u32>;
+
+fn f() {
+ atomicAdd(&(wg), 1u);
+ atomicStore(&(wg), 0u);
+ let a = atomicLoad(&(wg));
+ var b : u32;
+ b = atomicLoad(&(wg));
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_Struct) {
+ auto* src = R"(
+struct S {
+ a : u32,
+}
+
+var<workgroup> wg : S;
+
+fn f() {
+ stub_atomicAdd_u32(wg.a, 1u);
+
+ wg.a = 0u;
+ let a = wg.a;
+ var b : u32;
+ b = wg.a;
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : atomic<u32>,
+}
+
+struct S {
+ a : u32,
+}
+
+var<workgroup> wg : S_atomic;
+
+fn f() {
+ atomicAdd(&(wg.a), 1u);
+ atomicStore(&(wg.a), 0u);
+ let a = atomicLoad(&(wg.a));
+ var b : u32;
+ b = atomicLoad(&(wg.a));
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_NestedStruct) {
+ auto* src = R"(
+struct S0 {
+ a : u32,
+}
+
+struct S1 {
+ s0 : S0
+}
+
+var<workgroup> wg : S1;
+
+fn f() {
+ stub_atomicAdd_u32(wg.s0.a, 1u);
+
+ wg.s0.a = 0u;
+ let a = wg.s0.a;
+ var b : u32;
+ b = wg.s0.a;
+}
+)";
+
+ auto* expect = R"(
+struct S0_atomic {
+ a : atomic<u32>,
+}
+
+struct S0 {
+ a : u32,
+}
+
+struct S1_atomic {
+ s0 : S0_atomic,
+}
+
+struct S1 {
+ s0 : S0,
+}
+
+var<workgroup> wg : S1_atomic;
+
+fn f() {
+ atomicAdd(&(wg.s0.a), 1u);
+ atomicStore(&(wg.s0.a), 0u);
+ let a = atomicLoad(&(wg.s0.a));
+ var b : u32;
+ b = atomicLoad(&(wg.s0.a));
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_StructMultipleAtomics) {
+ auto* src = R"(
+struct S {
+ a : u32,
+ b : u32,
+ c : u32,
+}
+
+var<workgroup> wg : S;
+
+fn f() {
+ stub_atomicAdd_u32(wg.a, 1u);
+ stub_atomicAdd_u32(wg.b, 1u);
+
+ wg.a = 0u;
+ let a = wg.a;
+ var b : u32;
+ b = wg.a;
+
+ wg.b = 0u;
+ let c = wg.b;
+ var d : u32;
+ d = wg.b;
+
+ wg.c = 0u;
+ let e = wg.c;
+ var f : u32;
+ f = wg.c;
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : atomic<u32>,
+ b : atomic<u32>,
+ c : u32,
+}
+
+struct S {
+ a : u32,
+ b : u32,
+ c : u32,
+}
+
+var<workgroup> wg : S_atomic;
+
+fn f() {
+ atomicAdd(&(wg.a), 1u);
+ atomicAdd(&(wg.b), 1u);
+ atomicStore(&(wg.a), 0u);
+ let a = atomicLoad(&(wg.a));
+ var b : u32;
+ b = atomicLoad(&(wg.a));
+ atomicStore(&(wg.b), 0u);
+ let c = atomicLoad(&(wg.b));
+ var d : u32;
+ d = atomicLoad(&(wg.b));
+ wg.c = 0u;
+ let e = wg.c;
+ var f : u32;
+ f = wg.c;
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_ArrayOfScalar) {
+ auto* src = R"(
+var<workgroup> wg : array<u32, 4>;
+
+fn f() {
+ stub_atomicAdd_u32(wg[1], 1u);
+
+ wg[1] = 0u;
+ let a = wg[1];
+ var b : u32;
+ b = wg[1];
+}
+)";
+
+ auto* expect = R"(
+var<workgroup> wg : array<atomic<u32>, 4u>;
+
+fn f() {
+ atomicAdd(&(wg[1]), 1u);
+ atomicStore(&(wg[1]), 0u);
+ let a = atomicLoad(&(wg[1]));
+ var b : u32;
+ b = atomicLoad(&(wg[1]));
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_ArrayOfStruct) {
+ auto* src = R"(
+struct S {
+ a : u32,
+}
+
+var<workgroup> wg : array<S, 4>;
+
+fn f() {
+ stub_atomicAdd_u32(wg[1].a, 1u);
+
+ wg[1].a = 0u;
+ let a = wg[1].a;
+ var b : u32;
+ b = wg[1].a;
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : atomic<u32>,
+}
+
+struct S {
+ a : u32,
+}
+
+var<workgroup> wg : array<S_atomic, 4u>;
+
+fn f() {
+ atomicAdd(&(wg[1].a), 1u);
+ atomicStore(&(wg[1].a), 0u);
+ let a = atomicLoad(&(wg[1].a));
+ var b : u32;
+ b = atomicLoad(&(wg[1].a));
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_StructOfArray) {
+ auto* src = R"(
+struct S {
+ a : array<u32>,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S;
+
+fn f() {
+ stub_atomicAdd_u32(s.a[4], 1u);
+
+ s.a[4] = 0u;
+ let a = s.a[4];
+ var b : u32;
+ b = s.a[4];
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ a : array<atomic<u32>>,
+}
+
+struct S {
+ a : array<u32>,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S_atomic;
+
+fn f() {
+ atomicAdd(&(s.a[4]), 1u);
+ atomicStore(&(s.a[4]), 0u);
+ let a = atomicLoad(&(s.a[4]));
+ var b : u32;
+ b = atomicLoad(&(s.a[4]));
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SpirvAtomicTest, ReplaceAssignsAndDecls_ViaPtrLet) {
+ auto* src = R"(
+struct S {
+ i : u32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S;
+
+fn f() {
+ let p0 = &(s);
+ let p1 : ptr<storage, u32, read_write> = &((*(p0)).i);
+ stub_atomicAdd_u32(*p1, 1u);
+
+ *p1 = 0u;
+ let a = *p1;
+ var b : u32;
+ b = *p1;
+}
+)";
+
+ auto* expect = R"(
+struct S_atomic {
+ i : atomic<u32>,
+}
+
+struct S {
+ i : u32,
+}
+
+@group(0) @binding(1) var<storage, read_write> s : S_atomic;
+
+fn f() {
+ let p0 = &(s);
+ let p1 : ptr<storage, atomic<u32>, read_write> = &((*(p0)).i);
+ atomicAdd(&(*(p1)), 1u);
+ atomicStore(&(*(p1)), 0u);
+ let a = atomicLoad(&(*(p1)));
+ var b : u32;
+ b = atomicLoad(&(*(p1)));
+}
+)";
+
+ auto got = Run(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+} // namespace
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/substitute_override.cc b/chromium/third_party/dawn/src/tint/transform/substitute_override.cc
new file mode 100644
index 00000000000..de597c28fbc
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/substitute_override.cc
@@ -0,0 +1,96 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/substitute_override.h"
+
+#include <functional>
+
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/variable.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::transform::SubstituteOverride);
+TINT_INSTANTIATE_TYPEINFO(tint::transform::SubstituteOverride::Config);
+
+namespace tint::transform {
+
+SubstituteOverride::SubstituteOverride() = default;
+
+SubstituteOverride::~SubstituteOverride() = default;
+
+bool SubstituteOverride::ShouldRun(const Program* program, const DataMap&) const {
+ for (auto* node : program->AST().GlobalVariables()) {
+ if (node->Is<ast::Override>()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SubstituteOverride::Run(CloneContext& ctx, const DataMap& config, DataMap&) const {
+ const auto* data = config.Get<Config>();
+ if (!data) {
+ ctx.dst->Diagnostics().add_error(diag::System::Transform,
+ "Missing override substitution data");
+ return;
+ }
+
+ ctx.ReplaceAll([&](const ast::Override* w) -> const ast::Const* {
+ auto* sem = ctx.src->Sem().Get(w);
+
+ auto src = ctx.Clone(w->source);
+ auto sym = ctx.Clone(w->symbol);
+ auto* ty = ctx.Clone(w->type);
+
+ // No replacement provided, just clone the override node as a const.
+ auto iter = data->map.find(sem->OverrideId());
+ if (iter == data->map.end()) {
+ if (!w->constructor) {
+ ctx.dst->Diagnostics().add_error(
+ diag::System::Transform,
+ "Initializer not provided for override, and override not overridden.");
+ return nullptr;
+ }
+ return ctx.dst->Const(src, sym, ty, ctx.Clone(w->constructor));
+ }
+
+ auto value = iter->second;
+ auto* ctor = Switch(
+ sem->Type(),
+ [&](const sem::Bool*) { return ctx.dst->Expr(!std::equal_to<double>()(value, 0.0)); },
+ [&](const sem::I32*) { return ctx.dst->Expr(i32(value)); },
+ [&](const sem::U32*) { return ctx.dst->Expr(u32(value)); },
+ [&](const sem::F32*) { return ctx.dst->Expr(f32(value)); },
+ [&](const sem::F16*) { return ctx.dst->Expr(f16(value)); });
+
+ if (!ctor) {
+ ctx.dst->Diagnostics().add_error(diag::System::Transform,
+ "Failed to create override expression");
+ return nullptr;
+ }
+
+ return ctx.dst->Const(src, sym, ty, ctor);
+ });
+
+ ctx.Clone();
+}
+
+SubstituteOverride::Config::Config() = default;
+
+SubstituteOverride::Config::Config(const Config&) = default;
+
+SubstituteOverride::Config::~Config() = default;
+
+SubstituteOverride::Config& SubstituteOverride::Config::operator=(const Config&) = default;
+
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/substitute_override.h b/chromium/third_party/dawn/src/tint/transform/substitute_override.h
new file mode 100644
index 00000000000..9ea315d92d0
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/substitute_override.h
@@ -0,0 +1,91 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
+#define SRC_TINT_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
+
+#include <string>
+#include <unordered_map>
+
+#include "tint/override_id.h"
+
+#include "src/tint/transform/transform.h"
+
+namespace tint::transform {
+
+/// A transform that replaces overrides with the constant values provided.
+///
+/// # Example
+/// ```
+/// override width: f32;
+/// @id(1) override height: i32 = 4;
+/// override depth = 1i;
+/// ```
+///
+/// When transformed with `width` -> 1, `1` -> 22, `depth` -> 42
+///
+/// ```
+/// const width: f32 = 1f;
+/// const height: i32 = 22i;
+/// const depth = 42i;
+/// ```
+///
+/// @see crbug.com/tint/1582
+class SubstituteOverride final : public Castable<SubstituteOverride, Transform> {
+ public:
+ /// Configuration options for the transform
+ struct Config final : public Castable<Config, Data> {
+ /// Constructor
+ Config();
+
+ /// Copy constructor
+ Config(const Config&);
+
+ /// Destructor
+ ~Config() override;
+
+ /// Assignment operator
+ /// @returns this Config
+ Config& operator=(const Config&);
+
+ /// The map of override identifier to the override value.
+ /// The value is always a double coming into the transform and will be
+ /// converted to the correct type through and initializer.
+ std::unordered_map<OverrideId, double> map;
+ };
+
+ /// Constructor
+ SubstituteOverride();
+
+ /// Destructor
+ ~SubstituteOverride() override;
+
+ /// @param program the program to inspect
+ /// @param data optional extra transform-specific input data
+ /// @returns true if this transform should be run for the given program
+ bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
+
+ protected:
+ /// Runs the transform using the CloneContext built for transforming a
+ /// program. Run() is responsible for calling Clone() on the CloneContext.
+ /// @param ctx the CloneContext primed with the input program and
+ /// ProgramBuilder
+ /// @param inputs optional extra transform-specific input data
+ /// @param outputs optional extra transform-specific output data
+ void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
+};
+
+} // namespace tint::transform
+
+#endif // SRC_TINT_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
diff --git a/chromium/third_party/dawn/src/tint/transform/substitute_override_test.cc b/chromium/third_party/dawn/src/tint/transform/substitute_override_test.cc
new file mode 100644
index 00000000000..f84c32cd311
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/substitute_override_test.cc
@@ -0,0 +1,242 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/substitute_override.h"
+
+#include "src/tint/transform/test_helper.h"
+
+namespace tint::transform {
+namespace {
+
+using SubstituteOverrideTest = TransformTest;
+
+TEST_F(SubstituteOverrideTest, Error_NoData) {
+ auto* src = R"(
+override width: i32;
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = "error: Missing override substitution data";
+
+ DataMap data;
+ auto got = Run<SubstituteOverride>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SubstituteOverrideTest, Error_NoOverrideValue) {
+ auto* src = R"(
+override width: i32;
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = "error: Initializer not provided for override, and override not overridden.";
+
+ SubstituteOverride::Config cfg;
+ DataMap data;
+ data.Add<SubstituteOverride::Config>(cfg);
+
+ auto got = Run<SubstituteOverride>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SubstituteOverrideTest, Module_NoOverrides) {
+ auto* src = R"(
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = R"(
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ SubstituteOverride::Config cfg;
+
+ DataMap data;
+ data.Add<SubstituteOverride::Config>(cfg);
+ auto got = Run<SubstituteOverride>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SubstituteOverrideTest, ImplicitId) {
+ auto* src = R"(
+override i_width: i32;
+override i_height = 1i;
+
+override f_width: f32;
+override f_height = 1.f;
+
+// TODO(crbug.com/tint/1473)
+// override h_width: f16;
+// override h_height = 1.h;
+
+override b_width: bool;
+override b_height = true;
+
+override o_width = 2i;
+
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = R"(
+const i_width : i32 = 42i;
+
+const i_height = 11i;
+
+const f_width : f32 = 22.299999237f;
+
+const f_height = 12.399999619f;
+
+const b_width : bool = true;
+
+const b_height = false;
+
+const o_width = 2i;
+
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ SubstituteOverride::Config cfg;
+ cfg.map.insert({OverrideId{0}, 42.0});
+ cfg.map.insert({OverrideId{1}, 11.0});
+ cfg.map.insert({OverrideId{2}, 22.3});
+ cfg.map.insert({OverrideId{3}, 12.4});
+ // cfg.map.insert({OverrideId{4}, 9.4});
+ // cfg.map.insert({OverrideId{5}, 3.4});
+ cfg.map.insert({OverrideId{4}, 1.0});
+ cfg.map.insert({OverrideId{5}, 0.0});
+
+ DataMap data;
+ data.Add<SubstituteOverride::Config>(cfg);
+ auto got = Run<SubstituteOverride>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SubstituteOverrideTest, ExplicitId) {
+ auto* src = R"(
+enable f16;
+
+@id(0) override i_width: i32;
+@id(10) override i_height = 1i;
+
+@id(1) override f_width: f32;
+@id(9) override f_height = 1.f;
+
+// TODO(crbug.com/tint/1473)
+// @id(2) override h_width: f16;
+// @id(8) override h_height = 1.h;
+
+@id(3) override b_width: bool;
+@id(7) override b_height = true;
+
+@id(5) override o_width = 2i;
+
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = R"(
+enable f16;
+
+const i_width : i32 = 42i;
+
+const i_height = 11i;
+
+const f_width : f32 = 22.299999237f;
+
+const f_height = 12.399999619f;
+
+const b_width : bool = true;
+
+const b_height = false;
+
+const o_width = 13i;
+
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ SubstituteOverride::Config cfg;
+ cfg.map.insert({OverrideId{0}, 42.0});
+ cfg.map.insert({OverrideId{10}, 11.0});
+ cfg.map.insert({OverrideId{1}, 22.3});
+ cfg.map.insert({OverrideId{9}, 12.4});
+ cfg.map.insert({OverrideId{2}, 9.4});
+ cfg.map.insert({OverrideId{8}, 3.4});
+ cfg.map.insert({OverrideId{3}, 1.0});
+ cfg.map.insert({OverrideId{7}, 0.0});
+ cfg.map.insert({OverrideId{5}, 13});
+
+ DataMap data;
+ data.Add<SubstituteOverride::Config>(cfg);
+ auto got = Run<SubstituteOverride>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SubstituteOverrideTest, Identifier_Expression) {
+ auto* src = R"(
+override i_height = ~2i;
+
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = R"(
+const i_height = 11i;
+
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ SubstituteOverride::Config cfg;
+ cfg.map.insert({OverrideId{0}, 11.0});
+
+ DataMap data;
+ data.Add<SubstituteOverride::Config>(cfg);
+ auto got = Run<SubstituteOverride>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/transform.cc b/chromium/third_party/dawn/src/tint/transform/transform.cc
index f3ab1736739..3adfff6b266 100644
--- a/chromium/third_party/dawn/src/tint/transform/transform.cc
+++ b/chromium/third_party/dawn/src/tint/transform/transform.cc
@@ -106,9 +106,9 @@ const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const sem::Type*
}
if (auto* a = ty->As<sem::Array>()) {
auto* el = CreateASTTypeFor(ctx, a->ElemType());
- ast::AttributeList attrs;
+ utils::Vector<const ast::Attribute*, 1> attrs;
if (!a->IsStrideImplicit()) {
- attrs.emplace_back(ctx.dst->create<ast::StrideAttribute>(a->Stride()));
+ attrs.Push(ctx.dst->create<ast::StrideAttribute>(a->Stride()));
}
if (a->IsRuntimeSized()) {
return ctx.dst->ty.array(el, nullptr, std::move(attrs));
diff --git a/chromium/third_party/dawn/src/tint/transform/transform_test.cc b/chromium/third_party/dawn/src/tint/transform/transform_test.cc
index 3e342c5ec1b..4ec4d1d79af 100644
--- a/chromium/third_party/dawn/src/tint/transform/transform_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/transform_test.cc
@@ -69,7 +69,7 @@ TEST_F(CreateASTTypeForTest, ArrayImplicitStride) {
});
ASSERT_TRUE(arr->Is<ast::Array>());
ASSERT_TRUE(arr->As<ast::Array>()->type->Is<ast::F32>());
- ASSERT_EQ(arr->As<ast::Array>()->attributes.size(), 0u);
+ ASSERT_EQ(arr->As<ast::Array>()->attributes.Length(), 0u);
auto* size = arr->As<ast::Array>()->count->As<ast::IntLiteralExpression>();
ASSERT_NE(size, nullptr);
@@ -82,7 +82,7 @@ TEST_F(CreateASTTypeForTest, ArrayNonImplicitStride) {
});
ASSERT_TRUE(arr->Is<ast::Array>());
ASSERT_TRUE(arr->As<ast::Array>()->type->Is<ast::F32>());
- ASSERT_EQ(arr->As<ast::Array>()->attributes.size(), 1u);
+ ASSERT_EQ(arr->As<ast::Array>()->attributes.Length(), 1u);
ASSERT_TRUE(arr->As<ast::Array>()->attributes[0]->Is<ast::StrideAttribute>());
ASSERT_EQ(arr->As<ast::Array>()->attributes[0]->As<ast::StrideAttribute>()->stride, 64u);
diff --git a/chromium/third_party/dawn/src/tint/transform/unshadow.cc b/chromium/third_party/dawn/src/tint/transform/unshadow.cc
index dcf90daa8b8..952a88b3788 100644
--- a/chromium/third_party/dawn/src/tint/transform/unshadow.cc
+++ b/chromium/third_party/dawn/src/tint/transform/unshadow.cc
@@ -44,28 +44,45 @@ struct Unshadow::State {
// Maps a variable to its new name.
std::unordered_map<const sem::Variable*, Symbol> renamed_to;
- auto rename = [&](const sem::Variable* var) -> const ast::Variable* {
- auto* decl = var->Declaration();
+ auto rename = [&](const sem::Variable* v) -> const ast::Variable* {
+ auto* decl = v->Declaration();
auto name = ctx.src->Symbols().NameFor(decl->symbol);
auto symbol = ctx.dst->Symbols().New(name);
- renamed_to.emplace(var, symbol);
+ renamed_to.emplace(v, symbol);
auto source = ctx.Clone(decl->source);
auto* type = ctx.Clone(decl->type);
auto* constructor = ctx.Clone(decl->constructor);
auto attributes = ctx.Clone(decl->attributes);
- return ctx.dst->create<ast::Variable>(source, symbol, decl->declared_storage_class,
- decl->declared_access, type, decl->is_const,
- decl->is_overridable, constructor, attributes);
+ return Switch(
+ decl, //
+ [&](const ast::Var* var) {
+ return ctx.dst->Var(source, symbol, type, var->declared_storage_class,
+ var->declared_access, constructor, attributes);
+ },
+ [&](const ast::Let*) {
+ return ctx.dst->Let(source, symbol, type, constructor, attributes);
+ },
+ [&](const ast::Const*) {
+ return ctx.dst->Const(source, symbol, type, constructor, attributes);
+ },
+ [&](const ast::Parameter*) {
+ return ctx.dst->Param(source, symbol, type, attributes);
+ },
+ [&](Default) {
+ TINT_ICE(Transform, ctx.dst->Diagnostics())
+ << "unexpected variable type: " << decl->TypeInfo().name;
+ return nullptr;
+ });
};
- ctx.ReplaceAll([&](const ast::Variable* var) -> const ast::Variable* {
- if (auto* local = sem.Get<sem::LocalVariable>(var)) {
+ ctx.ReplaceAll([&](const ast::Variable* v) -> const ast::Variable* {
+ if (auto* local = sem.Get<sem::LocalVariable>(v)) {
if (local->Shadows()) {
return rename(local);
}
}
- if (auto* param = sem.Get<sem::Parameter>(var)) {
+ if (auto* param = sem.Get<sem::Parameter>(v)) {
if (param->Shadows()) {
return rename(param);
}
diff --git a/chromium/third_party/dawn/src/tint/transform/unshadow.h b/chromium/third_party/dawn/src/tint/transform/unshadow.h
index ce5e9758aa2..5ffe8399b98 100644
--- a/chromium/third_party/dawn/src/tint/transform/unshadow.h
+++ b/chromium/third_party/dawn/src/tint/transform/unshadow.h
@@ -21,7 +21,7 @@ namespace tint::transform {
/// Unshadow is a Transform that renames any variables that shadow another
/// variable.
-class Unshadow : public Castable<Unshadow, Transform> {
+class Unshadow final : public Castable<Unshadow, Transform> {
public:
/// Constructor
Unshadow();
diff --git a/chromium/third_party/dawn/src/tint/transform/unshadow_test.cc b/chromium/third_party/dawn/src/tint/transform/unshadow_test.cc
index 30e1db55e5b..f5a8102405b 100644
--- a/chromium/third_party/dawn/src/tint/transform/unshadow_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/unshadow_test.cc
@@ -34,14 +34,16 @@ TEST_F(UnshadowTest, Noop) {
auto* src = R"(
var<private> a : i32;
-let b : i32 = 1;
+const b : i32 = 1;
fn F(c : i32) {
var d : i32;
let e : i32 = 1;
+ const f : i32 = 2;
{
- var f : i32;
- let g : i32 = 1;
+ var g : i32;
+ let h : i32 = 1;
+ const i : i32 = 2;
}
}
)";
@@ -64,6 +66,10 @@ fn X() {
fn Y() {
let a = true;
}
+
+fn Z() {
+ const a = true;
+}
)";
auto* expect = R"(
@@ -76,6 +82,10 @@ fn X() {
fn Y() {
let a_2 = true;
}
+
+fn Z() {
+ const a_3 = true;
+}
)";
auto got = Run<Unshadow>(src);
@@ -93,6 +103,10 @@ fn Y() {
let a = true;
}
+fn Z() {
+ const a = true;
+}
+
type a = i32;
)";
@@ -105,6 +119,10 @@ fn Y() {
let a_2 = true;
}
+fn Z() {
+ const a_3 = true;
+}
+
type a = i32;
)";
@@ -126,6 +144,10 @@ fn X() {
fn Y() {
let a = false;
}
+
+fn Z() {
+ const a = false;
+}
)";
auto* expect = R"(
@@ -140,6 +162,10 @@ fn X() {
fn Y() {
let a_2 = false;
}
+
+fn Z() {
+ const a_3 = false;
+}
)";
auto got = Run<Unshadow>(src);
@@ -157,6 +183,10 @@ fn Y() {
let a = false;
}
+fn Z() {
+ const a = false;
+}
+
struct a {
m : i32,
};
@@ -172,6 +202,10 @@ fn Y() {
let a_2 = false;
}
+fn Z() {
+ const a_3 = false;
+}
+
struct a {
m : i32,
}
@@ -187,11 +221,19 @@ TEST_F(UnshadowTest, LocalShadowsFunction) {
fn a() {
var a = true;
var b = false;
+ var c = true;
}
fn b() {
let a = true;
let b = false;
+ let c = true;
+}
+
+fn c() {
+ const a = true;
+ const b = false;
+ const c = true;
}
)";
@@ -199,11 +241,19 @@ fn b() {
fn a() {
var a_1 = true;
var b_1 = false;
+ var c_1 = true;
}
fn b() {
let a_2 = true;
let b_2 = false;
+ let c_2 = true;
+}
+
+fn c() {
+ const a_3 = true;
+ const b_3 = false;
+ const c_3 = true;
}
)";
@@ -217,24 +267,39 @@ TEST_F(UnshadowTest, LocalShadowsFunction_OutOfOrder) {
fn b() {
let a = true;
let b = false;
+ let c = true;
}
fn a() {
var a = true;
var b = false;
+ var c = true;
}
+fn c() {
+ const a = true;
+ const b = false;
+ const c = true;
+}
)";
auto* expect = R"(
fn b() {
let a_1 = true;
let b_1 = false;
+ let c_1 = true;
}
fn a() {
var a_2 = true;
var b_2 = false;
+ var c_2 = true;
+}
+
+fn c() {
+ const a_3 = true;
+ const b_3 = false;
+ const c_3 = true;
}
)";
@@ -254,6 +319,10 @@ fn X() {
fn Y() {
let a = (a == 321);
}
+
+fn Z() {
+ const a = 321;
+}
)";
auto* expect = R"(
@@ -266,6 +335,10 @@ fn X() {
fn Y() {
let a_2 = (a == 321);
}
+
+fn Z() {
+ const a_3 = 321;
+}
)";
auto got = Run<Unshadow>(src);
@@ -283,6 +356,10 @@ fn Y() {
let a = (a == 321);
}
+fn Z() {
+ const a = 321;
+}
+
var<private> a : i32;
)";
@@ -295,6 +372,10 @@ fn Y() {
let a_2 = (a == 321);
}
+fn Z() {
+ const a_3 = 321;
+}
+
var<private> a : i32;
)";
@@ -314,10 +395,14 @@ fn X() {
fn Y() {
let a = (a == 321);
}
+
+fn Z() {
+ const a = 321;
+}
)";
auto* expect = R"(
-let a : i32 = 1;
+const a : i32 = 1;
fn X() {
var a_1 = (a == 123);
@@ -326,6 +411,10 @@ fn X() {
fn Y() {
let a_2 = (a == 321);
}
+
+fn Z() {
+ const a_3 = 321;
+}
)";
auto got = Run<Unshadow>(src);
@@ -343,6 +432,10 @@ fn Y() {
let a = (a == 321);
}
+fn Z() {
+ const a = 321;
+}
+
let a : i32 = 1;
)";
@@ -355,7 +448,87 @@ fn Y() {
let a_2 = (a == 321);
}
-let a : i32 = 1;
+fn Z() {
+ const a_3 = 321;
+}
+
+const a : i32 = 1;
+)";
+
+ auto got = Run<Unshadow>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnshadowTest, LocalShadowsGlobalConst) {
+ auto* src = R"(
+const a : i32 = 1;
+
+fn X() {
+ var a = (a == 123);
+}
+
+fn Y() {
+ let a = (a == 321);
+}
+
+fn Z() {
+ const a = 321;
+}
+)";
+
+ auto* expect = R"(
+const a : i32 = 1;
+
+fn X() {
+ var a_1 = (a == 123);
+}
+
+fn Y() {
+ let a_2 = (a == 321);
+}
+
+fn Z() {
+ const a_3 = 321;
+}
+)";
+
+ auto got = Run<Unshadow>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnshadowTest, LocalShadowsGlobalConst_OutOfOrder) {
+ auto* src = R"(
+fn X() {
+ var a = (a == 123);
+}
+
+fn Y() {
+ let a = (a == 321);
+}
+
+fn Z() {
+ const a = a;
+}
+
+const a : i32 = 1;
+)";
+
+ auto* expect = R"(
+fn X() {
+ var a_1 = (a == 123);
+}
+
+fn Y() {
+ let a_2 = (a == 321);
+}
+
+fn Z() {
+ const a_3 = a;
+}
+
+const a : i32 = 1;
)";
auto got = Run<Unshadow>(src);
@@ -373,6 +546,9 @@ fn X() {
{
let a = (a == 321);
}
+ {
+ const a = 321;
+ }
}
)";
@@ -385,6 +561,9 @@ fn X() {
{
let a_2 = (a == 321);
}
+ {
+ const a_3 = 321;
+ }
}
)";
@@ -403,6 +582,9 @@ fn X() {
{
let a = (a == 321);
}
+ {
+ const a = 321;
+ }
}
)";
@@ -415,6 +597,45 @@ fn X() {
{
let a_2 = (a == 321);
}
+ {
+ const a_3 = 321;
+ }
+}
+)";
+
+ auto got = Run<Unshadow>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnshadowTest, LocalShadowsLocalConst) {
+ auto* src = R"(
+fn X() {
+ const a = 1;
+ {
+ var a = (a == 123);
+ }
+ {
+ let a = (a == 321);
+ }
+ {
+ const a = a;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn X() {
+ const a = 1;
+ {
+ var a_1 = (a == 123);
+ }
+ {
+ let a_2 = (a == 321);
+ }
+ {
+ const a_3 = a;
+ }
}
)";
@@ -432,6 +653,9 @@ fn F(a : i32) {
{
let a = (a == 321);
}
+ {
+ const a = 321;
+ }
}
)";
@@ -443,6 +667,9 @@ fn F(a : i32) {
{
let a_2 = (a == 321);
}
+ {
+ const a_3 = 321;
+ }
}
)";
@@ -460,6 +687,9 @@ fn a(a : i32) {
{
let a = (a == 321);
}
+ {
+ const a = 321;
+ }
}
)";
@@ -471,6 +701,9 @@ fn a(a_1 : i32) {
{
let a_3 = (a_1 == 321);
}
+ {
+ const a_4 = 321;
+ }
}
)";
@@ -508,7 +741,7 @@ fn F(a : bool) {
)";
auto* expect = R"(
-let a : i32 = 1;
+const a : i32 = 1;
fn F(a_1 : bool) {
}
@@ -531,7 +764,47 @@ let a : i32 = 1;
fn F(a_1 : bool) {
}
-let a : i32 = 1;
+const a : i32 = 1;
+)";
+
+ auto got = Run<Unshadow>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnshadowTest, ParamShadowsGlobalConst) {
+ auto* src = R"(
+const a : i32 = 1;
+
+fn F(a : bool) {
+}
+)";
+
+ auto* expect = R"(
+const a : i32 = 1;
+
+fn F(a_1 : bool) {
+}
+)";
+
+ auto got = Run<Unshadow>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnshadowTest, ParamShadowsGlobalConst_OutOfOrder) {
+ auto* src = R"(
+fn F(a : bool) {
+}
+
+const a : i32 = 1;
+)";
+
+ auto* expect = R"(
+fn F(a_1 : bool) {
+}
+
+const a : i32 = 1;
)";
auto got = Run<Unshadow>(src);
diff --git a/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.cc b/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.cc
index e1ba74c2e9f..8c62f0484c0 100644
--- a/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.cc
+++ b/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.cc
@@ -54,8 +54,8 @@ class State {
Symbol ModuleDiscardVarName() {
if (!module_discard_var_name.IsValid()) {
module_discard_var_name = b.Symbols().New("tint_discard");
- ctx.dst->Global(module_discard_var_name, b.ty.bool_(), b.Expr(false),
- ast::StorageClass::kPrivate);
+ ctx.dst->GlobalVar(module_discard_var_name, b.ty.bool_(), b.Expr(false),
+ ast::StorageClass::kPrivate);
}
return module_discard_var_name;
}
@@ -67,7 +67,8 @@ class State {
Symbol ModuleDiscardFuncName() {
if (!module_discard_func_name.IsValid()) {
module_discard_func_name = b.Symbols().New("tint_discard_func");
- b.Func(module_discard_func_name, {}, b.ty.void_(), {b.Discard()});
+ b.Func(module_discard_func_name, tint::utils::Empty, b.ty.void_(),
+ tint::utils::Vector{b.Discard()});
}
return module_discard_func_name;
}
@@ -108,14 +109,14 @@ class State {
// }
//
const ast::IfStatement* IfDiscardReturn(const ast::Statement* stmt) {
- ast::StatementList stmts;
+ tint::utils::Vector<const ast::Statement*, 2> stmts;
// For entry point functions, also emit the discard statement
if (IsInEntryPointFunc(stmt)) {
- stmts.emplace_back(CallDiscardFunc());
+ stmts.Push(CallDiscardFunc());
}
- stmts.emplace_back(Return(stmt));
+ stmts.Push(Return(stmt));
auto var_name = ModuleDiscardVarName();
return b.If(var_name, b.Block(stmts));
@@ -262,6 +263,15 @@ class State {
}
return nullptr;
},
+ [&](const ast::WhileStatement* s) -> const ast::Statement* {
+ if (MayDiscard(sem.Get(s->condition))) {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "Unexpected WhileStatement condition that may discard. "
+ "Make sure transform::PromoteSideEffectsToDecl was run "
+ "first.";
+ }
+ return nullptr;
+ },
[&](const ast::IfStatement* s) -> const ast::Statement* {
auto* sem_expr = sem.Get(s->condition);
if (!MayDiscard(sem_expr)) {
diff --git a/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.h b/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.h
index 3b1d838ceb1..105a9d8d393 100644
--- a/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.h
+++ b/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions.h
@@ -36,7 +36,7 @@ namespace tint::transform {
///
/// @note Depends on the following transforms to have been run first:
/// * PromoteSideEffectsToDecl
-class UnwindDiscardFunctions : public Castable<UnwindDiscardFunctions, Transform> {
+class UnwindDiscardFunctions final : public Castable<UnwindDiscardFunctions, Transform> {
public:
/// Constructor
UnwindDiscardFunctions();
diff --git a/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions_test.cc b/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions_test.cc
index 481df9dfdbd..7d1fa272641 100644
--- a/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/unwind_discard_functions_test.cc
@@ -800,6 +800,67 @@ fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
EXPECT_EQ(expect, str(got));
}
+TEST_F(UnwindDiscardFunctionsTest, While_Cond) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@fragment
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ while (f() == 42) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@fragment
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ loop {
+ let tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ if (!((tint_symbol == 42))) {
+ break;
+ }
+ {
+ let marker2 = 0;
+ break;
+ }
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(UnwindDiscardFunctionsTest, Switch) {
auto* src = R"(
fn f() -> i32 {
diff --git a/chromium/third_party/dawn/src/tint/transform/utils/get_insertion_point_test.cc b/chromium/third_party/dawn/src/tint/transform/utils/get_insertion_point_test.cc
index 071cfea40a0..72fedd09d22 100644
--- a/chromium/third_party/dawn/src/tint/transform/utils/get_insertion_point_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/utils/get_insertion_point_test.cc
@@ -35,7 +35,7 @@ TEST_F(GetInsertionPointTest, Block) {
auto* expr = b.Expr(1_i);
auto* var = b.Decl(b.Var("a", nullptr, expr));
auto* block = b.Block(var);
- b.Func("f", {}, b.ty.void_(), {block});
+ b.Func("f", tint::utils::Empty, b.ty.void_(), tint::utils::Vector{block});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -56,9 +56,9 @@ TEST_F(GetInsertionPointTest, ForLoopInit) {
ProgramBuilder b;
auto* expr = b.Expr(1_i);
auto* var = b.Decl(b.Var("a", nullptr, expr));
- auto* fl = b.For(var, b.Expr(true), {}, b.Block());
+ auto* fl = b.For(var, b.Expr(true), nullptr, b.Block());
auto* func_block = b.Block(fl);
- b.Func("f", {}, b.ty.void_(), {func_block});
+ b.Func("f", tint::utils::Empty, b.ty.void_(), tint::utils::Vector{func_block});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -79,7 +79,7 @@ TEST_F(GetInsertionPointTest, ForLoopCont_Invalid) {
auto* expr = b.Expr(1_i);
auto* var = b.Decl(b.Var("a", nullptr, expr));
auto* s = b.For({}, b.Expr(true), var, b.Block());
- b.Func("f", {}, b.ty.void_(), {s});
+ b.Func("f", tint::utils::Empty, b.ty.void_(), tint::utils::Vector{s});
Program original(std::move(b));
ProgramBuilder cloned_b;
diff --git a/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before.cc b/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before.cc
index 450a2e8a922..913326792a7 100644
--- a/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before.cc
+++ b/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before.cc
@@ -16,12 +16,13 @@
#include <unordered_map>
-#include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/program_builder.h"
#include "src/tint/sem/block_statement.h"
#include "src/tint/sem/for_loop_statement.h"
#include "src/tint/sem/if_statement.h"
#include "src/tint/sem/reference.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/sem/while_statement.h"
#include "src/tint/utils/reverse.h"
namespace tint::transform {
@@ -35,18 +36,21 @@ class HoistToDeclBefore::State {
/// loop, so that declaration statements can be inserted before the
/// condition expression or continuing statement.
struct LoopInfo {
- ast::StatementList cond_decls;
- ast::StatementList cont_decls;
+ utils::Vector<const ast::Statement*, 8> cond_decls;
+ utils::Vector<const ast::Statement*, 8> cont_decls;
};
/// Info for each else-if that needs decomposing
struct ElseIfInfo {
/// Decls to insert before condition
- ast::StatementList cond_decls;
+ utils::Vector<const ast::Statement*, 8> cond_decls;
};
/// For-loops that need to be decomposed to loops.
- std::unordered_map<const sem::ForLoopStatement*, LoopInfo> loops;
+ std::unordered_map<const sem::ForLoopStatement*, LoopInfo> for_loops;
+
+ /// Whiles that need to be decomposed to loops.
+ std::unordered_map<const sem::WhileStatement*, LoopInfo> while_loops;
/// 'else if' statements that need to be decomposed to 'else {if}'
std::unordered_map<const ast::IfStatement*, ElseIfInfo> else_ifs;
@@ -55,7 +59,7 @@ class HoistToDeclBefore::State {
// registered declaration statements before the condition or continuing
// statement.
void ForLoopsToLoops() {
- if (loops.empty()) {
+ if (for_loops.empty()) {
return;
}
@@ -64,7 +68,7 @@ class HoistToDeclBefore::State {
auto& sem = ctx.src->Sem();
if (auto* fl = sem.Get(stmt)) {
- if (auto it = loops.find(fl); it != loops.end()) {
+ if (auto it = for_loops.find(fl); it != for_loops.end()) {
auto& info = it->second;
auto* for_loop = fl->Declaration();
// For-loop needs to be decomposed to a loop.
@@ -81,10 +85,10 @@ class HoistToDeclBefore::State {
// { break; }
auto* break_body = b.Block(b.create<ast::BreakStatement>());
// if (!condition) { break; }
- body_stmts.emplace_back(b.If(not_cond, break_body));
+ body_stmts.Push(b.If(not_cond, break_body));
}
// Next emit the for-loop body
- body_stmts.emplace_back(ctx.Clone(for_loop->body));
+ body_stmts.Push(ctx.Clone(for_loop->body));
// Finally create the continuing block if there was one.
const ast::BlockStatement* continuing = nullptr;
@@ -92,7 +96,7 @@ class HoistToDeclBefore::State {
// Continuing block starts with any let declarations used by
// the continuing.
auto cont_stmts = info.cont_decls;
- cont_stmts.emplace_back(ctx.Clone(cont));
+ cont_stmts.Push(ctx.Clone(cont));
continuing = b.Block(cont_stmts);
}
@@ -108,6 +112,51 @@ class HoistToDeclBefore::State {
});
}
+ // Converts any while-loops marked for conversion to loops, inserting
+ // registered declaration statements before the condition.
+ void WhilesToLoops() {
+ if (while_loops.empty()) {
+ return;
+ }
+
+ // At least one while needs to be transformed into a loop.
+ ctx.ReplaceAll([&](const ast::WhileStatement* stmt) -> const ast::Statement* {
+ auto& sem = ctx.src->Sem();
+
+ if (auto* w = sem.Get(stmt)) {
+ if (auto it = while_loops.find(w); it != while_loops.end()) {
+ auto& info = it->second;
+ auto* while_loop = w->Declaration();
+ // While needs to be decomposed to a loop.
+ // Build the loop body's statements.
+ // Start with any let declarations for the conditional
+ // expression.
+ auto body_stmts = info.cond_decls;
+ // Emit the condition as:
+ // if (!cond) { break; }
+ auto* cond = while_loop->condition;
+ // !condition
+ auto* not_cond =
+ b.create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, ctx.Clone(cond));
+ // { break; }
+ auto* break_body = b.Block(b.create<ast::BreakStatement>());
+ // if (!condition) { break; }
+ body_stmts.Push(b.If(not_cond, break_body));
+
+ // Next emit the body
+ body_stmts.Push(ctx.Clone(while_loop->body));
+
+ const ast::BlockStatement* continuing = nullptr;
+
+ auto* body = b.Block(body_stmts);
+ auto* loop = b.Loop(body, continuing);
+ return loop;
+ }
+ }
+ return nullptr;
+ });
+ }
+
void ElseIfsToElseWithNestedIfs() {
// Decompose 'else-if' statements into 'else { if }' blocks.
ctx.ReplaceAll([&](const ast::IfStatement* else_if) -> const ast::Statement* {
@@ -124,7 +173,7 @@ class HoistToDeclBefore::State {
auto* cond = ctx.Clone(else_if->condition);
auto* body = ctx.Clone(else_if->body);
auto* new_if = b.If(cond, body, b.Else(ctx.Clone(else_if->else_statement)));
- body_stmts.emplace_back(new_if);
+ body_stmts.Push(new_if);
// Replace the 'else-if' with the new 'else' block.
return b.Block(body_stmts);
@@ -140,18 +189,18 @@ class HoistToDeclBefore::State {
/// before `before_expr`.
/// @param before_expr expression to insert `expr` before
/// @param expr expression to hoist
- /// @param as_const hoist to `let` if true, otherwise to `var`
+ /// @param as_let hoist to `let` if true, otherwise to `var`
/// @param decl_name optional name to use for the variable/constant name
/// @return true on success
bool Add(const sem::Expression* before_expr,
const ast::Expression* expr,
- bool as_const,
+ bool as_let,
const char* decl_name) {
auto name = b.Symbols().New(decl_name);
// Construct the let/var that holds the hoisted expr
- auto* v = as_const ? b.Let(name, nullptr, ctx.Clone(expr))
- : b.Var(name, nullptr, ctx.Clone(expr));
+ auto* v = as_let ? static_cast<const ast::Variable*>(b.Let(name, nullptr, ctx.Clone(expr)))
+ : static_cast<const ast::Variable*>(b.Var(name, nullptr, ctx.Clone(expr)));
auto* decl = b.Decl(v);
if (!InsertBefore(before_expr->Stmt(), decl)) {
@@ -182,7 +231,7 @@ class HoistToDeclBefore::State {
// Index the map to convert this else if, even if `stmt` is nullptr.
auto& decls = else_if_info.cond_decls;
if (stmt) {
- decls.emplace_back(stmt);
+ decls.Push(stmt);
}
return true;
}
@@ -192,9 +241,21 @@ class HoistToDeclBefore::State {
// For-loop needs to be decomposed to a loop.
// Index the map to convert this for-loop, even if `stmt` is nullptr.
- auto& decls = loops[fl].cond_decls;
+ auto& decls = for_loops[fl].cond_decls;
+ if (stmt) {
+ decls.Push(stmt);
+ }
+ return true;
+ }
+
+ if (auto* w = before_stmt->As<sem::WhileStatement>()) {
+ // Insertion point is a while condition.
+ // While needs to be decomposed to a loop.
+
+ // Index the map to convert this while, even if `stmt` is nullptr.
+ auto& decls = while_loops[w].cond_decls;
if (stmt) {
- decls.emplace_back(stmt);
+ decls.Push(stmt);
}
return true;
}
@@ -227,9 +288,9 @@ class HoistToDeclBefore::State {
// For-loop needs to be decomposed to a loop.
// Index the map to convert this for-loop, even if `stmt` is nullptr.
- auto& decls = loops[fl].cont_decls;
+ auto& decls = for_loops[fl].cont_decls;
if (stmt) {
- decls.emplace_back(stmt);
+ decls.Push(stmt);
}
return true;
}
@@ -257,6 +318,7 @@ class HoistToDeclBefore::State {
/// @return true on success
bool Apply() {
ForLoopsToLoops();
+ WhilesToLoops();
ElseIfsToElseWithNestedIfs();
return true;
}
@@ -268,9 +330,9 @@ HoistToDeclBefore::~HoistToDeclBefore() {}
bool HoistToDeclBefore::Add(const sem::Expression* before_expr,
const ast::Expression* expr,
- bool as_const,
+ bool as_let,
const char* decl_name) {
- return state_->Add(before_expr, expr, as_const, decl_name);
+ return state_->Add(before_expr, expr, as_let, decl_name);
}
bool HoistToDeclBefore::InsertBefore(const sem::Statement* before_stmt,
diff --git a/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before_test.cc b/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before_test.cc
index 1e4cb8ef369..6d4533dbee7 100644
--- a/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/utils/hoist_to_decl_before_test.cc
@@ -17,6 +17,7 @@
#include "gtest/gtest-spi.h"
#include "src/tint/program_builder.h"
#include "src/tint/sem/if_statement.h"
+#include "src/tint/sem/index_accessor_expression.h"
#include "src/tint/sem/statement.h"
#include "src/tint/transform/test_helper.h"
#include "src/tint/transform/utils/hoist_to_decl_before.h"
@@ -35,7 +36,7 @@ TEST_F(HoistToDeclBeforeTest, VarInit) {
ProgramBuilder b;
auto* expr = b.Expr(1_i);
auto* var = b.Decl(b.Var("a", nullptr, expr));
- b.Func("f", {}, b.ty.void_(), {var});
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -66,8 +67,8 @@ TEST_F(HoistToDeclBeforeTest, ForLoopInit) {
// }
ProgramBuilder b;
auto* expr = b.Expr(1_i);
- auto* s = b.For(b.Decl(b.Var("a", nullptr, expr)), b.Expr(true), {}, b.Block());
- b.Func("f", {}, b.ty.void_(), {s});
+ auto* s = b.For(b.Decl(b.Var("a", nullptr, expr)), b.Expr(true), nullptr, b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -101,8 +102,8 @@ TEST_F(HoistToDeclBeforeTest, ForLoopCond) {
ProgramBuilder b;
auto* var = b.Decl(b.Var("a", b.ty.bool_()));
auto* expr = b.Expr("a");
- auto* s = b.For({}, expr, {}, b.Block());
- b.Func("f", {}, b.ty.void_(), {var, s});
+ auto* s = b.For(nullptr, expr, nullptr, b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -140,8 +141,8 @@ TEST_F(HoistToDeclBeforeTest, ForLoopCont) {
// }
ProgramBuilder b;
auto* expr = b.Expr(1_i);
- auto* s = b.For({}, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
- b.Func("f", {}, b.ty.void_(), {s});
+ auto* s = b.For(nullptr, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -175,6 +176,47 @@ fn f() {
EXPECT_EQ(expect, str(cloned));
}
+TEST_F(HoistToDeclBeforeTest, WhileCond) {
+ // fn f() {
+ // var a : bool;
+ // while(a) {
+ // }
+ // }
+ ProgramBuilder b;
+ auto* var = b.Decl(b.Var("a", b.ty.bool_()));
+ auto* expr = b.Expr("a");
+ auto* s = b.While(expr, b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
+
+ Program original(std::move(b));
+ ProgramBuilder cloned_b;
+ CloneContext ctx(&cloned_b, &original);
+
+ HoistToDeclBefore hoistToDeclBefore(ctx);
+ auto* sem_expr = ctx.src->Sem().Get(expr);
+ hoistToDeclBefore.Add(sem_expr, expr, true);
+ hoistToDeclBefore.Apply();
+
+ ctx.Clone();
+ Program cloned(std::move(cloned_b));
+
+ auto* expect = R"(
+fn f() {
+ var a : bool;
+ loop {
+ let tint_symbol = a;
+ if (!(tint_symbol)) {
+ break;
+ }
+ {
+ }
+ }
+}
+)";
+
+ EXPECT_EQ(expect, str(cloned));
+}
+
TEST_F(HoistToDeclBeforeTest, ElseIf) {
// fn f() {
// var a : bool;
@@ -189,7 +231,7 @@ TEST_F(HoistToDeclBeforeTest, ElseIf) {
auto* s = b.If(b.Expr(true), b.Block(), //
b.Else(b.If(expr, b.Block(), //
b.Else(b.Block()))));
- b.Func("f", {}, b.ty.void_(), {var, s});
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -228,7 +270,7 @@ TEST_F(HoistToDeclBeforeTest, Array1D) {
auto* var1 = b.Decl(b.Var("a", b.ty.array<i32, 10>()));
auto* expr = b.IndexAccessor("a", 0_i);
auto* var2 = b.Decl(b.Var("b", nullptr, expr));
- b.Func("f", {}, b.ty.void_(), {var1, var2});
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var1, var2});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -263,7 +305,7 @@ TEST_F(HoistToDeclBeforeTest, Array2D) {
auto* var1 = b.Decl(b.Var("a", b.ty.array(b.ty.array<i32, 10>(), 10_i)));
auto* expr = b.IndexAccessor(b.IndexAccessor("a", 0_i), 0_i);
auto* var2 = b.Decl(b.Var("b", nullptr, expr));
- b.Func("f", {}, b.ty.void_(), {var1, var2});
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var1, var2});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -297,8 +339,8 @@ TEST_F(HoistToDeclBeforeTest, Prepare_ForLoopCond) {
ProgramBuilder b;
auto* var = b.Decl(b.Var("a", b.ty.bool_()));
auto* expr = b.Expr("a");
- auto* s = b.For({}, expr, {}, b.Block());
- b.Func("f", {}, b.ty.void_(), {var, s});
+ auto* s = b.For(nullptr, expr, nullptr, b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -335,8 +377,8 @@ TEST_F(HoistToDeclBeforeTest, Prepare_ForLoopCont) {
// }
ProgramBuilder b;
auto* expr = b.Expr(1_i);
- auto* s = b.For({}, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
- b.Func("f", {}, b.ty.void_(), {s});
+ auto* s = b.For(nullptr, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -383,7 +425,7 @@ TEST_F(HoistToDeclBeforeTest, Prepare_ElseIf) {
auto* s = b.If(b.Expr(true), b.Block(), //
b.Else(b.If(expr, b.Block(), //
b.Else(b.Block()))));
- b.Func("f", {}, b.ty.void_(), {var, s});
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -419,9 +461,9 @@ TEST_F(HoistToDeclBeforeTest, InsertBefore_Block) {
// var a = 1i;
// }
ProgramBuilder b;
- b.Func("foo", {}, b.ty.void_(), {});
+ b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1_i)));
- b.Func("f", {}, b.ty.void_(), {var});
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -457,10 +499,10 @@ TEST_F(HoistToDeclBeforeTest, InsertBefore_ForLoopInit) {
// }
// }
ProgramBuilder b;
- b.Func("foo", {}, b.ty.void_(), {});
+ b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1_i)));
- auto* s = b.For(var, b.Expr(true), {}, b.Block());
- b.Func("f", {}, b.ty.void_(), {s});
+ auto* s = b.For(var, b.Expr(true), nullptr, b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -498,11 +540,11 @@ TEST_F(HoistToDeclBeforeTest, InsertBefore_ForLoopCont) {
// }
// }
ProgramBuilder b;
- b.Func("foo", {}, b.ty.void_(), {});
+ b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1_i)));
auto* cont = b.CompoundAssign("a", b.Expr(1_i), ast::BinaryOp::kAdd);
- auto* s = b.For({}, b.Expr(true), cont, b.Block());
- b.Func("f", {}, b.ty.void_(), {var, s});
+ auto* s = b.For(nullptr, b.Expr(true), cont, b.Block());
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
Program original(std::move(b));
ProgramBuilder cloned_b;
@@ -552,12 +594,12 @@ TEST_F(HoistToDeclBeforeTest, InsertBefore_ElseIf) {
// }
// }
ProgramBuilder b;
- b.Func("foo", {}, b.ty.void_(), {});
+ b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
auto* var = b.Decl(b.Var("a", b.ty.bool_()));
auto* elseif = b.If(b.Expr("a"), b.Block(), b.Else(b.Block()));
auto* s = b.If(b.Expr(true), b.Block(), //
b.Else(elseif));
- b.Func("f", {}, b.ty.void_(), {var, s});
+ b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
Program original(std::move(b));
ProgramBuilder cloned_b;
diff --git a/chromium/third_party/dawn/src/tint/transform/var_for_dynamic_index_test.cc b/chromium/third_party/dawn/src/tint/transform/var_for_dynamic_index_test.cc
index ca767c9d057..05c19b3eb9b 100644
--- a/chromium/third_party/dawn/src/tint/transform/var_for_dynamic_index_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/var_for_dynamic_index_test.cc
@@ -484,7 +484,8 @@ TEST_F(VarForDynamicIndexTest, ArrayIndexConstantLet) {
fn f() {
let p = array<i32, 4>(1, 2, 3, 4);
let c = 1;
- let x = p[c];
+ var var_for_index = p;
+ let x = var_for_index[c];
}
)";
@@ -501,7 +502,8 @@ TEST_F(VarForDynamicIndexTest, MatrixIndexConstantLet) {
fn f() {
let p = mat2x2(1.0, 2.0, 3.0, 4.0);
let c = 1;
- let x = p[c];
+ var var_for_index = p;
+ let x = var_for_index[c];
}
)";
diff --git a/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.cc b/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.cc
index 9cd9757bbbe..113db5f7b1f 100644
--- a/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.cc
+++ b/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.cc
@@ -18,6 +18,7 @@
#include <utility>
#include "src/tint/program_builder.h"
+#include "src/tint/sem/abstract_numeric.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/expression.h"
#include "src/tint/sem/type_constructor.h"
@@ -36,7 +37,7 @@ bool VectorizeScalarMatrixConstructors::ShouldRun(const Program* program, const
if (auto* call = program->Sem().Get<sem::Call>(node)) {
if (call->Target()->Is<sem::TypeConstructor>() && call->Type()->Is<sem::Matrix>()) {
auto& args = call->Arguments();
- if (args.size() > 0 && args[0]->Type()->is_scalar()) {
+ if (!args.IsEmpty() && args[0]->Type()->UnwrapRef()->is_scalar()) {
return true;
}
}
@@ -54,38 +55,45 @@ void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx, const DataMap&, D
if (!ty_ctor) {
return nullptr;
}
- // Check if this is a matrix constructor with scalar arguments.
auto* mat_type = call->Type()->As<sem::Matrix>();
if (!mat_type) {
return nullptr;
}
auto& args = call->Arguments();
- if (args.size() == 0) {
+ if (args.IsEmpty()) {
return nullptr;
}
- if (!args[0]->Type()->is_scalar()) {
+
+ // If the argument type is a matrix, then this is an identity / conversion constructor.
+ // If the argument type is a vector, then we're already column vectors.
+ // If the argument type is abstract, then we're const-expression and there's no need to
+ // adjust this, as it'll be constant folded by the backend.
+ if (args[0]
+ ->Type()
+ ->UnwrapRef()
+ ->IsAnyOf<sem::Matrix, sem::Vector, sem::AbstractNumeric>()) {
return nullptr;
}
// Constructs a matrix using vector columns, with the elements constructed using the
// 'element(uint32_t c, uint32_t r)' callback.
auto build_mat = [&](auto&& element) {
- ast::ExpressionList columns(mat_type->columns());
+ utils::Vector<const ast::Expression*, 4> columns;
for (uint32_t c = 0; c < mat_type->columns(); c++) {
- ast::ExpressionList row_values(mat_type->rows());
+ utils::Vector<const ast::Expression*, 4> row_values;
for (uint32_t r = 0; r < mat_type->rows(); r++) {
- row_values[r] = element(c, r);
+ row_values.Push(element(c, r));
}
// Construct the column vector.
- columns[c] = ctx.dst->vec(CreateASTTypeFor(ctx, mat_type->type()), mat_type->rows(),
- row_values);
+ columns.Push(ctx.dst->vec(CreateASTTypeFor(ctx, mat_type->type()), mat_type->rows(),
+ std::move(row_values)));
}
return ctx.dst->Construct(CreateASTTypeFor(ctx, mat_type), columns);
};
- if (args.size() == 1) {
+ if (args.Length() == 1) {
// Generate a helper function for constructing the matrix.
// This is done to ensure that the single argument value is only evaluated once, and
// with the correct expression evaluation order.
@@ -94,12 +102,12 @@ void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx, const DataMap&, D
ctx.dst->Symbols().New("build_mat" + std::to_string(mat_type->columns()) + "x" +
std::to_string(mat_type->rows()));
ctx.dst->Func(name,
- {
+ utils::Vector{
// Single scalar parameter
ctx.dst->Param("value", CreateASTTypeFor(ctx, mat_type->type())),
},
CreateASTTypeFor(ctx, mat_type),
- {
+ utils::Vector{
ctx.dst->Return(build_mat([&](uint32_t, uint32_t) { //
return ctx.dst->Expr("value");
})),
@@ -109,7 +117,7 @@ void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx, const DataMap&, D
return ctx.dst->Call(fn, ctx.Clone(args[0]->Declaration()));
}
- if (args.size() == mat_type->columns() * mat_type->rows()) {
+ if (args.Length() == mat_type->columns() * mat_type->rows()) {
return build_mat([&](uint32_t c, uint32_t r) {
return ctx.Clone(args[c * mat_type->rows() + r]->Declaration());
});
diff --git a/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.h b/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.h
index 83c4ce1aa64..31c57f0a8c3 100644
--- a/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.h
+++ b/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors.h
@@ -20,7 +20,7 @@
namespace tint::transform {
/// A transform that converts scalar matrix constructors to the vector form.
-class VectorizeScalarMatrixConstructors
+class VectorizeScalarMatrixConstructors final
: public Castable<VectorizeScalarMatrixConstructors, Transform> {
public:
/// Constructor
diff --git a/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc b/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc
index 1ee9d337b7f..017af721736 100644
--- a/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc
+++ b/chromium/third_party/dawn/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc
@@ -31,48 +31,40 @@ TEST_F(VectorizeScalarMatrixConstructorsTest, ShouldRunEmptyModule) {
EXPECT_FALSE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
}
-TEST_P(VectorizeScalarMatrixConstructorsTest, SingleScalars) {
+TEST_P(VectorizeScalarMatrixConstructorsTest, MultipleScalars) {
uint32_t cols = GetParam().first;
uint32_t rows = GetParam().second;
- std::string matrix_no_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows);
- std::string matrix = matrix_no_type + "<f32>";
- std::string vector = "vec" + std::to_string(rows) + "<f32>";
- std::string values;
+ std::string mat_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>";
+ std::string vec_type = "vec" + std::to_string(rows) + "<f32>";
+ std::string scalar_values;
+ std::string vector_values;
for (uint32_t c = 0; c < cols; c++) {
if (c > 0) {
- values += ", ";
+ vector_values += ", ";
+ scalar_values += ", ";
}
- values += vector + "(";
+ vector_values += vec_type + "(";
for (uint32_t r = 0; r < rows; r++) {
if (r > 0) {
- values += ", ";
+ scalar_values += ", ";
+ vector_values += ", ";
}
- values += "value";
+ auto value = std::to_string(c * rows + r) + ".0";
+ scalar_values += value;
+ vector_values += value;
}
- values += ")";
+ vector_values += ")";
}
- std::string src = R"(
-@fragment
-fn main() {
- let m = ${matrix}(42.0);
-}
-)";
-
- std::string expect = R"(
-fn build_${matrix_no_type}(value : f32) -> ${matrix} {
- return ${matrix}(${values});
-}
-
+ std::string tmpl = R"(
@fragment
fn main() {
- let m = build_${matrix_no_type}(42.0);
+ let m = ${matrix}(${values});
}
)";
- src = utils::ReplaceAll(src, "${matrix}", matrix);
- expect = utils::ReplaceAll(expect, "${matrix}", matrix);
- expect = utils::ReplaceAll(expect, "${matrix_no_type}", matrix_no_type);
- expect = utils::ReplaceAll(expect, "${values}", values);
+ tmpl = utils::ReplaceAll(tmpl, "${matrix}", mat_type);
+ auto src = utils::ReplaceAll(tmpl, "${values}", scalar_values);
+ auto expect = utils::ReplaceAll(tmpl, "${values}", vector_values);
EXPECT_TRUE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
@@ -81,7 +73,7 @@ fn main() {
EXPECT_EQ(expect, str(got));
}
-TEST_P(VectorizeScalarMatrixConstructorsTest, MultipleScalars) {
+TEST_P(VectorizeScalarMatrixConstructorsTest, MultipleScalarsReference) {
uint32_t cols = GetParam().first;
uint32_t rows = GetParam().second;
std::string mat_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>";
@@ -99,7 +91,7 @@ TEST_P(VectorizeScalarMatrixConstructorsTest, MultipleScalars) {
scalar_values += ", ";
vector_values += ", ";
}
- auto value = std::to_string(c * rows + r) + ".0";
+ auto value = "v[" + std::to_string((c * rows + r) % 4) + "]";
scalar_values += value;
vector_values += value;
}
@@ -109,6 +101,7 @@ TEST_P(VectorizeScalarMatrixConstructorsTest, MultipleScalars) {
std::string tmpl = R"(
@fragment
fn main() {
+ let v = vec4<f32>(1.0, 2.0, 3.0, 8.0);
let m = ${matrix}(${values});
}
)";
diff --git a/chromium/third_party/dawn/src/tint/transform/vertex_pulling.cc b/chromium/third_party/dawn/src/tint/transform/vertex_pulling.cc
index e297c904493..6eb2bbf213a 100644
--- a/chromium/third_party/dawn/src/tint/transform/vertex_pulling.cc
+++ b/chromium/third_party/dawn/src/tint/transform/vertex_pulling.cc
@@ -228,7 +228,7 @@ struct State {
Symbol pulling_position_name;
Symbol struct_buffer_name;
std::unordered_map<uint32_t, Symbol> vertex_buffer_names;
- ast::VariableList new_function_parameters;
+ utils::Vector<const ast::Parameter*, 8> new_function_parameters;
/// Generate the vertex buffer binding name
/// @param index index to append to buffer name
@@ -254,17 +254,17 @@ struct State {
static const char kStructName[] = "TintVertexData";
auto* struct_type =
ctx.dst->Structure(ctx.dst->Symbols().New(kStructName),
- {
+ utils::Vector{
ctx.dst->Member(GetStructBufferName(), ctx.dst->ty.array<u32>()),
});
for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
// The decorated variable with struct type
- ctx.dst->Global(GetVertexBufferName(i), ctx.dst->ty.Of(struct_type),
- ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- ctx.dst->create<ast::BindingAttribute>(i),
- ctx.dst->create<ast::GroupAttribute>(cfg.pulling_group),
- });
+ ctx.dst->GlobalVar(GetVertexBufferName(i), ctx.dst->ty.Of(struct_type),
+ ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ ctx.dst->create<ast::BindingAttribute>(i),
+ ctx.dst->create<ast::GroupAttribute>(cfg.pulling_group),
+ });
}
}
@@ -273,7 +273,7 @@ struct State {
// Assign by looking at the vertex descriptor to find attributes with
// matching location.
- ast::StatementList stmts;
+ utils::Vector<const ast::Statement*, 8> stmts;
for (uint32_t buffer_idx = 0; buffer_idx < cfg.vertex_state.size(); ++buffer_idx) {
const VertexBufferLayoutDescriptor& buffer_layout = cfg.vertex_state[buffer_idx];
@@ -303,8 +303,7 @@ struct State {
}
// let pulling_offset_n = <attribute_offset>
- stmts.emplace_back(
- ctx.dst->Decl(ctx.dst->Let(buffer_array_base, nullptr, attribute_offset)));
+ stmts.Push(ctx.dst->Decl(ctx.dst->Let(buffer_array_base, nullptr, attribute_offset)));
for (const VertexAttributeDescriptor& attribute_desc : buffer_layout.attributes) {
auto it = location_info.find(attribute_desc.shader_location);
@@ -356,24 +355,24 @@ struct State {
} else if (var_dt.width > fmt_dt.width) {
// WGSL variable vector width is wider than the loaded vector width
const ast::Type* ty = nullptr;
- ast::ExpressionList values{fetch};
+ utils::Vector<const ast::Expression*, 8> values{fetch};
switch (var_dt.base_type) {
case BaseType::kI32:
ty = ctx.dst->ty.i32();
for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
- values.emplace_back(ctx.dst->Expr((i == 3) ? 1_i : 0_i));
+ values.Push(ctx.dst->Expr((i == 3) ? 1_i : 0_i));
}
break;
case BaseType::kU32:
ty = ctx.dst->ty.u32();
for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
- values.emplace_back(ctx.dst->Expr((i == 3) ? 1_u : 0_u));
+ values.Push(ctx.dst->Expr((i == 3) ? 1_u : 0_u));
}
break;
case BaseType::kF32:
ty = ctx.dst->ty.f32();
for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
- values.emplace_back(ctx.dst->Expr((i == 3) ? 1_f : 0_f));
+ values.Push(ctx.dst->Expr((i == 3) ? 1_f : 0_f));
}
break;
default:
@@ -384,15 +383,15 @@ struct State {
}
// Assign the value to the WGSL variable
- stmts.emplace_back(ctx.dst->Assign(var.expr(), value));
+ stmts.Push(ctx.dst->Assign(var.expr(), value));
}
}
- if (stmts.empty()) {
+ if (stmts.IsEmpty()) {
return nullptr;
}
- return ctx.dst->create<ast::BlockStatement>(stmts);
+ return ctx.dst->create<ast::BlockStatement>(std::move(stmts));
}
/// Generates an expression reading from a buffer a specific format.
@@ -679,11 +678,11 @@ struct State {
const ast::Type* base_type,
VertexFormat base_format,
uint32_t count) {
- ast::ExpressionList expr_list;
+ utils::Vector<const ast::Expression*, 8> expr_list;
for (uint32_t i = 0; i < count; ++i) {
// Offset read position by element_stride for each component
uint32_t primitive_offset = offset + element_stride * i;
- expr_list.push_back(LoadPrimitive(array_base, primitive_offset, buffer, base_format));
+ expr_list.Push(LoadPrimitive(array_base, primitive_offset, buffer, base_format));
}
return ctx.dst->Construct(ctx.dst->create<ast::Vector>(base_type, count),
@@ -695,7 +694,7 @@ struct State {
/// vertex_index and instance_index builtins if present.
/// @param func the entry point function
/// @param param the parameter to process
- void ProcessNonStructParameter(const ast::Function* func, const ast::Variable* param) {
+ void ProcessNonStructParameter(const ast::Function* func, const ast::Parameter* param) {
if (auto* location = ast::GetAttribute<ast::LocationAttribute>(param->attributes)) {
// Create a function-scope variable to replace the parameter.
auto func_var_sym = ctx.Clone(param->symbol);
@@ -709,16 +708,16 @@ struct State {
location_info[location->value] = info;
} else if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
// Check for existing vertex_index and instance_index builtins.
- if (builtin->builtin == ast::Builtin::kVertexIndex) {
+ if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
vertex_index_expr = [this, param]() {
return ctx.dst->Expr(ctx.Clone(param->symbol));
};
- } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
+ } else if (builtin->builtin == ast::BuiltinValue::kInstanceIndex) {
instance_index_expr = [this, param]() {
return ctx.dst->Expr(ctx.Clone(param->symbol));
};
}
- new_function_parameters.push_back(ctx.Clone(param));
+ new_function_parameters.Push(ctx.Clone(param));
} else {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << "Invalid entry point parameter";
}
@@ -733,13 +732,13 @@ struct State {
/// @param param the parameter to process
/// @param struct_ty the structure type
void ProcessStructParameter(const ast::Function* func,
- const ast::Variable* param,
+ const ast::Parameter* param,
const ast::Struct* struct_ty) {
auto param_sym = ctx.Clone(param->symbol);
// Process the struct members.
bool has_locations = false;
- ast::StructMemberList members_to_clone;
+ utils::Vector<const ast::StructMember*, 8> members_to_clone;
for (auto* member : struct_ty->members) {
auto member_sym = ctx.Clone(member->symbol);
std::function<const ast::Expression*()> member_expr = [this, param_sym, member_sym]() {
@@ -756,12 +755,12 @@ struct State {
} else if (auto* builtin =
ast::GetAttribute<ast::BuiltinAttribute>(member->attributes)) {
// Check for existing vertex_index and instance_index builtins.
- if (builtin->builtin == ast::Builtin::kVertexIndex) {
+ if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
vertex_index_expr = member_expr;
- } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
+ } else if (builtin->builtin == ast::BuiltinValue::kInstanceIndex) {
instance_index_expr = member_expr;
}
- members_to_clone.push_back(member);
+ members_to_clone.Push(member);
} else {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << "Invalid entry point parameter";
}
@@ -769,7 +768,7 @@ struct State {
if (!has_locations) {
// Nothing to do.
- new_function_parameters.push_back(ctx.Clone(param));
+ new_function_parameters.Push(ctx.Clone(param));
return;
}
@@ -777,21 +776,20 @@ struct State {
auto* func_var = ctx.dst->Var(param_sym, ctx.Clone(param->type));
ctx.InsertFront(func->body->statements, ctx.dst->Decl(func_var));
- if (!members_to_clone.empty()) {
+ if (!members_to_clone.IsEmpty()) {
// Create a new struct without the location attributes.
- ast::StructMemberList new_members;
+ utils::Vector<const ast::StructMember*, 8> new_members;
for (auto* member : members_to_clone) {
auto member_sym = ctx.Clone(member->symbol);
auto* member_type = ctx.Clone(member->type);
auto member_attrs = ctx.Clone(member->attributes);
- new_members.push_back(
- ctx.dst->Member(member_sym, member_type, std::move(member_attrs)));
+ new_members.Push(ctx.dst->Member(member_sym, member_type, std::move(member_attrs)));
}
auto* new_struct = ctx.dst->Structure(ctx.dst->Sym(), new_members);
// Create a new function parameter with this struct.
auto* new_param = ctx.dst->Param(ctx.dst->Sym(), ctx.dst->ty.Of(new_struct));
- new_function_parameters.push_back(new_param);
+ new_function_parameters.Push(new_param);
// Copy values from the new parameter to the function-scope variable.
for (auto* member : members_to_clone) {
@@ -825,8 +823,9 @@ struct State {
for (const VertexBufferLayoutDescriptor& layout : cfg.vertex_state) {
if (layout.step_mode == VertexStepMode::kVertex) {
auto name = ctx.dst->Symbols().New("tint_pulling_vertex_index");
- new_function_parameters.push_back(ctx.dst->Param(
- name, ctx.dst->ty.u32(), {ctx.dst->Builtin(ast::Builtin::kVertexIndex)}));
+ new_function_parameters.Push(ctx.dst->Param(
+ name, ctx.dst->ty.u32(),
+ utils::Vector{ctx.dst->Builtin(ast::BuiltinValue::kVertexIndex)}));
vertex_index_expr = [this, name]() { return ctx.dst->Expr(name); };
break;
}
@@ -836,8 +835,9 @@ struct State {
for (const VertexBufferLayoutDescriptor& layout : cfg.vertex_state) {
if (layout.step_mode == VertexStepMode::kInstance) {
auto name = ctx.dst->Symbols().New("tint_pulling_instance_index");
- new_function_parameters.push_back(ctx.dst->Param(
- name, ctx.dst->ty.u32(), {ctx.dst->Builtin(ast::Builtin::kInstanceIndex)}));
+ new_function_parameters.Push(ctx.dst->Param(
+ name, ctx.dst->ty.u32(),
+ utils::Vector{ctx.dst->Builtin(ast::BuiltinValue::kInstanceIndex)}));
instance_index_expr = [this, name]() { return ctx.dst->Expr(name); };
break;
}
diff --git a/chromium/third_party/dawn/src/tint/transform/vertex_pulling.h b/chromium/third_party/dawn/src/tint/transform/vertex_pulling.h
index 78756005deb..92eb627524f 100644
--- a/chromium/third_party/dawn/src/tint/transform/vertex_pulling.h
+++ b/chromium/third_party/dawn/src/tint/transform/vertex_pulling.h
@@ -128,10 +128,10 @@ using VertexStateDescriptor = std::vector<VertexBufferLayoutDescriptor>;
/// code, but these are types that the data may arrive as. We need to convert
/// these smaller types into the base types such as `f32` and `u32` for the
/// shader to use.
-class VertexPulling : public Castable<VertexPulling, Transform> {
+class VertexPulling final : public Castable<VertexPulling, Transform> {
public:
/// Configuration options for the transform
- struct Config : public Castable<Config, Data> {
+ struct Config final : public Castable<Config, Data> {
/// Constructor
Config();
diff --git a/chromium/third_party/dawn/src/tint/transform/while_to_loop.cc b/chromium/third_party/dawn/src/tint/transform/while_to_loop.cc
new file mode 100644
index 00000000000..45944e67aed
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/while_to_loop.cc
@@ -0,0 +1,67 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/while_to_loop.h"
+
+#include "src/tint/ast/break_statement.h"
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::transform::WhileToLoop);
+
+namespace tint::transform {
+
+WhileToLoop::WhileToLoop() = default;
+
+WhileToLoop::~WhileToLoop() = default;
+
+bool WhileToLoop::ShouldRun(const Program* program, const DataMap&) const {
+ for (auto* node : program->ASTNodes().Objects()) {
+ if (node->Is<ast::WhileStatement>()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void WhileToLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+ ctx.ReplaceAll([&](const ast::WhileStatement* w) -> const ast::Statement* {
+ utils::Vector<const ast::Statement*, 16> stmts;
+ auto* cond = w->condition;
+
+ // !condition
+ auto* not_cond =
+ ctx.dst->create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, ctx.Clone(cond));
+
+ // { break; }
+ auto* break_body = ctx.dst->Block(ctx.dst->create<ast::BreakStatement>());
+
+ // if (!condition) { break; }
+ stmts.Push(ctx.dst->If(not_cond, break_body));
+
+ for (auto* stmt : w->body->statements) {
+ stmts.Push(ctx.Clone(stmt));
+ }
+
+ const ast::BlockStatement* continuing = nullptr;
+
+ auto* body = ctx.dst->Block(stmts);
+ auto* loop = ctx.dst->create<ast::LoopStatement>(body, continuing);
+
+ return loop;
+ });
+
+ ctx.Clone();
+}
+
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var.h b/chromium/third_party/dawn/src/tint/transform/while_to_loop.h
index 67a32c48b82..4915d681e69 100644
--- a/chromium/third_party/dawn/src/tint/transform/promote_initializers_to_const_var.h
+++ b/chromium/third_party/dawn/src/tint/transform/while_to_loop.h
@@ -12,23 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_CONST_VAR_H_
-#define SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_CONST_VAR_H_
+#ifndef SRC_TINT_TRANSFORM_WHILE_TO_LOOP_H_
+#define SRC_TINT_TRANSFORM_WHILE_TO_LOOP_H_
#include "src/tint/transform/transform.h"
namespace tint::transform {
-/// A transform that hoists the array and structure initializers to a constant
-/// variable, declared just before the statement of usage.
-/// @see crbug.com/tint/406
-class PromoteInitializersToConstVar : public Castable<PromoteInitializersToConstVar, Transform> {
+/// WhileToLoop is a Transform that converts a while statement into a loop
+/// statement. This is required by the SPIR-V writer.
+class WhileToLoop final : public Castable<WhileToLoop, Transform> {
public:
/// Constructor
- PromoteInitializersToConstVar();
+ WhileToLoop();
/// Destructor
- ~PromoteInitializersToConstVar() override;
+ ~WhileToLoop() override;
+
+ /// @param program the program to inspect
+ /// @param data optional extra transform-specific input data
+ /// @returns true if this transform should be run for the given program
+ bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
protected:
/// Runs the transform using the CloneContext built for transforming a
@@ -42,4 +46,4 @@ class PromoteInitializersToConstVar : public Castable<PromoteInitializersToConst
} // namespace tint::transform
-#endif // SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_CONST_VAR_H_
+#endif // SRC_TINT_TRANSFORM_WHILE_TO_LOOP_H_
diff --git a/chromium/third_party/dawn/src/tint/transform/while_to_loop_test.cc b/chromium/third_party/dawn/src/tint/transform/while_to_loop_test.cc
new file mode 100644
index 00000000000..6e5699dfb79
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/transform/while_to_loop_test.cc
@@ -0,0 +1,129 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/while_to_loop.h"
+
+#include "src/tint/transform/test_helper.h"
+
+namespace tint::transform {
+namespace {
+
+using WhileToLoopTest = TransformTest;
+
+TEST_F(WhileToLoopTest, ShouldRunEmptyModule) {
+ auto* src = R"()";
+
+ EXPECT_FALSE(ShouldRun<WhileToLoop>(src));
+}
+
+TEST_F(WhileToLoopTest, ShouldRunHasWhile) {
+ auto* src = R"(
+fn f() {
+ while (true) {
+ break;
+ }
+}
+)";
+
+ EXPECT_TRUE(ShouldRun<WhileToLoop>(src));
+}
+
+TEST_F(WhileToLoopTest, EmptyModule) {
+ auto* src = "";
+ auto* expect = src;
+
+ auto got = Run<WhileToLoop>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+// Test an empty for loop.
+TEST_F(WhileToLoopTest, Empty) {
+ auto* src = R"(
+fn f() {
+ while (true) {
+ break;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ loop {
+ if (!(true)) {
+ break;
+ }
+ break;
+ }
+}
+)";
+
+ auto got = Run<WhileToLoop>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+// Test a for loop with non-empty body.
+TEST_F(WhileToLoopTest, Body) {
+ auto* src = R"(
+fn f() {
+ while (true) {
+ discard;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ loop {
+ if (!(true)) {
+ break;
+ }
+ discard;
+ }
+}
+)";
+
+ auto got = Run<WhileToLoop>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+// Test a loop with a break condition
+TEST_F(WhileToLoopTest, BreakCondition) {
+ auto* src = R"(
+fn f() {
+ while (0 == 1) {
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ loop {
+ if (!((0 == 1))) {
+ break;
+ }
+ }
+}
+)";
+
+ auto got = Run<WhileToLoop>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace
+
+} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.cc b/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.cc
deleted file mode 100644
index eb133d784ef..00000000000
--- a/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/transform/wrap_arrays_in_structs.h"
-
-#include <utility>
-
-#include "src/tint/program_builder.h"
-#include "src/tint/sem/array.h"
-#include "src/tint/sem/call.h"
-#include "src/tint/sem/expression.h"
-#include "src/tint/sem/type_constructor.h"
-#include "src/tint/utils/map.h"
-#include "src/tint/utils/transform.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::transform::WrapArraysInStructs);
-
-namespace tint::transform {
-
-WrapArraysInStructs::WrappedArrayInfo::WrappedArrayInfo() = default;
-WrapArraysInStructs::WrappedArrayInfo::WrappedArrayInfo(const WrappedArrayInfo&) = default;
-WrapArraysInStructs::WrappedArrayInfo::~WrappedArrayInfo() = default;
-
-WrapArraysInStructs::WrapArraysInStructs() = default;
-
-WrapArraysInStructs::~WrapArraysInStructs() = default;
-
-bool WrapArraysInStructs::ShouldRun(const Program* program, const DataMap&) const {
- for (auto* node : program->ASTNodes().Objects()) {
- if (program->Sem().Get<sem::Array>(node->As<ast::Type>())) {
- return true;
- }
- }
- return false;
-}
-
-void WrapArraysInStructs::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
- auto& sem = ctx.src->Sem();
-
- std::unordered_map<const sem::Array*, WrappedArrayInfo> wrapped_arrays;
- auto wrapper = [&](const sem::Array* array) { return WrapArray(ctx, wrapped_arrays, array); };
- auto wrapper_typename = [&](const sem::Array* arr) -> ast::TypeName* {
- auto info = wrapper(arr);
- return info ? ctx.dst->create<ast::TypeName>(info.wrapper_name) : nullptr;
- };
-
- // Replace all array types with their corresponding wrapper
- ctx.ReplaceAll([&](const ast::Type* ast_type) -> const ast::Type* {
- auto* type = ctx.src->TypeOf(ast_type);
- if (auto* array = type->UnwrapRef()->As<sem::Array>()) {
- return wrapper_typename(array);
- }
- return nullptr;
- });
-
- // Fix up index accessors so `a[1]` becomes `a.arr[1]`
- ctx.ReplaceAll(
- [&](const ast::IndexAccessorExpression* accessor) -> const ast::IndexAccessorExpression* {
- if (auto* array =
- ::tint::As<sem::Array>(sem.Get(accessor->object)->Type()->UnwrapRef())) {
- if (wrapper(array)) {
- // Array is wrapped in a structure. Emit a member accessor to get
- // to the actual array.
- auto* arr = ctx.Clone(accessor->object);
- auto* idx = ctx.Clone(accessor->index);
- auto* unwrapped = ctx.dst->MemberAccessor(arr, "arr");
- return ctx.dst->IndexAccessor(accessor->source, unwrapped, idx);
- }
- }
- return nullptr;
- });
-
- // Fix up array constructors so `A(1,2)` becomes `tint_array_wrapper(A(1,2))`
- ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
- if (auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>()) {
- if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
- if (auto* array = ctor->ReturnType()->As<sem::Array>()) {
- if (auto w = wrapper(array)) {
- // Wrap the array type constructor with another constructor for
- // the wrapper
- auto* wrapped_array_ty = ctx.dst->ty.type_name(w.wrapper_name);
- auto* array_ty = w.array_type(ctx);
- auto args = utils::Transform(call->Arguments(),
- [&](const tint::sem::Expression* s) {
- return ctx.Clone(s->Declaration());
- });
- auto* arr_ctor = ctx.dst->Construct(array_ty, args);
- return ctx.dst->Construct(wrapped_array_ty, arr_ctor);
- }
- }
- }
- }
- return nullptr;
- });
-
- ctx.Clone();
-}
-
-WrapArraysInStructs::WrappedArrayInfo WrapArraysInStructs::WrapArray(
- CloneContext& ctx,
- std::unordered_map<const sem::Array*, WrappedArrayInfo>& wrapped_arrays,
- const sem::Array* array) const {
- if (array->IsRuntimeSized()) {
- return {}; // We don't want to wrap runtime sized arrays
- }
-
- return utils::GetOrCreate(wrapped_arrays, array, [&] {
- WrappedArrayInfo info;
-
- // Generate a unique name for the array wrapper
- info.wrapper_name = ctx.dst->Symbols().New("tint_array_wrapper");
-
- // Examine the element type. Is it also an array?
- std::function<const ast::Type*(CloneContext&)> el_type;
- if (auto* el_array = array->ElemType()->As<sem::Array>()) {
- // Array of array - call WrapArray() on the element type
- if (auto el = WrapArray(ctx, wrapped_arrays, el_array)) {
- el_type = [=](CloneContext& c) {
- return c.dst->create<ast::TypeName>(el.wrapper_name);
- };
- }
- }
-
- // If the element wasn't an array, just create the typical AST type for it
- if (!el_type) {
- el_type = [=](CloneContext& c) { return CreateASTTypeFor(c, array->ElemType()); };
- }
-
- // Construct the single structure field type
- info.array_type = [=](CloneContext& c) {
- ast::AttributeList attrs;
- if (!array->IsStrideImplicit()) {
- attrs.emplace_back(c.dst->create<ast::StrideAttribute>(array->Stride()));
- }
- return c.dst->ty.array(el_type(c), u32(array->Count()), std::move(attrs));
- };
-
- // Structure() will create and append the ast::Struct to the
- // global declarations of `ctx.dst`. As we haven't finished building the
- // current module-scope statement or function, this will be placed
- // immediately before the usage.
- ctx.dst->Structure(info.wrapper_name, {ctx.dst->Member("arr", info.array_type(ctx))});
- return info;
- });
-}
-
-} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.h b/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.h
deleted file mode 100644
index 4653c6beeab..00000000000
--- a/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_TINT_TRANSFORM_WRAP_ARRAYS_IN_STRUCTS_H_
-#define SRC_TINT_TRANSFORM_WRAP_ARRAYS_IN_STRUCTS_H_
-
-#include <string>
-#include <unordered_map>
-
-#include "src/tint/transform/transform.h"
-
-// Forward declarations
-namespace tint::ast {
-class Type;
-} // namespace tint::ast
-
-namespace tint::transform {
-
-/// WrapArraysInStructs is a transform that replaces all array types with a
-/// structure holding a single field of that array type.
-/// Array index expressions and constructors are also adjusted to deal with this
-/// wrapping.
-/// This transform helps with backends that cannot directly return arrays or use
-/// them as parameters.
-class WrapArraysInStructs : public Castable<WrapArraysInStructs, Transform> {
- public:
- /// Constructor
- WrapArraysInStructs();
-
- /// Destructor
- ~WrapArraysInStructs() override;
-
- /// @param program the program to inspect
- /// @param data optional extra transform-specific input data
- /// @returns true if this transform should be run for the given program
- bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
-
- protected:
- /// Runs the transform using the CloneContext built for transforming a
- /// program. Run() is responsible for calling Clone() on the CloneContext.
- /// @param ctx the CloneContext primed with the input program and
- /// ProgramBuilder
- /// @param inputs optional extra transform-specific input data
- /// @param outputs optional extra transform-specific output data
- void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
-
- private:
- struct WrappedArrayInfo {
- WrappedArrayInfo();
- WrappedArrayInfo(const WrappedArrayInfo&);
- ~WrappedArrayInfo();
-
- Symbol wrapper_name;
- std::function<const ast::Type*(CloneContext&)> array_type;
-
- operator bool() { return wrapper_name.IsValid(); }
- };
-
- /// WrapArray wraps the fixed-size array type in a new structure (if it hasn't
- /// already been wrapped). WrapArray will recursively wrap arrays-of-arrays.
- /// The new structure will be added to module-scope type declarations of
- /// `ctx.dst`.
- /// @param ctx the CloneContext
- /// @param wrapped_arrays a map of src array type to the wrapped structure
- /// name
- /// @param array the array type
- /// @return the name of the structure that wraps the array, or an invalid
- /// Symbol if this array should not be wrapped
- WrappedArrayInfo WrapArray(
- CloneContext& ctx,
- std::unordered_map<const sem::Array*, WrappedArrayInfo>& wrapped_arrays,
- const sem::Array* array) const;
-};
-
-} // namespace tint::transform
-
-#endif // SRC_TINT_TRANSFORM_WRAP_ARRAYS_IN_STRUCTS_H_
diff --git a/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs_test.cc b/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs_test.cc
deleted file mode 100644
index 7a7a6b337d6..00000000000
--- a/chromium/third_party/dawn/src/tint/transform/wrap_arrays_in_structs_test.cc
+++ /dev/null
@@ -1,422 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/transform/wrap_arrays_in_structs.h"
-
-#include <memory>
-#include <utility>
-
-#include "src/tint/transform/test_helper.h"
-
-namespace tint::transform {
-namespace {
-
-using WrapArraysInStructsTest = TransformTest;
-
-TEST_F(WrapArraysInStructsTest, ShouldRunEmptyModule) {
- auto* src = R"()";
-
- EXPECT_FALSE(ShouldRun<WrapArraysInStructs>(src));
-}
-
-TEST_F(WrapArraysInStructsTest, ShouldRunHasArray) {
- auto* src = R"(
-var<private> arr : array<i32, 4>;
-)";
-
- EXPECT_TRUE(ShouldRun<WrapArraysInStructs>(src));
-}
-
-TEST_F(WrapArraysInStructsTest, EmptyModule) {
- auto* src = R"()";
- auto* expect = src;
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArrayAsGlobal) {
- auto* src = R"(
-var<private> arr : array<i32, 4>;
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 4u>,
-}
-
-var<private> arr : tint_array_wrapper;
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArrayAsFunctionVar) {
- auto* src = R"(
-fn f() {
- var arr : array<i32, 4>;
- let x = arr[3];
-}
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 4u>,
-}
-
-fn f() {
- var arr : tint_array_wrapper;
- let x = arr.arr[3];
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArrayAsParam) {
- auto* src = R"(
-fn f(a : array<i32, 4>) -> i32 {
- return a[2];
-}
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 4u>,
-}
-
-fn f(a : tint_array_wrapper) -> i32 {
- return a.arr[2];
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArrayAsReturn) {
- auto* src = R"(
-fn f() -> array<i32, 4> {
- return array<i32, 4>(1, 2, 3, 4);
-}
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 4u>,
-}
-
-fn f() -> tint_array_wrapper {
- return tint_array_wrapper(array<i32, 4u>(1, 2, 3, 4));
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArrayAlias) {
- auto* src = R"(
-type Inner = array<i32, 2>;
-type Array = array<Inner, 2>;
-
-fn f() {
- var arr : Array;
- arr = Array();
- arr = Array(Inner(1, 2), Inner(3, 4));
- let vals : Array = Array(Inner(1, 2), Inner(3, 4));
- arr = vals;
- let x = arr[3];
-}
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 2u>,
-}
-
-type Inner = tint_array_wrapper;
-
-struct tint_array_wrapper_1 {
- arr : array<tint_array_wrapper, 2u>,
-}
-
-type Array = tint_array_wrapper_1;
-
-fn f() {
- var arr : tint_array_wrapper_1;
- arr = tint_array_wrapper_1(array<tint_array_wrapper, 2u>());
- arr = tint_array_wrapper_1(array<tint_array_wrapper, 2u>(tint_array_wrapper(array<i32, 2u>(1, 2)), tint_array_wrapper(array<i32, 2u>(3, 4))));
- let vals : tint_array_wrapper_1 = tint_array_wrapper_1(array<tint_array_wrapper, 2u>(tint_array_wrapper(array<i32, 2u>(1, 2)), tint_array_wrapper(array<i32, 2u>(3, 4))));
- arr = vals;
- let x = arr.arr[3];
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArrayAlias_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var arr : Array;
- arr = Array();
- arr = Array(Inner(1, 2), Inner(3, 4));
- let vals : Array = Array(Inner(1, 2), Inner(3, 4));
- arr = vals;
- let x = arr[3];
-}
-
-type Array = array<Inner, 2>;
-type Inner = array<i32, 2>;
-)";
- auto* expect = R"(
-struct tint_array_wrapper_1 {
- arr : array<i32, 2u>,
-}
-
-struct tint_array_wrapper {
- arr : array<tint_array_wrapper_1, 2u>,
-}
-
-fn f() {
- var arr : tint_array_wrapper;
- arr = tint_array_wrapper(array<tint_array_wrapper_1, 2u>());
- arr = tint_array_wrapper(array<tint_array_wrapper_1, 2u>(tint_array_wrapper_1(array<i32, 2u>(1, 2)), tint_array_wrapper_1(array<i32, 2u>(3, 4))));
- let vals : tint_array_wrapper = tint_array_wrapper(array<tint_array_wrapper_1, 2u>(tint_array_wrapper_1(array<i32, 2u>(1, 2)), tint_array_wrapper_1(array<i32, 2u>(3, 4))));
- arr = vals;
- let x = arr.arr[3];
-}
-
-type Array = tint_array_wrapper;
-
-type Inner = tint_array_wrapper_1;
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArraysInStruct) {
- auto* src = R"(
-struct S {
- a : array<i32, 4>,
- b : array<i32, 8>,
- c : array<i32, 4>,
-};
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 4u>,
-}
-
-struct tint_array_wrapper_1 {
- arr : array<i32, 8u>,
-}
-
-struct S {
- a : tint_array_wrapper,
- b : tint_array_wrapper_1,
- c : tint_array_wrapper,
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, ArraysOfArraysInStruct) {
- auto* src = R"(
-struct S {
- a : array<i32, 4>,
- b : array<array<i32, 4>, 4>,
- c : array<array<array<i32, 4>, 4>, 4>,
-};
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 4u>,
-}
-
-struct tint_array_wrapper_1 {
- arr : array<tint_array_wrapper, 4u>,
-}
-
-struct tint_array_wrapper_2 {
- arr : array<tint_array_wrapper_1, 4u>,
-}
-
-struct S {
- a : tint_array_wrapper,
- b : tint_array_wrapper_1,
- c : tint_array_wrapper_2,
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, AccessArraysOfArraysInStruct) {
- auto* src = R"(
-struct S {
- a : array<i32, 4>,
- b : array<array<i32, 4>, 4>,
- c : array<array<array<i32, 4>, 4>, 4>,
-};
-
-fn f(s : S) -> i32 {
- return s.a[2] + s.b[1][2] + s.c[3][1][2];
-}
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 4u>,
-}
-
-struct tint_array_wrapper_1 {
- arr : array<tint_array_wrapper, 4u>,
-}
-
-struct tint_array_wrapper_2 {
- arr : array<tint_array_wrapper_1, 4u>,
-}
-
-struct S {
- a : tint_array_wrapper,
- b : tint_array_wrapper_1,
- c : tint_array_wrapper_2,
-}
-
-fn f(s : S) -> i32 {
- return ((s.a.arr[2] + s.b.arr[1].arr[2]) + s.c.arr[3].arr[1].arr[2]);
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, DeclarationOrder) {
- auto* src = R"(
-type T0 = i32;
-
-type T1 = array<i32, 1>;
-
-type T2 = i32;
-
-fn f1(a : array<i32, 2>) {
-}
-
-type T3 = i32;
-
-fn f2() {
- var v : array<i32, 3>;
-}
-)";
- auto* expect = R"(
-type T0 = i32;
-
-struct tint_array_wrapper {
- arr : array<i32, 1u>,
-}
-
-type T1 = tint_array_wrapper;
-
-type T2 = i32;
-
-struct tint_array_wrapper_1 {
- arr : array<i32, 2u>,
-}
-
-fn f1(a : tint_array_wrapper_1) {
-}
-
-type T3 = i32;
-
-struct tint_array_wrapper_2 {
- arr : array<i32, 3u>,
-}
-
-fn f2() {
- var v : tint_array_wrapper_2;
-}
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(WrapArraysInStructsTest, DeclarationOrder_OutOfOrder) {
- auto* src = R"(
-fn f2() {
- var v : array<i32, 3>;
-}
-
-type T3 = i32;
-
-fn f1(a : array<i32, 2>) {
-}
-
-type T2 = i32;
-
-type T1 = array<i32, 1>;
-
-type T0 = i32;
-)";
- auto* expect = R"(
-struct tint_array_wrapper {
- arr : array<i32, 3u>,
-}
-
-fn f2() {
- var v : tint_array_wrapper;
-}
-
-type T3 = i32;
-
-struct tint_array_wrapper_1 {
- arr : array<i32, 2u>,
-}
-
-fn f1(a : tint_array_wrapper_1) {
-}
-
-type T2 = i32;
-
-struct tint_array_wrapper_2 {
- arr : array<i32, 1u>,
-}
-
-type T1 = tint_array_wrapper_2;
-
-type T0 = i32;
-)";
-
- auto got = Run<WrapArraysInStructs>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-} // namespace
-} // namespace tint::transform
diff --git a/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.cc b/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.cc
index 6e843109922..94df3b9885a 100644
--- a/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.cc
@@ -32,6 +32,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::transform::ZeroInitWorkgroupMemory);
namespace tint::transform {
+using StatementList = utils::Vector<const ast::Statement*, 8>;
+
/// PIMPL state for the ZeroInitWorkgroupMemory transform
struct ZeroInitWorkgroupMemory::State {
/// The clone context
@@ -73,7 +75,7 @@ struct ZeroInitWorkgroupMemory::State {
};
/// A list of unique ArrayIndex
- using ArrayIndices = utils::UniqueVector<ArrayIndex, ArrayIndex::Hasher>;
+ using ArrayIndices = utils::UniqueVector<ArrayIndex, 4, ArrayIndex::Hasher>;
/// Expression holds information about an expression that is being built for a
/// statement will zero workgroup values.
@@ -137,7 +139,7 @@ struct ZeroInitWorkgroupMemory::State {
std::function<const ast::Expression*()> local_index;
for (auto* param : fn->params) {
if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
- if (builtin->builtin == ast::Builtin::kLocalInvocationIndex) {
+ if (builtin->builtin == ast::BuiltinValue::kLocalInvocationIndex) {
local_index = [=] { return b.Expr(ctx.Clone(param->symbol)); };
break;
}
@@ -147,7 +149,7 @@ struct ZeroInitWorkgroupMemory::State {
for (auto* member : str->Members()) {
if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(
member->Declaration()->attributes)) {
- if (builtin->builtin == ast::Builtin::kLocalInvocationIndex) {
+ if (builtin->builtin == ast::BuiltinValue::kLocalInvocationIndex) {
local_index = [=] {
auto* param_expr = b.Expr(ctx.Clone(param->symbol));
auto member_name = ctx.Clone(member->Declaration()->symbol);
@@ -162,7 +164,9 @@ struct ZeroInitWorkgroupMemory::State {
if (!local_index) {
// No existing local index parameter. Append one to the entry point.
auto* param = b.Param(b.Symbols().New("local_invocation_index"), b.ty.u32(),
- {b.Builtin(ast::Builtin::kLocalInvocationIndex)});
+ utils::Vector{
+ b.Builtin(ast::BuiltinValue::kLocalInvocationIndex),
+ });
ctx.InsertBack(fn->params, param);
local_index = [=] { return b.Expr(param->symbol); };
}
@@ -189,7 +193,7 @@ struct ZeroInitWorkgroupMemory::State {
ArrayIndices array_indices;
for (auto& s : stmts) {
for (auto& idx : s.array_indices) {
- array_indices.add(idx);
+ array_indices.Add(idx);
}
}
@@ -216,7 +220,7 @@ struct ZeroInitWorkgroupMemory::State {
auto block =
DeclareArrayIndices(num_iterations, array_indices, [&] { return b.Expr(idx); });
for (auto& s : stmts) {
- block.emplace_back(s.stmt);
+ block.Push(s.stmt);
}
auto* for_loop = b.For(init, cond, cont, b.Block(block));
ctx.InsertFront(fn->body->statements, for_loop);
@@ -232,7 +236,7 @@ struct ZeroInitWorkgroupMemory::State {
auto block = DeclareArrayIndices(num_iterations, array_indices,
[&] { return b.Expr(local_index()); });
for (auto& s : stmts) {
- block.emplace_back(s.stmt);
+ block.Push(s.stmt);
}
auto* if_stmt = b.If(cond, b.Block(block));
ctx.InsertFront(fn->body->statements, if_stmt);
@@ -246,7 +250,7 @@ struct ZeroInitWorkgroupMemory::State {
auto block = DeclareArrayIndices(num_iterations, array_indices,
[&] { return b.Expr(local_index()); });
for (auto& s : stmts) {
- block.emplace_back(s.stmt);
+ block.Push(s.stmt);
}
ctx.InsertFront(fn->body->statements, b.Block(block));
}
@@ -307,7 +311,7 @@ struct ZeroInitWorkgroupMemory::State {
auto division = num_values;
auto a = get_expr(modulo);
auto array_indices = a.array_indices;
- array_indices.add(ArrayIndex{modulo, division});
+ array_indices.Add(ArrayIndex{modulo, division});
auto index = utils::GetOrCreate(array_index_names, ArrayIndex{modulo, division},
[&] { return b.Symbols().New("i"); });
return Expression{b.IndexAccessor(a.expr, index), a.num_iterations, array_indices};
@@ -327,11 +331,10 @@ struct ZeroInitWorkgroupMemory::State {
/// @param iteration a function that returns the index of the current
/// iteration.
/// @returns the list of `let` statements that declare the array indices
- ast::StatementList DeclareArrayIndices(
- uint32_t num_iterations,
- const ArrayIndices& array_indices,
- const std::function<const ast::Expression*()>& iteration) {
- ast::StatementList stmts;
+ StatementList DeclareArrayIndices(uint32_t num_iterations,
+ const ArrayIndices& array_indices,
+ const std::function<const ast::Expression*()>& iteration) {
+ StatementList stmts;
std::map<Symbol, ArrayIndex> indices_by_name;
for (auto index : array_indices) {
auto name = array_index_names.at(index);
@@ -341,7 +344,7 @@ struct ZeroInitWorkgroupMemory::State {
: iteration();
auto* div = (index.division != 1u) ? b.Div(mod, u32(index.division)) : mod;
auto* decl = b.Decl(b.Let(name, b.ty.u32(), div));
- stmts.emplace_back(decl);
+ stmts.Push(decl);
}
return stmts;
}
@@ -358,8 +361,8 @@ struct ZeroInitWorkgroupMemory::State {
continue;
}
auto* sem = ctx.src->Sem().Get(expr);
- if (auto c = sem->ConstantValue()) {
- workgroup_size_const *= c.Element<AInt>(0).value;
+ if (auto* c = sem->ConstantValue()) {
+ workgroup_size_const *= c->As<AInt>();
continue;
}
// Constant value could not be found. Build expression instead.
@@ -416,8 +419,8 @@ ZeroInitWorkgroupMemory::ZeroInitWorkgroupMemory() = default;
ZeroInitWorkgroupMemory::~ZeroInitWorkgroupMemory() = default;
bool ZeroInitWorkgroupMemory::ShouldRun(const Program* program, const DataMap&) const {
- for (auto* decl : program->AST().GlobalDeclarations()) {
- if (auto* var = decl->As<ast::Variable>()) {
+ for (auto* global : program->AST().GlobalVariables()) {
+ if (auto* var = global->As<ast::Var>()) {
if (var->declared_storage_class == ast::StorageClass::kWorkgroup) {
return true;
}
diff --git a/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.h b/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.h
index c75772553d7..07feaa895a6 100644
--- a/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.h
+++ b/chromium/third_party/dawn/src/tint/transform/zero_init_workgroup_memory.h
@@ -22,7 +22,7 @@ namespace tint::transform {
/// ZeroInitWorkgroupMemory is a transform that injects code at the top of entry
/// points to zero-initialize workgroup memory used by that entry point (and all
/// transitive functions called by that entry point)
-class ZeroInitWorkgroupMemory : public Castable<ZeroInitWorkgroupMemory, Transform> {
+class ZeroInitWorkgroupMemory final : public Castable<ZeroInitWorkgroupMemory, Transform> {
public:
/// Constructor
ZeroInitWorkgroupMemory();
diff --git a/chromium/third_party/dawn/src/tint/utils/bitset.h b/chromium/third_party/dawn/src/tint/utils/bitset.h
new file mode 100644
index 00000000000..86dccd6ddbf
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/bitset.h
@@ -0,0 +1,102 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_UTILS_BITSET_H_
+#define SRC_TINT_UTILS_BITSET_H_
+
+#include <stdint.h>
+
+#include "src/tint/utils/vector.h"
+
+namespace tint::utils {
+
+/// Bitset is a dynamically sized, vector of bits, packed into integer words.
+/// Bits can be individually read and written using the index operator.
+///
+/// Bitset will fit at least `N` bits internally before spilling to heap allocations.
+template <size_t N = 0>
+class Bitset {
+ /// The integer word type used to hold the bits
+ using Word = size_t;
+ /// Number of bits per word
+ static constexpr size_t kWordBits = sizeof(Word) * 8;
+
+ /// Number of words required to hold the number of bits
+ static constexpr size_t NumWords(size_t num_bits) {
+ return ((num_bits + kWordBits - 1) / kWordBits);
+ }
+
+ public:
+ /// Constructor
+ Bitset() = default;
+
+ /// Destructor
+ ~Bitset() = default;
+
+ /// Accessor for a single bit
+ struct Bit {
+ /// The word that contains the bit
+ Word& word;
+ /// A word with a single bit set, which masks the targetted bit
+ Word const mask;
+
+ /// Assignment operator
+ /// @param value the new value for the bit
+ /// @returns this Bit so calls can be chained
+ const Bit& operator=(bool value) const {
+ if (value) {
+ word = word | mask;
+ } else {
+ word = word & ~mask;
+ }
+ return *this;
+ }
+
+ /// Conversion operator
+ /// @returns the bit value
+ operator bool() const { return (word & mask) != 0; }
+ };
+
+ /// @param new_len the new size of the bitmap, in bits.
+ void Resize(size_t new_len) {
+ vec_.Resize(NumWords(new_len));
+
+ // Clear any potentially set bits that are in the top part of the word
+ if (size_t high_bit = new_len % kWordBits; high_bit > 0) {
+ vec_.Back() &= (static_cast<Word>(1) << high_bit) - 1;
+ }
+
+ len_ = new_len;
+ }
+
+ /// @return the number of bits in the bitset.
+ size_t Length() const { return len_; }
+
+ /// Index operator
+ /// @param index the index of the bit to access
+ /// @return the accessor for the indexed bit
+ Bit operator[](size_t index) {
+ auto& word = vec_[index / kWordBits];
+ auto mask = static_cast<Word>(1) << (index % kWordBits);
+ return Bit{word, mask};
+ }
+
+ private:
+ Vector<size_t, NumWords(N)> vec_;
+ size_t len_ = 0;
+};
+
+} // namespace tint::utils
+
+#endif // SRC_TINT_UTILS_BITSET_H_
diff --git a/chromium/third_party/dawn/src/tint/utils/bitset_test.cc b/chromium/third_party/dawn/src/tint/utils/bitset_test.cc
new file mode 100644
index 00000000000..b07cf744933
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/bitset_test.cc
@@ -0,0 +1,119 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/bitset.h"
+
+#include "gtest/gtest.h"
+
+namespace tint::utils {
+namespace {
+
+TEST(Bitset, Length) {
+ Bitset<8> bits;
+ EXPECT_EQ(bits.Length(), 0u);
+ bits.Resize(100u);
+ EXPECT_EQ(bits.Length(), 100u);
+}
+
+TEST(Bitset, InitCleared_NoSpill) {
+ Bitset<256> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_FALSE(bits[i]);
+ }
+}
+
+TEST(Bitset, InitCleared_Spill) {
+ Bitset<64> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_FALSE(bits[i]);
+ }
+}
+
+TEST(Bitset, ReadWrite_NoSpill) {
+ Bitset<256> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ bits[i] = (i & 0x2) == 0;
+ }
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_EQ(bits[i], (i & 0x2) == 0);
+ }
+}
+
+TEST(Bitset, ReadWrite_Spill) {
+ Bitset<64> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ bits[i] = (i & 0x2) == 0;
+ }
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_EQ(bits[i], (i & 0x2) == 0);
+ }
+}
+
+TEST(Bitset, ShinkGrowAlignedClears_NoSpill) {
+ Bitset<256> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ bits[i] = true;
+ }
+ bits.Resize(64);
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_EQ(bits[i], i < 64u);
+ }
+}
+
+TEST(Bitset, ShinkGrowAlignedClears_Spill) {
+ Bitset<64> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ bits[i] = true;
+ }
+ bits.Resize(64);
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_EQ(bits[i], i < 64u);
+ }
+}
+TEST(Bitset, ShinkGrowMisalignedClears_NoSpill) {
+ Bitset<256> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ bits[i] = true;
+ }
+ bits.Resize(42);
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_EQ(bits[i], i < 42u);
+ }
+}
+
+TEST(Bitset, ShinkGrowMisalignedClears_Spill) {
+ Bitset<64> bits;
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ bits[i] = true;
+ }
+ bits.Resize(42);
+ bits.Resize(256);
+ for (size_t i = 0; i < 256; i++) {
+ EXPECT_EQ(bits[i], i < 42u);
+ }
+}
+
+} // namespace
+} // namespace tint::utils
diff --git a/chromium/third_party/dawn/src/tint/utils/block_allocator.h b/chromium/third_party/dawn/src/tint/utils/block_allocator.h
index f4139409854..91a8a535cf9 100644
--- a/chromium/third_party/dawn/src/tint/utils/block_allocator.h
+++ b/chromium/third_party/dawn/src/tint/utils/block_allocator.h
@@ -24,10 +24,10 @@
namespace tint::utils {
-/// A container and allocator of objects of (or deriving from) the template
-/// type `T`. Objects are allocated by calling Create(), and are owned by the
-/// BlockAllocator. When the BlockAllocator is destructed, all constructed
-/// objects are automatically destructed and freed.
+/// A container and allocator of objects of (or deriving from) the template type `T`.
+/// Objects are allocated by calling Create(), and are owned by the BlockAllocator.
+/// When the BlockAllocator is destructed, all constructed objects are automatically destructed and
+/// freed.
///
/// Objects held by the BlockAllocator can be iterated over using a View.
template <typename T, size_t BLOCK_SIZE = 64 * 1024, size_t BLOCK_ALIGNMENT = 16>
@@ -44,8 +44,7 @@ class BlockAllocator {
/// Block is linked list of memory blocks.
/// Blocks are allocated out of heap memory.
///
- /// Note: We're not using std::aligned_storage here as this warns / errors
- /// on MSVC.
+ /// Note: We're not using std::aligned_storage here as this warns / errors on MSVC.
struct alignas(BLOCK_ALIGNMENT) Block {
uint8_t data[BLOCK_SIZE];
Block* next;
@@ -97,22 +96,22 @@ class BlockAllocator {
size_t idx;
};
- /// View provides begin() and end() methods for looping over the objects
- /// owned by the BlockAllocator.
+ /// View provides begin() and end() methods for looping over the objects owned by the
+ /// BlockAllocator.
template <bool IS_CONST>
class TView {
public:
/// @returns an iterator to the beginning of the view
TIterator<IS_CONST> begin() const {
- return TIterator<IS_CONST>{allocator_->pointers_.root, 0};
+ return TIterator<IS_CONST>{allocator_->data.pointers.root, 0};
}
/// @returns an iterator to the end of the view
TIterator<IS_CONST> end() const {
- return allocator_->pointers_.current_index >= Pointers::kMax
+ return allocator_->data.pointers.current_index >= Pointers::kMax
? TIterator<IS_CONST>(nullptr, 0)
- : TIterator<IS_CONST>(allocator_->pointers_.current,
- allocator_->pointers_.current_index);
+ : TIterator<IS_CONST>(allocator_->data.pointers.current,
+ allocator_->data.pointers.current_index);
}
private:
@@ -128,12 +127,12 @@ class BlockAllocator {
/// An immutable iterator type over the objects of the BlockAllocator
using ConstIterator = TIterator<true>;
- /// View provides begin() and end() methods for looping over the objects
- /// owned by the BlockAllocator.
+ /// View provides begin() and end() methods for looping over the objects owned by the
+ /// BlockAllocator.
using View = TView<false>;
- /// ConstView provides begin() and end() methods for looping over the objects
- /// owned by the BlockAllocator.
+ /// ConstView provides begin() and end() methods for looping over the objects owned by the
+ /// BlockAllocator.
using ConstView = TView<true>;
/// Constructor
@@ -141,10 +140,7 @@ class BlockAllocator {
/// Move constructor
/// @param rhs the BlockAllocator to move
- BlockAllocator(BlockAllocator&& rhs) {
- std::swap(block_, rhs.block_);
- std::swap(pointers_, rhs.pointers_);
- }
+ BlockAllocator(BlockAllocator&& rhs) { std::swap(data, rhs.data); }
/// Move assignment operator
/// @param rhs the BlockAllocator to move
@@ -152,8 +148,7 @@ class BlockAllocator {
BlockAllocator& operator=(BlockAllocator&& rhs) {
if (this != &rhs) {
Reset();
- std::swap(block_, rhs.block_);
- std::swap(pointers_, rhs.pointers_);
+ std::swap(data, rhs.data);
}
return *this;
}
@@ -168,8 +163,7 @@ class BlockAllocator {
ConstView Objects() const { return ConstView(this); }
/// Creates a new `TYPE` owned by the BlockAllocator.
- /// When the BlockAllocator is destructed the object will be destructed and
- /// freed.
+ /// When the BlockAllocator is destructed the object will be destructed and freed.
/// @param args the arguments to pass to the type constructor
/// @returns the pointer to the constructed object
template <typename TYPE = T, typename... ARGS>
@@ -183,6 +177,7 @@ class BlockAllocator {
auto* ptr = Allocate<TYPE>();
new (ptr) TYPE(std::forward<ARGS>(args)...);
AddObjectPointer(ptr);
+ data.count++;
return ptr;
}
@@ -192,97 +187,106 @@ class BlockAllocator {
for (auto ptr : Objects()) {
ptr->~T();
}
- auto* block = block_.root;
+ auto* block = data.block.root;
while (block != nullptr) {
auto* next = block->next;
delete block;
block = next;
}
- block_ = {};
- pointers_ = {};
+ data = {};
}
+ /// @returns the total number of allocated objects.
+ size_t Count() const { return data.count; }
+
private:
BlockAllocator(const BlockAllocator&) = delete;
BlockAllocator& operator=(const BlockAllocator&) = delete;
- /// Allocates an instance of TYPE from the current block, or from a newly
- /// allocated block if the current block is full.
+ /// Allocates an instance of TYPE from the current block, or from a newly allocated block if the
+ /// current block is full.
template <typename TYPE>
TYPE* Allocate() {
static_assert(sizeof(TYPE) <= BLOCK_SIZE,
"Cannot construct TYPE with size greater than BLOCK_SIZE");
static_assert(alignof(TYPE) <= BLOCK_ALIGNMENT, "alignof(TYPE) is greater than ALIGNMENT");
- block_.current_offset = utils::RoundUp(alignof(TYPE), block_.current_offset);
- if (block_.current_offset + sizeof(TYPE) > BLOCK_SIZE) {
+ auto& block = data.block;
+
+ block.current_offset = utils::RoundUp(alignof(TYPE), block.current_offset);
+ if (block.current_offset + sizeof(TYPE) > BLOCK_SIZE) {
// Allocate a new block from the heap
- auto* prev_block = block_.current;
- block_.current = new Block;
- if (!block_.current) {
+ auto* prev_block = block.current;
+ block.current = new Block;
+ if (!block.current) {
return nullptr; // out of memory
}
- block_.current->next = nullptr;
- block_.current_offset = 0;
+ block.current->next = nullptr;
+ block.current_offset = 0;
if (prev_block) {
- prev_block->next = block_.current;
+ prev_block->next = block.current;
} else {
- block_.root = block_.current;
+ block.root = block.current;
}
}
- auto* base = &block_.current->data[0];
- auto* ptr = utils::Bitcast<TYPE*>(base + block_.current_offset);
- block_.current_offset += sizeof(TYPE);
+ auto* base = &block.current->data[0];
+ auto* ptr = utils::Bitcast<TYPE*>(base + block.current_offset);
+ block.current_offset += sizeof(TYPE);
return ptr;
}
/// Adds `ptr` to the linked list of objects owned by this BlockAllocator.
- /// Once added, `ptr` will be tracked for destruction when the BlockAllocator
- /// is destructed.
+ /// Once added, `ptr` will be tracked for destruction when the BlockAllocator is destructed.
void AddObjectPointer(T* ptr) {
- if (pointers_.current_index >= Pointers::kMax) {
- auto* prev_pointers = pointers_.current;
- pointers_.current = Allocate<Pointers>();
- if (!pointers_.current) {
+ auto& pointers = data.pointers;
+
+ if (pointers.current_index >= Pointers::kMax) {
+ auto* prev_pointers = pointers.current;
+ pointers.current = Allocate<Pointers>();
+ if (!pointers.current) {
return; // out of memory
}
- pointers_.current->next = nullptr;
- pointers_.current_index = 0;
+ pointers.current->next = nullptr;
+ pointers.current_index = 0;
if (prev_pointers) {
- prev_pointers->next = pointers_.current;
+ prev_pointers->next = pointers.current;
} else {
- pointers_.root = pointers_.current;
+ pointers.root = pointers.current;
}
}
- pointers_.current->ptrs[pointers_.current_index++] = ptr;
+ pointers.current->ptrs[pointers.current_index++] = ptr;
}
struct {
- /// The root block of the block linked list
- Block* root = nullptr;
- /// The current (end) block of the blocked linked list.
- /// New allocations come from this block
- Block* current = nullptr;
- /// The byte offset in #current for the next allocation.
- /// Initialized with BLOCK_SIZE so that the first allocation triggers a
- /// block allocation.
- size_t current_offset = BLOCK_SIZE;
- } block_;
-
- struct {
- /// The root Pointers structure of the pointers linked list
- Pointers* root = nullptr;
- /// The current (end) Pointers structure of the pointers linked list.
- /// AddObjectPointer() adds to this structure.
- Pointers* current = nullptr;
- /// The array index in #current for the next append.
- /// Initialized with Pointers::kMax so that the first append triggers a
- /// allocation of the Pointers structure.
- size_t current_index = Pointers::kMax;
- } pointers_;
+ struct {
+ /// The root block of the block linked list
+ Block* root = nullptr;
+ /// The current (end) block of the blocked linked list.
+ /// New allocations come from this block
+ Block* current = nullptr;
+ /// The byte offset in #current for the next allocation.
+ /// Initialized with BLOCK_SIZE so that the first allocation triggers a block
+ /// allocation.
+ size_t current_offset = BLOCK_SIZE;
+ } block;
+
+ struct {
+ /// The root Pointers structure of the pointers linked list
+ Pointers* root = nullptr;
+ /// The current (end) Pointers structure of the pointers linked list.
+ /// AddObjectPointer() adds to this structure.
+ Pointers* current = nullptr;
+ /// The array index in #current for the next append.
+ /// Initialized with Pointers::kMax so that the first append triggers a allocation of
+ /// the Pointers structure.
+ size_t current_index = Pointers::kMax;
+ } pointers;
+
+ size_t count = 0;
+ } data;
};
} // namespace tint::utils
diff --git a/chromium/third_party/dawn/src/tint/utils/block_allocator_test.cc b/chromium/third_party/dawn/src/tint/utils/block_allocator_test.cc
index 600019c4e9b..16847557c2a 100644
--- a/chromium/third_party/dawn/src/tint/utils/block_allocator_test.cc
+++ b/chromium/third_party/dawn/src/tint/utils/block_allocator_test.cc
@@ -33,6 +33,7 @@ TEST_F(BlockAllocatorTest, Empty) {
Allocator allocator;
+ EXPECT_EQ(allocator.Count(), 0u);
for (int* i : allocator.Objects()) {
(void)i;
if ((true)) { // Workaround for "error: loop will run at most once"
@@ -47,6 +48,19 @@ TEST_F(BlockAllocatorTest, Empty) {
}
}
+TEST_F(BlockAllocatorTest, Count) {
+ using Allocator = BlockAllocator<int>;
+
+ for (size_t n : {0u, 1u, 10u, 16u, 20u, 32u, 50u, 64u, 100u, 256u, 300u, 512u, 500u, 512u}) {
+ Allocator allocator;
+ EXPECT_EQ(allocator.Count(), 0u);
+ for (size_t i = 0; i < n; i++) {
+ allocator.Create(123);
+ }
+ EXPECT_EQ(allocator.Count(), n);
+ }
+}
+
TEST_F(BlockAllocatorTest, ObjectLifetime) {
using Allocator = BlockAllocator<LifetimeCounter>;
@@ -67,7 +81,7 @@ TEST_F(BlockAllocatorTest, ObjectLifetime) {
TEST_F(BlockAllocatorTest, MoveConstruct) {
using Allocator = BlockAllocator<LifetimeCounter>;
- for (size_t n : {0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
+ for (size_t n : {0u, 1u, 10u, 16u, 20u, 32u, 50u, 64u, 100u, 256u, 300u, 512u, 500u, 512u}) {
size_t count = 0;
{
Allocator allocator_a;
@@ -75,9 +89,11 @@ TEST_F(BlockAllocatorTest, MoveConstruct) {
allocator_a.Create(&count);
}
EXPECT_EQ(count, n);
+ EXPECT_EQ(allocator_a.Count(), n);
Allocator allocator_b{std::move(allocator_a)};
EXPECT_EQ(count, n);
+ EXPECT_EQ(allocator_b.Count(), n);
}
EXPECT_EQ(count, 0u);
@@ -87,7 +103,7 @@ TEST_F(BlockAllocatorTest, MoveConstruct) {
TEST_F(BlockAllocatorTest, MoveAssign) {
using Allocator = BlockAllocator<LifetimeCounter>;
- for (size_t n : {0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
+ for (size_t n : {0u, 1u, 10u, 16u, 20u, 32u, 50u, 64u, 100u, 256u, 300u, 512u, 500u, 512u}) {
size_t count_a = 0;
size_t count_b = 0;
@@ -97,16 +113,19 @@ TEST_F(BlockAllocatorTest, MoveAssign) {
allocator_a.Create(&count_a);
}
EXPECT_EQ(count_a, n);
+ EXPECT_EQ(allocator_a.Count(), n);
Allocator allocator_b;
for (size_t i = 0; i < n; i++) {
allocator_b.Create(&count_b);
}
EXPECT_EQ(count_b, n);
+ EXPECT_EQ(allocator_b.Count(), n);
allocator_b = std::move(allocator_a);
EXPECT_EQ(count_a, n);
EXPECT_EQ(count_b, 0u);
+ EXPECT_EQ(allocator_b.Count(), n);
}
EXPECT_EQ(count_a, 0u);
diff --git a/chromium/third_party/dawn/src/tint/utils/compiler_macros.h b/chromium/third_party/dawn/src/tint/utils/compiler_macros.h
index 34965c672af..b3cca3cb113 100644
--- a/chromium/third_party/dawn/src/tint/utils/compiler_macros.h
+++ b/chromium/third_party/dawn/src/tint/utils/compiler_macros.h
@@ -25,7 +25,11 @@
////////////////////////////////////////////////////////////////////////////////
#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW __pragma(warning(disable : 4756))
#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED /* currently no-op */
+#define TINT_DISABLE_WARNING_NEWLINE_EOF /* currently no-op */
+#define TINT_DISABLE_WARNING_OLD_STYLE_CAST /* currently no-op */
+#define TINT_DISABLE_WARNING_SIGN_CONVERSION /* currently no-op */
#define TINT_DISABLE_WARNING_UNREACHABLE_CODE __pragma(warning(disable : 4702))
+#define TINT_DISABLE_WARNING_WEAK_VTABLES /* currently no-op */
// clang-format off
#define TINT_BEGIN_DISABLE_WARNING(name) \
@@ -42,7 +46,12 @@
////////////////////////////////////////////////////////////////////////////////
#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW /* currently no-op */
#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED /* currently no-op */
+#define TINT_DISABLE_WARNING_NEWLINE_EOF _Pragma("clang diagnostic ignored \"-Wnewline-eof\"")
+#define TINT_DISABLE_WARNING_OLD_STYLE_CAST _Pragma("clang diagnostic ignored \"-Wold-style-cast\"")
+#define TINT_DISABLE_WARNING_SIGN_CONVERSION \
+ _Pragma("clang diagnostic ignored \"-Wsign-conversion\"")
#define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
+#define TINT_DISABLE_WARNING_WEAK_VTABLES _Pragma("clang diagnostic ignored \"-Wweak-vtables\"")
// clang-format off
#define TINT_BEGIN_DISABLE_WARNING(name) \
@@ -60,7 +69,11 @@
#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW /* currently no-op */
#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED \
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+#define TINT_DISABLE_WARNING_NEWLINE_EOF /* currently no-op */
+#define TINT_DISABLE_WARNING_OLD_STYLE_CAST /* currently no-op */
+#define TINT_DISABLE_WARNING_SIGN_CONVERSION /* currently no-op */
#define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
+#define TINT_DISABLE_WARNING_WEAK_VTABLES /* currently no-op */
// clang-format off
#define TINT_BEGIN_DISABLE_WARNING(name) \
diff --git a/chromium/third_party/dawn/src/tint/utils/hash.h b/chromium/third_party/dawn/src/tint/utils/hash.h
index 3deb14bcc43..d1fac116b60 100644
--- a/chromium/third_party/dawn/src/tint/utils/hash.h
+++ b/chromium/third_party/dawn/src/tint/utils/hash.h
@@ -22,6 +22,8 @@
#include <utility>
#include <vector>
+#include "src/tint/utils/vector.h"
+
namespace tint::utils {
namespace detail {
@@ -67,6 +69,15 @@ void HashCombine(size_t* hash, const std::vector<T>& vector) {
}
/// HashCombine "hashes" together an existing hash and hashable values.
+template <typename T, size_t N>
+void HashCombine(size_t* hash, const utils::Vector<T, N>& list) {
+ HashCombine(hash, list.Length());
+ for (auto& el : list) {
+ HashCombine(hash, el);
+ }
+}
+
+/// HashCombine "hashes" together an existing hash and hashable values.
template <typename... TYPES>
void HashCombine(size_t* hash, const std::tuple<TYPES...>& tuple) {
HashCombine(hash, sizeof...(TYPES));
diff --git a/chromium/third_party/dawn/src/tint/utils/hash_test.cc b/chromium/third_party/dawn/src/tint/utils/hash_test.cc
index cb74df95c71..6ce68206303 100644
--- a/chromium/third_party/dawn/src/tint/utils/hash_test.cc
+++ b/chromium/third_party/dawn/src/tint/utils/hash_test.cc
@@ -19,6 +19,7 @@
#include <unordered_map>
#include "gtest/gtest.h"
+#include "src/tint/utils/vector.h"
namespace tint::utils {
namespace {
@@ -35,13 +36,22 @@ TEST(HashTests, Basic) {
EXPECT_NE(Hash(std::string("hello")), Hash(std::string("world")));
}
-TEST(HashTests, Vector) {
+TEST(HashTests, StdVector) {
EXPECT_EQ(Hash(std::vector<int>({})), Hash(std::vector<int>({})));
EXPECT_EQ(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3})));
EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 4})));
EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3, 4})));
}
+TEST(HashTests, TintVector) {
+ EXPECT_EQ(Hash(Vector<int, 0>({})), Hash(Vector<int, 0>({})));
+ EXPECT_EQ(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3})));
+ EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 4})));
+ EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3, 4})));
+ EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 4>({1, 2, 3})));
+ EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 2>({1, 2, 3})));
+}
+
TEST(HashTests, Tuple) {
EXPECT_EQ(Hash(std::make_tuple(1)), Hash(std::make_tuple(1)));
EXPECT_EQ(Hash(std::make_tuple(1, 2, 3)), Hash(std::make_tuple(1, 2, 3)));
diff --git a/chromium/third_party/dawn/src/tint/utils/hashmap.h b/chromium/third_party/dawn/src/tint/utils/hashmap.h
new file mode 100644
index 00000000000..81bebf2410e
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/hashmap.h
@@ -0,0 +1,305 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_UTILS_HASHMAP_H_
+#define SRC_TINT_UTILS_HASHMAP_H_
+
+#include <functional>
+#include <optional>
+#include <utility>
+
+#include "src/tint/utils/hashset.h"
+
+namespace tint::utils {
+
+/// An unordered map that uses a robin-hood hashing algorithm.
+///
+/// Hashmap internally wraps a Hashset for providing a store for key-value pairs.
+///
+/// @see Hashset
+template <typename K,
+ typename V,
+ size_t N,
+ typename HASH = std::hash<K>,
+ typename EQUAL = std::equal_to<K>>
+class Hashmap {
+ /// LazyCreator is a transient structure used to late-build the Entry::value, when inserted into
+ /// the underlying Hashset.
+ ///
+ /// LazyCreator holds a #key, and a #create function used to build the final Entry::value.
+ /// The #create function must be of the signature `V()`.
+ ///
+ /// LazyCreator can be compared to Entry and hashed, allowing them to be passed to
+ /// Hashset::Insert(). If the set does not contain an existing entry with #key,
+ /// Hashset::Insert() will construct a new Entry passing the rvalue LazyCreator as the
+ /// constructor argument, which in turn calls the #create function to generate the entry value.
+ ///
+ /// @see Entry
+ /// @see Hasher
+ /// @see Equality
+ template <typename CREATE>
+ struct LazyCreator {
+ /// The key of the entry to insert into the map
+ const K& key;
+ /// The value creation function
+ CREATE create;
+ };
+
+ /// Entry holds a key and value pair, and is used as the element type of the underlying Hashset.
+ /// Entries are compared and hashed using only the #key.
+ /// @see Hasher
+ /// @see Equality
+ struct Entry {
+ /// Constructor from a key and value pair
+ Entry(K k, V v) : key(std::move(k)), value(std::move(v)) {}
+
+ /// Copy-constructor.
+ Entry(const Entry&) = default;
+
+ /// Move-constructor.
+ Entry(Entry&&) = default;
+
+ /// Constructor from a LazyCreator.
+ /// The constructor invokes the LazyCreator::create function to build the #value.
+ /// @see LazyCreator
+ template <typename CREATE>
+ Entry(const LazyCreator<CREATE>& creator) // NOLINT(runtime/explicit)
+ : key(creator.key), value(creator.create()) {}
+
+ /// Assignment operator from a LazyCreator.
+ /// The assignment invokes the LazyCreator::create function to build the #value.
+ /// @see LazyCreator
+ template <typename CREATE>
+ Entry& operator=(LazyCreator<CREATE>&& creator) {
+ key = std::move(creator.key);
+ value = creator.create();
+ return *this;
+ }
+
+ /// Copy-assignment operator
+ Entry& operator=(const Entry&) = default;
+
+ /// Move-assignment operator
+ Entry& operator=(Entry&&) = default;
+
+ K key; /// The map entry key
+ V value; /// The map entry value
+ };
+
+ /// Hash provider for the underlying Hashset.
+ /// Provides hash functions for an Entry, K or LazyCreator.
+ /// The hash functions only consider the key of an entry.
+ struct Hasher {
+ /// Calculates a hash from an Entry
+ size_t operator()(const Entry& entry) const { return HASH()(entry.key); }
+ /// Calculates a hash from a K
+ size_t operator()(const K& key) const { return HASH()(key); }
+ /// Calculates a hash from a LazyCreator
+ template <typename CREATE>
+ size_t operator()(const LazyCreator<CREATE>& lc) const {
+ return HASH()(lc.key);
+ }
+ };
+
+ /// Equality provider for the underlying Hashset.
+ /// Provides equality functions for an Entry, K or LazyCreator to an Entry.
+ /// The equality functions only consider the key for equality.
+ struct Equality {
+ /// Compares an Entry to an Entry for equality.
+ bool operator()(const Entry& a, const Entry& b) const { return EQUAL()(a.key, b.key); }
+ /// Compares a K to an Entry for equality.
+ bool operator()(const K& a, const Entry& b) const { return EQUAL()(a, b.key); }
+ /// Compares a LazyCreator to an Entry for equality.
+ template <typename CREATE>
+ bool operator()(const LazyCreator<CREATE>& lc, const Entry& b) const {
+ return EQUAL()(lc.key, b.key);
+ }
+ };
+
+ /// The underlying set
+ using Set = Hashset<Entry, N, Hasher, Equality>;
+
+ public:
+ /// A Key and Value const-reference pair.
+ struct KeyValue {
+ /// key of a map entry
+ const K& key;
+ /// value of a map entry
+ const V& value;
+
+ /// Equality operator
+ /// @param other the other KeyValue
+ /// @returns true if the key and value of this KeyValue are equal to other's.
+ bool operator==(const KeyValue& other) const {
+ return key == other.key && value == other.value;
+ }
+ };
+
+ /// STL-style alias to KeyValue.
+ /// Used by gmock for the `ElementsAre` checks.
+ using value_type = KeyValue;
+
+ /// Iterator for the map
+ class Iterator {
+ public:
+ /// @returns the key of the entry pointed to by this iterator
+ const K& Key() const { return it->key; }
+
+ /// @returns the value of the entry pointed to by this iterator
+ const V& Value() const { return it->value; }
+
+ /// Increments the iterator
+ /// @returns this iterator
+ Iterator& operator++() {
+ ++it;
+ return *this;
+ }
+
+ /// Equality operator
+ /// @param other the other iterator to compare this iterator to
+ /// @returns true if this iterator is equal to other
+ bool operator==(const Iterator& other) const { return it == other.it; }
+
+ /// Inequality operator
+ /// @param other the other iterator to compare this iterator to
+ /// @returns true if this iterator is not equal to other
+ bool operator!=(const Iterator& other) const { return it != other.it; }
+
+ /// @returns a pair of key and value for the entry pointed to by this iterator
+ KeyValue operator*() const { return {Key(), Value()}; }
+
+ private:
+ /// Friend class
+ friend class Hashmap;
+
+ /// Underlying iterator type
+ using SetIterator = typename Set::Iterator;
+
+ explicit Iterator(SetIterator i) : it(i) {}
+
+ SetIterator it;
+ };
+
+ /// Removes all entries from the map.
+ void Clear() { set_.Clear(); }
+
+ /// Adds the key-value pair to the map, if the map does not already contain an entry with a key
+ /// equal to `key`.
+ /// @param key the entry's key to add to the map
+ /// @param value the entry's value to add to the map
+ /// @returns true if the entry was added to the map, false if there was already an entry in the
+ /// map with a key equal to `key`.
+ template <typename KEY, typename VALUE>
+ bool Add(KEY&& key, VALUE&& value) {
+ return set_.Add(Entry{std::forward<KEY>(key), std::forward<VALUE>(value)});
+ }
+
+ /// Adds the key-value pair to the map, replacing any entry with a key equal to `key`.
+ /// @param key the entry's key to add to the map
+ /// @param value the entry's value to add to the map
+ template <typename KEY, typename VALUE>
+ void Replace(KEY&& key, VALUE&& value) {
+ set_.Replace(Entry{std::forward<KEY>(key), std::forward<VALUE>(value)});
+ }
+
+ /// Searches for an entry with the given key value.
+ /// @param key the entry's key value to search for.
+ /// @returns the value of the entry with the given key, or no value if the entry was not found.
+ std::optional<V> Get(const K& key) {
+ if (auto* entry = set_.Find(key)) {
+ return entry->value;
+ }
+ return std::nullopt;
+ }
+
+ /// Searches for an entry with the given key value, adding and returning the result of
+ /// calling `create` if the entry was not found.
+ /// @param key the entry's key value to search for.
+ /// @param create the create function to call if the map does not contain the key.
+ /// @returns the value of the entry.
+ template <typename CREATE>
+ V& GetOrCreate(const K& key, CREATE&& create) {
+ LazyCreator<CREATE> lc{key, std::forward<CREATE>(create)};
+ auto res = set_.Add(std::move(lc));
+ return res.entry->value;
+ }
+
+ /// Searches for an entry with the given key value, adding and returning a newly created
+ /// zero-initialized value if the entry was not found.
+ /// @param key the entry's key value to search for.
+ /// @returns the value of the entry.
+ V& GetOrZero(const K& key) {
+ auto zero = [] { return V{}; };
+ LazyCreator<decltype(zero)> lc{key, zero};
+ auto res = set_.Add(std::move(lc));
+ return res.entry->value;
+ }
+
+ /// Searches for an entry with the given key value.
+ /// @param key the entry's key value to search for.
+ /// @returns the a pointer to the value of the entry with the given key, or nullptr if the entry
+ /// was not found.
+ /// @warning the pointer must not be used after the map is mutated
+ V* Find(const K& key) {
+ if (auto* entry = set_.Find(key)) {
+ return &entry->value;
+ }
+ return nullptr;
+ }
+
+ /// Searches for an entry with the given key value.
+ /// @param key the entry's key value to search for.
+ /// @returns the a pointer to the value of the entry with the given key, or nullptr if the entry
+ /// was not found.
+ /// @warning the pointer must not be used after the map is mutated
+ const V* Find(const K& key) const {
+ if (auto* entry = set_.Find(key)) {
+ return &entry->value;
+ }
+ return nullptr;
+ }
+
+ /// Removes an entry from the set with a key equal to `key`.
+ /// @param key the entry key value to remove.
+ /// @returns true if an entry was removed.
+ bool Remove(const K& key) { return set_.Remove(key); }
+
+ /// Checks whether an entry exists in the map with a key equal to `key`.
+ /// @param key the entry key value to search for.
+ /// @returns true if the map contains an entry with the given key.
+ bool Contains(const K& key) const { return set_.Contains(key); }
+
+ /// Pre-allocates memory so that the map can hold at least `capacity` entries.
+ /// @param capacity the new capacity of the map.
+ void Reserve(size_t capacity) { set_.Reserve(capacity); }
+
+ /// @returns the number of entries in the map.
+ size_t Count() const { return set_.Count(); }
+
+ /// @returns true if the map contains no entries.
+ bool IsEmpty() const { return set_.IsEmpty(); }
+
+ /// @returns an iterator to the start of the map
+ Iterator begin() const { return Iterator{set_.begin()}; }
+
+ /// @returns an iterator to the end of the map
+ Iterator end() const { return Iterator{set_.end()}; }
+
+ private:
+ Set set_;
+};
+
+} // namespace tint::utils
+
+#endif // SRC_TINT_UTILS_HASHMAP_H_
diff --git a/chromium/third_party/dawn/src/tint/utils/hashmap_test.cc b/chromium/third_party/dawn/src/tint/utils/hashmap_test.cc
new file mode 100644
index 00000000000..45e929b4c00
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/hashmap_test.cc
@@ -0,0 +1,179 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/hashmap.h"
+
+#include <array>
+#include <random>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+
+#include "gmock/gmock.h"
+
+namespace tint::utils {
+namespace {
+
+constexpr std::array kPrimes{
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
+ 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131,
+ 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
+ 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311,
+ 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
+};
+
+TEST(Hashmap, Empty) {
+ Hashmap<std::string, int, 8> map;
+ EXPECT_EQ(map.Count(), 0u);
+}
+
+TEST(Hashmap, AddRemove) {
+ Hashmap<std::string, std::string, 8> map;
+ EXPECT_TRUE(map.Add("hello", "world"));
+ EXPECT_EQ(map.Get("hello"), "world");
+ EXPECT_EQ(map.Count(), 1u);
+ EXPECT_TRUE(map.Contains("hello"));
+ EXPECT_FALSE(map.Contains("world"));
+ EXPECT_FALSE(map.Add("hello", "cat"));
+ EXPECT_EQ(map.Count(), 1u);
+ EXPECT_TRUE(map.Remove("hello"));
+ EXPECT_EQ(map.Count(), 0u);
+ EXPECT_FALSE(map.Contains("hello"));
+ EXPECT_FALSE(map.Contains("world"));
+}
+
+TEST(Hashmap, ReplaceRemove) {
+ Hashmap<std::string, std::string, 8> map;
+ map.Replace("hello", "world");
+ EXPECT_EQ(map.Get("hello"), "world");
+ EXPECT_EQ(map.Count(), 1u);
+ EXPECT_TRUE(map.Contains("hello"));
+ EXPECT_FALSE(map.Contains("world"));
+ map.Replace("hello", "cat");
+ EXPECT_EQ(map.Get("hello"), "cat");
+ EXPECT_EQ(map.Count(), 1u);
+ EXPECT_TRUE(map.Remove("hello"));
+ EXPECT_EQ(map.Count(), 0u);
+ EXPECT_FALSE(map.Contains("hello"));
+ EXPECT_FALSE(map.Contains("world"));
+}
+
+TEST(Hashmap, Iterator) {
+ using Map = Hashmap<int, std::string, 8>;
+ using KV = typename Map::KeyValue;
+ Map map;
+ map.Add(1, "one");
+ map.Add(4, "four");
+ map.Add(3, "three");
+ map.Add(2, "two");
+ EXPECT_THAT(map, testing::UnorderedElementsAre(KV{1, "one"}, KV{2, "two"}, KV{3, "three"},
+ KV{4, "four"}));
+}
+
+TEST(Hashmap, AddMany) {
+ Hashmap<int, std::string, 8> map;
+ for (size_t i = 0; i < kPrimes.size(); i++) {
+ int prime = kPrimes[i];
+ ASSERT_TRUE(map.Add(prime, std::to_string(prime))) << "i: " << i;
+ ASSERT_FALSE(map.Add(prime, std::to_string(prime))) << "i: " << i;
+ ASSERT_EQ(map.Count(), i + 1);
+ }
+ ASSERT_EQ(map.Count(), kPrimes.size());
+ for (int prime : kPrimes) {
+ ASSERT_TRUE(map.Contains(prime)) << prime;
+ ASSERT_EQ(map.Get(prime), std::to_string(prime)) << prime;
+ }
+}
+
+TEST(Hashmap, GetOrCreate) {
+ Hashmap<int, std::string, 8> map;
+ EXPECT_EQ(map.GetOrCreate(0, [&] { return "zero"; }), "zero");
+ EXPECT_EQ(map.Count(), 1u);
+ EXPECT_EQ(map.Get(0), "zero");
+
+ bool create_called = false;
+ EXPECT_EQ(map.GetOrCreate(0,
+ [&] {
+ create_called = true;
+ return "oh noes";
+ }),
+ "zero");
+ EXPECT_FALSE(create_called);
+ EXPECT_EQ(map.Count(), 1u);
+ EXPECT_EQ(map.Get(0), "zero");
+
+ EXPECT_EQ(map.GetOrCreate(1, [&] { return "one"; }), "one");
+ EXPECT_EQ(map.Count(), 2u);
+ EXPECT_EQ(map.Get(1), "one");
+}
+
+TEST(Hashmap, Soak) {
+ std::mt19937 rnd;
+ std::unordered_map<std::string, std::string> reference;
+ Hashmap<std::string, std::string, 8> map;
+ for (size_t i = 0; i < 1000000; i++) {
+ std::string key = std::to_string(rnd() & 64);
+ std::string value = "V" + key;
+ switch (rnd() % 7) {
+ case 0: { // Add
+ auto expected = reference.emplace(key, value).second;
+ EXPECT_EQ(map.Add(key, value), expected) << "i:" << i;
+ EXPECT_EQ(map.Get(key), value) << "i:" << i;
+ EXPECT_TRUE(map.Contains(key)) << "i:" << i;
+ break;
+ }
+ case 1: { // Replace
+ reference[key] = value;
+ map.Replace(key, value);
+ EXPECT_EQ(map.Get(key), value) << "i:" << i;
+ EXPECT_TRUE(map.Contains(key)) << "i:" << i;
+ break;
+ }
+ case 2: { // Remove
+ auto expected = reference.erase(key) != 0;
+ EXPECT_EQ(map.Remove(key), expected) << "i:" << i;
+ EXPECT_FALSE(map.Get(key).has_value()) << "i:" << i;
+ EXPECT_FALSE(map.Contains(key)) << "i:" << i;
+ break;
+ }
+ case 3: { // Contains
+ auto expected = reference.count(key) != 0;
+ EXPECT_EQ(map.Contains(key), expected) << "i:" << i;
+ break;
+ }
+ case 4: { // Get
+ if (reference.count(key) != 0) {
+ auto expected = reference[key];
+ EXPECT_EQ(map.Get(key), expected) << "i:" << i;
+ } else {
+ EXPECT_FALSE(map.Get(key).has_value()) << "i:" << i;
+ }
+ break;
+ }
+ case 5: { // Copy / Move
+ Hashmap<std::string, std::string, 8> tmp(map);
+ map = std::move(tmp);
+ break;
+ }
+ case 6: { // Clear
+ reference.clear();
+ map.Clear();
+ break;
+ }
+ }
+ }
+}
+
+} // namespace
+} // namespace tint::utils
diff --git a/chromium/third_party/dawn/src/tint/utils/hashset.h b/chromium/third_party/dawn/src/tint/utils/hashset.h
new file mode 100644
index 00000000000..f88a304bf96
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/hashset.h
@@ -0,0 +1,508 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_UTILS_HASHSET_H_
+#define SRC_TINT_UTILS_HASHSET_H_
+
+#include <stddef.h>
+#include <algorithm>
+#include <functional>
+#include <optional>
+#include <tuple>
+#include <utility>
+
+#include "src/tint/debug.h"
+#include "src/tint/utils/vector.h"
+
+namespace tint::utils {
+
+/// Action taken by Hashset::Insert()
+enum class AddAction {
+ /// Insert() added a new entry to the Hashset
+ kAdded,
+ /// Insert() replaced an existing entry in the Hashset
+ kReplaced,
+ /// Insert() found an existing entry, which was not replaced.
+ kKeptExisting,
+};
+
+/// An unordered set that uses a robin-hood hashing algorithm.
+/// @see the fantastic tutorial: https://programming.guide/robin-hood-hashing.html
+template <typename T, size_t N, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
+class Hashset {
+ /// A slot is a single entry in the underlying vector.
+ /// A slot can either be empty or filled with a value. If the slot is empty, #hash and #distance
+ /// will be zero.
+ struct Slot {
+ template <typename V>
+ bool Equals(size_t value_hash, const V& val) const {
+ return value_hash == hash && EQUAL()(val, value.value());
+ }
+
+ /// The slot value. If this does not contain a value, then the slot is vacant.
+ std::optional<T> value;
+ /// The precomputed hash of value.
+ size_t hash = 0;
+ size_t distance = 0;
+ };
+
+ /// The target length of the underlying vector length in relation to the number of entries in
+ /// the set, expressed as a percentage. For example a value of `150` would mean there would be
+ /// at least 50% more slots than the number of set entries.
+ static constexpr size_t kRehashFactor = 150;
+
+ /// @returns the target slot vector size to hold `n` set entries.
+ static constexpr size_t NumSlots(size_t count) { return (count * kRehashFactor) / 100; }
+
+ /// The fixed-size slot vector length, based on N and kRehashFactor.
+ static constexpr size_t kNumFixedSlots = NumSlots(N);
+
+ /// The minimum number of slots for the set.
+ static constexpr size_t kMinSlots = std::max<size_t>(kNumFixedSlots, 4);
+
+ public:
+ /// Iterator for entries in the set
+ class Iterator {
+ public:
+ /// @returns the value pointed to by this iterator
+ const T* operator->() const { return &current->value.value(); }
+
+ /// Increments the iterator
+ /// @returns this iterator
+ Iterator& operator++() {
+ if (current == end) {
+ return *this;
+ }
+ current++;
+ SkipToNextValue();
+ return *this;
+ }
+
+ /// Equality operator
+ /// @param other the other iterator to compare this iterator to
+ /// @returns true if this iterator is equal to other
+ bool operator==(const Iterator& other) const { return current == other.current; }
+
+ /// Inequality operator
+ /// @param other the other iterator to compare this iterator to
+ /// @returns true if this iterator is not equal to other
+ bool operator!=(const Iterator& other) const { return current != other.current; }
+
+ /// @returns a reference to the value at the iterator
+ const T& operator*() const { return current->value.value(); }
+
+ private:
+ /// Friend class
+ friend class Hashset;
+
+ Iterator(const Slot* c, const Slot* e) : current(c), end(e) { SkipToNextValue(); }
+
+ /// Moves the iterator forward, stopping at the next slot that is not empty.
+ void SkipToNextValue() {
+ while (current != end && !current->value.has_value()) {
+ current++;
+ }
+ }
+
+ const Slot* current; /// The slot the iterator is pointing to
+ const Slot* end; /// One past the last slot in the set
+ };
+
+ /// Type of `T`.
+ using value_type = T;
+
+ /// Constructor
+ Hashset() { slots_.Resize(kMinSlots); }
+
+ /// Copy constructor
+ /// @param other the other Hashset to copy
+ Hashset(const Hashset& other) = default;
+
+ /// Move constructor
+ /// @param other the other Hashset to move
+ Hashset(Hashset&& other) = default;
+
+ /// Destructor
+ ~Hashset() { Clear(); }
+
+ /// Copy-assignment operator
+ /// @param other the other Hashset to copy
+ /// @returns this so calls can be chained
+ Hashset& operator=(const Hashset& other) = default;
+
+ /// Move-assignment operator
+ /// @param other the other Hashset to move
+ /// @returns this so calls can be chained
+ Hashset& operator=(Hashset&& other) = default;
+
+ /// Removes all entries from the set.
+ void Clear() {
+ slots_.Clear(); // Destructs all entries
+ slots_.Resize(kMinSlots);
+ count_ = 0;
+ }
+
+ /// Result of Add()
+ struct AddResult {
+ /// Whether the insert replaced or added a new entry to the set.
+ AddAction action = AddAction::kAdded;
+ /// A pointer to the inserted entry.
+ /// @warning do not modify this pointer in a way that would cause the equality or hash of
+ /// the entry to change. Doing this will corrupt the Hashset.
+ T* entry = nullptr;
+
+ /// @returns true if the entry was added to the set, or an existing entry was replaced.
+ operator bool() const { return action != AddAction::kKeptExisting; }
+ };
+
+ /// Adds a value to the set, if the set does not already contain an entry equal to `value`.
+ /// @param value the value to add to the set.
+ /// @returns A AddResult describing the result of the add
+ /// @warning do not modify the inserted entry in a way that would cause the equality of hash of
+ /// the entry to change. Doing this will corrupt the Hashset.
+ template <typename V>
+ AddResult Add(V&& value) {
+ return Put<PutMode::kAdd>(std::forward<V>(value));
+ }
+
+ /// Adds a value to the set, replacing any entry equal to `value`.
+ /// @param value the value to add to the set.
+ /// @returns A AddResult describing the result of the replace
+ template <typename V>
+ AddResult Replace(V&& value) {
+ return Put<PutMode::kReplace>(std::forward<V>(value));
+ }
+
+ /// Removes an entry from the set.
+ /// @param value the value to remove from the set.
+ /// @returns true if an entry was removed.
+ template <typename V>
+ bool Remove(const V& value) {
+ const auto [found, start] = IndexOf(value);
+ if (!found) {
+ return false;
+ }
+
+ // Shuffle the entries backwards until we either find a free slot, or a slot that has zero
+ // distance.
+ Slot* prev = nullptr;
+ Scan(start, [&](size_t, size_t index) {
+ auto& slot = slots_[index];
+ if (prev) {
+ // note: `distance == 0` also includes empty slots.
+ if (slot.distance == 0) {
+ // Clear the previous slot, and stop shuffling.
+ *prev = {};
+ return Action::kStop;
+ } else {
+ // Shuffle the slot backwards.
+ prev->value = std::move(slot.value);
+ prev->hash = slot.hash;
+ prev->distance = slot.distance - 1;
+ }
+ }
+ prev = &slot;
+ return Action::kContinue;
+ });
+
+ // Entry was removed.
+ count_--;
+
+ return true;
+ }
+
+ /// @param value the value to search for.
+ /// @returns the value of the entry that is equal to `value`, or no value if the entry was not
+ /// found.
+ template <typename V>
+ std::optional<T> Get(const V& value) const {
+ if (const auto [found, index] = IndexOf(value); found) {
+ return slots_[index].value.value();
+ }
+ return std::nullopt;
+ }
+
+ /// @param value the value to search for.
+ /// @returns a pointer to the entry that is equal to the given value, or nullptr if the set does
+ /// not contain the given value.
+ template <typename V>
+ const T* Find(const V& value) const {
+ const auto [found, index] = IndexOf(value);
+ return found ? &slots_[index].value.value() : nullptr;
+ }
+
+ /// @param value the value to search for.
+ /// @returns a pointer to the entry that is equal to the given value, or nullptr if the set does
+ /// not contain the given value.
+ /// @warning do not modify the inserted entry in a way that would cause the equality of hash of
+ /// the entry to change. Doing this will corrupt the Hashset.
+ template <typename V>
+ T* Find(const V& value) {
+ const auto [found, index] = IndexOf(value);
+ return found ? &slots_[index].value.value() : nullptr;
+ }
+
+ /// Checks whether an entry exists in the set
+ /// @param value the value to search for.
+ /// @returns true if the set contains an entry with the given value.
+ template <typename V>
+ bool Contains(const V& value) const {
+ const auto [found, _] = IndexOf(value);
+ return found;
+ }
+
+ /// Pre-allocates memory so that the set can hold at least `capacity` entries.
+ /// @param capacity the new capacity of the set.
+ void Reserve(size_t capacity) {
+ // Calculate the number of slots required to hold `capacity` entries.
+ const size_t num_slots = std::max(NumSlots(capacity), kMinSlots);
+ if (slots_.Length() >= num_slots) {
+ // Already have enough slots.
+ return;
+ }
+
+ // Move all the values out of the set and into a vector.
+ Vector<T, N> values;
+ values.Reserve(count_);
+ for (auto& slot : slots_) {
+ if (slot.value.has_value()) {
+ values.Push(std::move(slot.value.value()));
+ }
+ }
+
+ // Clear the set, grow the number of slots.
+ Clear();
+ slots_.Resize(num_slots);
+
+ // As the number of slots has grown, the slot indices will have changed from before, so
+ // re-add all the values back into the set.
+ for (auto& value : values) {
+ Add(std::move(value));
+ }
+ }
+
+ /// @returns the number of entries in the set.
+ size_t Count() const { return count_; }
+
+ /// @returns true if the set contains no entries.
+ bool IsEmpty() const { return count_ == 0; }
+
+ /// @returns an iterator to the start of the set.
+ Iterator begin() const { return Iterator{slots_.begin(), slots_.end()}; }
+
+ /// @returns an iterator to the end of the set.
+ Iterator end() const { return Iterator{slots_.end(), slots_.end()}; }
+
+ /// A debug function for checking that the set is in good health.
+ /// Asserts if the set is corrupted.
+ void ValidateIntegrity() const {
+ size_t num_alive = 0;
+ for (size_t slot_idx = 0; slot_idx < slots_.Length(); slot_idx++) {
+ const auto& slot = slots_[slot_idx];
+ if (slot.value.has_value()) {
+ num_alive++;
+ auto const [index, hash] = Hash(slot.value.value());
+ TINT_ASSERT(Utils, hash == slot.hash);
+ TINT_ASSERT(Utils, slot_idx == Wrap(index + slot.distance));
+ }
+ }
+ TINT_ASSERT(Utils, num_alive == count_);
+ }
+
+ private:
+ /// The behaviour of Put() when an entry already exists with the given key.
+ enum class PutMode {
+ /// Do not replace existing entries with the new value.
+ kAdd,
+ /// Replace existing entries with the new value.
+ kReplace,
+ };
+ /// The common implementation for Add() and Replace()
+ /// @param value the value to add to the set.
+ /// @returns A AddResult describing the result of the insertion
+ template <PutMode MODE, typename V>
+ AddResult Put(V&& value) {
+ // Ensure the set can fit a new entry
+ if (ShouldRehash(count_ + 1)) {
+ Reserve((count_ + 1) * 2);
+ }
+
+ const auto hash = Hash(value);
+
+ AddResult result{};
+ Scan(hash.scan_start, [&](size_t distance, size_t index) {
+ auto& slot = slots_[index];
+ if (!slot.value.has_value()) {
+ // Found an empty slot.
+ // Place value directly into the slot, and we're done.
+ slot.value.emplace(std::forward<V>(value));
+ slot.hash = hash.value;
+ slot.distance = distance;
+ count_++;
+ result = AddResult{AddAction::kAdded, &slot.value.value()};
+ return Action::kStop;
+ }
+
+ // Slot has an entry
+
+ if (slot.Equals(hash.value, value)) {
+ // Slot is equal to value. Replace or preserve?
+ if constexpr (MODE == PutMode::kReplace) {
+ slot.value = std::forward<V>(value);
+ result = AddResult{AddAction::kReplaced, &slot.value.value()};
+ } else {
+ result = AddResult{AddAction::kKeptExisting, &slot.value.value()};
+ }
+ return Action::kStop;
+ }
+
+ if (slot.distance < distance) {
+ // Existing slot has a closer distance than the value we're attempting to insert.
+ // Steal from the rich!
+ // Move the current slot to a temporary (evicted), and put the value into the slot.
+ Slot evicted{std::forward<V>(value), hash.value, distance};
+ std::swap(evicted, slot);
+
+ // Find a new home for the evicted slot.
+ evicted.distance++; // We've already swapped at index.
+ InsertShuffle(Wrap(index + 1), std::move(evicted));
+
+ count_++;
+ result = AddResult{AddAction::kAdded, &slot.value.value()};
+
+ return Action::kStop;
+ }
+ return Action::kContinue;
+ });
+
+ return result;
+ }
+
+ /// Return type of the Scan() callback.
+ enum class Action {
+ /// Continue scanning for a slot
+ kContinue,
+ /// Immediately stop scanning for a slot
+ kStop,
+ };
+
+ /// Sequentially visits each of the slots starting with the slot with the index `start`, calling
+ /// the callback function `f` for each slot until `f` returns Action::kStop.
+ /// `f` must be a function with the signature `Action(size_t distance, size_t index)`.
+ /// `f` must return Action::kStop within one whole cycle of the slots.
+ template <typename F>
+ void Scan(size_t start, F&& f) const {
+ size_t index = start;
+ for (size_t distance = 0; distance < slots_.Length(); distance++) {
+ if (f(distance, index) == Action::kStop) {
+ return;
+ }
+ index = Wrap(index + 1);
+ }
+ tint::diag::List diags;
+ TINT_ICE(Utils, diags) << "Hashset::Scan() looped entire set without finding a slot";
+ }
+
+ /// HashResult is the return value of Hash()
+ struct HashResult {
+ /// The target (zero-distance) slot index for the value.
+ size_t scan_start;
+ /// The calculated hash of the value.
+ size_t value;
+ };
+
+ /// @returns a tuple holding the target slot index for the given value, and the hash of the
+ /// value, respectively.
+ template <typename V>
+ HashResult Hash(const V& value) const {
+ size_t hash = HASH()(value);
+ size_t index = Wrap(hash);
+ return {index, hash};
+ }
+
+ /// Looks for the value in the set.
+ /// @returns a tuple holding a boolean representing whether the value was found in the set, and
+ /// if found, the index of the slot that holds the value.
+ template <typename V>
+ std::tuple<bool, size_t> IndexOf(const V& value) const {
+ const auto hash = Hash(value);
+
+ bool found = false;
+ size_t idx = 0;
+
+ Scan(hash.scan_start, [&](size_t distance, size_t index) {
+ auto& slot = slots_[index];
+ if (!slot.value.has_value()) {
+ return Action::kStop;
+ }
+ if (slot.Equals(hash.value, value)) {
+ found = true;
+ idx = index;
+ return Action::kStop;
+ }
+ if (slot.distance < distance) {
+ // If the slot distance is less than the current probe distance, then the slot must
+ // be for entry that has an index that comes after value. In this situation, we know
+ // that the set does not contain the value, as it would have been found before this
+ // slot. The "Lookup" section of https://programming.guide/robin-hood-hashing.html
+ // suggests that the condition should inverted, but this is wrong.
+ return Action::kStop;
+ }
+ return Action::kContinue;
+ });
+
+ return {found, idx};
+ }
+
+ /// Shuffles slots for an insertion that has been placed one slot before `start`.
+ /// @param evicted the slot content that was evicted for the insertion.
+ void InsertShuffle(size_t start, Slot evicted) {
+ Scan(start, [&](size_t, size_t index) {
+ auto& slot = slots_[index];
+
+ if (!slot.value.has_value()) {
+ // Empty slot found for evicted.
+ slot = std::move(evicted);
+ return Action::kStop; // We're done.
+ }
+
+ if (slot.distance < evicted.distance) {
+ // Occupied slot has shorter distance to evicted.
+ // Swap slot and evicted.
+ std::swap(slot, evicted);
+ }
+
+ // evicted moves further from the target slot...
+ evicted.distance++;
+
+ return Action::kContinue;
+ });
+ }
+
+ /// @returns true if the set should grow the slot vector, and rehash the items.
+ bool ShouldRehash(size_t count) const { return NumSlots(count) > slots_.Length(); }
+
+ /// Wrap returns the index value modulo the number of slots.
+ size_t Wrap(size_t index) const { return index % slots_.Length(); }
+
+ /// The vector of slots. The vector length is equal to its capacity.
+ Vector<Slot, kNumFixedSlots> slots_;
+
+ /// The number of entries in the set.
+ size_t count_ = 0;
+};
+
+} // namespace tint::utils
+
+#endif // SRC_TINT_UTILS_HASHSET_H_
diff --git a/chromium/third_party/dawn/src/tint/utils/hashset_test.cc b/chromium/third_party/dawn/src/tint/utils/hashset_test.cc
new file mode 100644
index 00000000000..4213b32490c
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/hashset_test.cc
@@ -0,0 +1,142 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/hashset.h"
+
+#include <array>
+#include <random>
+#include <string>
+#include <tuple>
+#include <unordered_set>
+
+#include "gmock/gmock.h"
+
+namespace tint::utils {
+namespace {
+
+constexpr std::array kPrimes{
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
+ 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131,
+ 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
+ 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311,
+ 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
+};
+
+TEST(Hashset, Empty) {
+ Hashset<std::string, 8> set;
+ EXPECT_EQ(set.Count(), 0u);
+}
+
+TEST(Hashset, AddRemove) {
+ Hashset<std::string, 8> set;
+ EXPECT_TRUE(set.Add("hello"));
+ EXPECT_EQ(set.Count(), 1u);
+ EXPECT_TRUE(set.Contains("hello"));
+ EXPECT_FALSE(set.Contains("world"));
+ EXPECT_FALSE(set.Add("hello"));
+ EXPECT_EQ(set.Count(), 1u);
+ EXPECT_TRUE(set.Remove("hello"));
+ EXPECT_EQ(set.Count(), 0u);
+ EXPECT_FALSE(set.Contains("hello"));
+ EXPECT_FALSE(set.Contains("world"));
+}
+
+TEST(Hashset, AddMany) {
+ Hashset<int, 8> set;
+ for (size_t i = 0; i < kPrimes.size(); i++) {
+ int prime = kPrimes[i];
+ ASSERT_TRUE(set.Add(prime)) << "i: " << i;
+ ASSERT_FALSE(set.Add(prime)) << "i: " << i;
+ ASSERT_EQ(set.Count(), i + 1);
+ set.ValidateIntegrity();
+ }
+ ASSERT_EQ(set.Count(), kPrimes.size());
+ for (int prime : kPrimes) {
+ ASSERT_TRUE(set.Contains(prime)) << prime;
+ }
+}
+
+TEST(Hashset, Iterator) {
+ Hashset<std::string, 8> set;
+ set.Add("one");
+ set.Add("four");
+ set.Add("three");
+ set.Add("two");
+ EXPECT_THAT(set, testing::UnorderedElementsAre("one", "two", "three", "four"));
+}
+
+TEST(Hashset, Soak) {
+ std::mt19937 rnd;
+ std::unordered_set<std::string> reference;
+ Hashset<std::string, 8> set;
+ for (size_t i = 0; i < 1000000; i++) {
+ std::string value = std::to_string(rnd() & 0x100);
+ switch (rnd() % 8) {
+ case 0: { // Add
+ auto expected = reference.emplace(value).second;
+ ASSERT_EQ(set.Add(value), expected) << "i: " << i;
+ ASSERT_TRUE(set.Contains(value)) << "i: " << i;
+ break;
+ }
+ case 1: { // Replace
+ reference.emplace(value);
+ set.Replace(value);
+ ASSERT_TRUE(set.Contains(value)) << "i: " << i;
+ break;
+ }
+ case 2: { // Remove
+ auto expected = reference.erase(value) != 0;
+ ASSERT_EQ(set.Remove(value), expected) << "i: " << i;
+ ASSERT_FALSE(set.Contains(value)) << "i: " << i;
+ break;
+ }
+ case 3: { // Contains
+ auto expected = reference.count(value) != 0;
+ ASSERT_EQ(set.Contains(value), expected) << "i: " << i;
+ break;
+ }
+ case 4: { // Get
+ if (reference.count(value) != 0) {
+ ASSERT_TRUE(set.Get(value).has_value()) << "i: " << i;
+ ASSERT_EQ(set.Get(value), value) << "i: " << i;
+ } else {
+ ASSERT_FALSE(set.Get(value).has_value()) << "i: " << i;
+ }
+ break;
+ }
+ case 5: { // Find
+ if (reference.count(value) != 0) {
+ ASSERT_EQ(*set.Find(value), value) << "i: " << i;
+ } else {
+ ASSERT_EQ(set.Find(value), nullptr) << "i: " << i;
+ }
+ break;
+ }
+ case 6: { // Copy / Move
+ Hashset<std::string, 8> tmp(set);
+ set = std::move(tmp);
+ break;
+ }
+ case 7: { // Clear
+ reference.clear();
+ set.Clear();
+ break;
+ }
+ }
+ set.ValidateIntegrity();
+ }
+}
+
+} // namespace
+} // namespace tint::utils
diff --git a/chromium/third_party/dawn/src/tint/utils/io/command_posix.cc b/chromium/third_party/dawn/src/tint/utils/io/command_posix.cc
index 23ee5115fdd..b3371e76134 100644
--- a/chromium/third_party/dawn/src/tint/utils/io/command_posix.cc
+++ b/chromium/third_party/dawn/src/tint/utils/io/command_posix.cc
@@ -164,7 +164,7 @@ Command::Output Command::Exec(std::initializer_list<std::string> arguments) cons
// run the target command.
//
// The parent process is responsible for feeding any input to the stdin_pipe
- // and collectting output from the std[out,err]_pipes.
+ // and collecting output from the std[out,err]_pipes.
int child_id = fork();
if (child_id < 0) {
@@ -251,7 +251,9 @@ Command::Output Command::Exec(std::initializer_list<std::string> arguments) cons
std::vector<const char*> args;
args.emplace_back(path_.c_str());
for (auto& arg : arguments) {
- args.emplace_back(arg.c_str());
+ if (!arg.empty()) {
+ args.emplace_back(arg.c_str());
+ }
}
args.emplace_back(nullptr);
auto res = execv(path_.c_str(), const_cast<char* const*>(args.data()));
diff --git a/chromium/third_party/dawn/src/tint/utils/io/command_windows.cc b/chromium/third_party/dawn/src/tint/utils/io/command_windows.cc
index f953a857760..8c94e254f4a 100644
--- a/chromium/third_party/dawn/src/tint/utils/io/command_windows.cc
+++ b/chromium/third_party/dawn/src/tint/utils/io/command_windows.cc
@@ -16,9 +16,12 @@
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
+#include <dbghelp.h>
#include <sstream>
#include <string>
+#include "src/tint/utils/defer.h"
+
namespace tint::utils {
namespace {
@@ -97,9 +100,34 @@ class Pipe {
Handle write;
};
+/// Queries whether the file at the given path is an executable or DLL.
bool ExecutableExists(const std::string& path) {
- DWORD type = 0;
- return GetBinaryTypeA(path.c_str(), &type);
+ auto file = Handle(CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_READONLY, NULL));
+ if (!file) {
+ return false;
+ }
+
+ auto map = Handle(CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL));
+ if (map == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ void* addr_header = MapViewOfFileEx(map, FILE_MAP_READ, 0, 0, 0, NULL);
+
+ // Dynamically obtain the address of, and call ImageNtHeader. This is done to avoid tint.exe
+ // needing to statically link Dbghelp.lib.
+ static auto* dbg_help = LoadLibraryA("Dbghelp.dll"); // Leaks, but who cares?
+ if (dbg_help) {
+ if (FARPROC proc = GetProcAddress(dbg_help, "ImageNtHeader")) {
+ using ImageNtHeaderPtr = decltype(&ImageNtHeader);
+ auto* image_nt_header = reinterpret_cast<ImageNtHeaderPtr>(proc)(addr_header);
+ return image_nt_header != nullptr;
+ }
+ }
+
+ // Couldn't call ImageNtHeader, assume it is executable
+ return false;
}
std::string FindExecutable(const std::string& name) {
@@ -172,7 +200,9 @@ Command::Output Command::Exec(std::initializer_list<std::string> arguments) cons
std::stringstream args;
args << path_;
for (auto& arg : arguments) {
- args << " " << arg;
+ if (!arg.empty()) {
+ args << " " << arg;
+ }
}
PROCESS_INFORMATION pi{};
@@ -187,7 +217,8 @@ Command::Output Command::Exec(std::initializer_list<std::string> arguments) cons
&si, // Pointer to STARTUPINFO structure
&pi)) { // Pointer to PROCESS_INFORMATION structure
Output out;
- out.err = "Command::Exec() CreateProcess() failed";
+ out.err = "Command::Exec() CreateProcess('" + args.str() + "') failed";
+ out.error_code = 1;
return out;
}
diff --git a/chromium/third_party/dawn/src/tint/utils/result.h b/chromium/third_party/dawn/src/tint/utils/result.h
index b2a69d56fc4..b535f4fcdb3 100644
--- a/chromium/third_party/dawn/src/tint/utils/result.h
+++ b/chromium/third_party/dawn/src/tint/utils/result.h
@@ -16,8 +16,7 @@
#define SRC_TINT_UTILS_RESULT_H_
#include <ostream>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <variant> // NOLINT(build/include_order)
+#include <variant>
namespace tint::utils {
@@ -33,7 +32,7 @@ static constexpr const FailureType Failure;
/// information about the failure, except that something failed. Must not be the same type
/// as SUCCESS_TYPE.
template <typename SUCCESS_TYPE, typename FAILURE_TYPE = FailureType>
-struct Result {
+struct [[nodiscard]] Result {
static_assert(!std::is_same_v<SUCCESS_TYPE, FAILURE_TYPE>,
"Result must not have the same type for SUCCESS_TYPE and FAILURE_TYPE");
diff --git a/chromium/third_party/dawn/src/tint/utils/string.h b/chromium/third_party/dawn/src/tint/utils/string.h
index a11e44e4210..f10e2581d31 100644
--- a/chromium/third_party/dawn/src/tint/utils/string.h
+++ b/chromium/third_party/dawn/src/tint/utils/string.h
@@ -15,6 +15,7 @@
#ifndef SRC_TINT_UTILS_STRING_H_
#define SRC_TINT_UTILS_STRING_H_
+#include <sstream>
#include <string>
namespace tint::utils {
@@ -34,6 +35,15 @@ inline std::string ReplaceAll(std::string str,
return str;
}
+/// @param value the value to be printed as a string
+/// @returns value printed as a string via the std::ostream `<<` operator
+template <typename T>
+std::string ToString(const T& value) {
+ std::stringstream s;
+ s << value;
+ return s.str();
+}
+
} // namespace tint::utils
#endif // SRC_TINT_UTILS_STRING_H_
diff --git a/chromium/third_party/dawn/src/tint/utils/string_test.cc b/chromium/third_party/dawn/src/tint/utils/string_test.cc
index 0d3e14fc401..d1cab51e95e 100644
--- a/chromium/third_party/dawn/src/tint/utils/string_test.cc
+++ b/chromium/third_party/dawn/src/tint/utils/string_test.cc
@@ -32,5 +32,10 @@ TEST(StringTest, ReplaceAll) {
ASSERT_EQ("aabxybbxybcc", ReplaceAll("aabbcc", "b", "bxyb"));
}
+TEST(StringTest, ToString) {
+ ASSERT_EQ("123", ToString(123));
+ ASSERT_EQ("hello", ToString("hello"));
+}
+
} // namespace
} // namespace tint::utils
diff --git a/chromium/third_party/dawn/src/tint/utils/transform.h b/chromium/third_party/dawn/src/tint/utils/transform.h
index ff925303ca9..2faca462c10 100644
--- a/chromium/third_party/dawn/src/tint/utils/transform.h
+++ b/chromium/third_party/dawn/src/tint/utils/transform.h
@@ -21,6 +21,7 @@
#include <vector>
#include "src/tint/traits.h"
+#include "src/tint/utils/vector.h"
namespace tint::utils {
@@ -52,6 +53,72 @@ auto Transform(const std::vector<IN>& in, TRANSFORMER&& transform)
return result;
}
+/// Transform performs an element-wise transformation of a vector.
+/// @param in the input vector.
+/// @param transform the transformation function with signature: `OUT(IN)`
+/// @returns a new vector with each element of the source vector transformed by `transform`.
+template <typename IN, size_t N, typename TRANSFORMER>
+auto Transform(const Vector<IN, N>& in, TRANSFORMER&& transform)
+ -> Vector<decltype(transform(in[0])), N> {
+ const auto count = in.Length();
+ Vector<decltype(transform(in[0])), N> result;
+ result.Reserve(count);
+ for (size_t i = 0; i < count; ++i) {
+ result.Push(transform(in[i]));
+ }
+ return result;
+}
+
+/// Transform performs an element-wise transformation of a vector.
+/// @param in the input vector.
+/// @param transform the transformation function with signature: `OUT(IN, size_t)`
+/// @returns a new vector with each element of the source vector transformed by `transform`.
+template <typename IN, size_t N, typename TRANSFORMER>
+auto Transform(const Vector<IN, N>& in, TRANSFORMER&& transform)
+ -> Vector<decltype(transform(in[0], 1u)), N> {
+ const auto count = in.Length();
+ Vector<decltype(transform(in[0], 1u)), N> result;
+ result.Reserve(count);
+ for (size_t i = 0; i < count; ++i) {
+ result.Push(transform(in[i], i));
+ }
+ return result;
+}
+
+/// Transform performs an element-wise transformation of a vector reference.
+/// @param in the input vector.
+/// @param transform the transformation function with signature: `OUT(IN)`
+/// @tparam N the small-array size of the returned Vector
+/// @returns a new vector with each element of the source vector transformed by `transform`.
+template <size_t N, typename IN, typename TRANSFORMER>
+auto Transform(const VectorRef<IN>& in, TRANSFORMER&& transform)
+ -> Vector<decltype(transform(in[0])), N> {
+ const auto count = in.Length();
+ Vector<decltype(transform(in[0])), N> result;
+ result.Reserve(count);
+ for (size_t i = 0; i < count; ++i) {
+ result.Push(transform(in[i]));
+ }
+ return result;
+}
+
+/// Transform performs an element-wise transformation of a vector reference.
+/// @param in the input vector.
+/// @param transform the transformation function with signature: `OUT(IN, size_t)`
+/// @tparam N the small-array size of the returned Vector
+/// @returns a new vector with each element of the source vector transformed by `transform`.
+template <size_t N, typename IN, typename TRANSFORMER>
+auto Transform(const VectorRef<IN>& in, TRANSFORMER&& transform)
+ -> Vector<decltype(transform(in[0], 1u)), N> {
+ const auto count = in.Length();
+ Vector<decltype(transform(in[0], 1u)), N> result;
+ result.Reserve(count);
+ for (size_t i = 0; i < count; ++i) {
+ result.Push(transform(in[i], i));
+ }
+ return result;
+}
+
/// TransformN performs an element-wise transformation of a vector, transforming and returning at
/// most `n` elements.
/// @param in the input vector.
diff --git a/chromium/third_party/dawn/src/tint/utils/transform_test.cc b/chromium/third_party/dawn/src/tint/utils/transform_test.cc
index 89c07568c9e..71b3f0cb510 100644
--- a/chromium/third_party/dawn/src/tint/utils/transform_test.cc
+++ b/chromium/third_party/dawn/src/tint/utils/transform_test.cc
@@ -26,7 +26,7 @@
namespace tint::utils {
namespace {
-TEST(TransformTest, Empty) {
+TEST(TransformTest, StdVectorEmpty) {
const std::vector<int> empty{};
{
auto transformed = Transform(empty, [](int) -> int {
@@ -46,21 +46,21 @@ TEST(TransformTest, Empty) {
}
}
-TEST(TransformTest, Identity) {
+TEST(TransformTest, StdVectorIdentity) {
const std::vector<int> input{1, 2, 3, 4};
auto transformed = Transform(input, [](int i) { return i; });
CHECK_ELEMENT_TYPE(transformed, int);
EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
}
-TEST(TransformTest, IdentityWithIndex) {
+TEST(TransformTest, StdVectorIdentityWithIndex) {
const std::vector<int> input{1, 2, 3, 4};
auto transformed = Transform(input, [](int i, size_t) { return i; });
CHECK_ELEMENT_TYPE(transformed, int);
EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
}
-TEST(TransformTest, Index) {
+TEST(TransformTest, StdVectorIndex) {
const std::vector<int> input{10, 20, 30, 40};
{
auto transformed = Transform(input, [](int, size_t idx) { return idx; });
@@ -69,7 +69,7 @@ TEST(TransformTest, Index) {
}
}
-TEST(TransformTest, TransformSameType) {
+TEST(TransformTest, TransformStdVectorSameType) {
const std::vector<int> input{1, 2, 3, 4};
{
auto transformed = Transform(input, [](int i) { return i * 10; });
@@ -78,7 +78,7 @@ TEST(TransformTest, TransformSameType) {
}
}
-TEST(TransformTest, TransformDifferentType) {
+TEST(TransformTest, TransformStdVectorDifferentType) {
const std::vector<int> input{1, 2, 3, 4};
{
auto transformed = Transform(input, [](int i) { return std::to_string(i); });
@@ -87,7 +87,7 @@ TEST(TransformTest, TransformDifferentType) {
}
}
-TEST(TransformNTest, Empty) {
+TEST(TransformNTest, StdVectorEmpty) {
const std::vector<int> empty{};
{
auto transformed = TransformN(empty, 4u, [](int) -> int {
@@ -107,7 +107,7 @@ TEST(TransformNTest, Empty) {
}
}
-TEST(TransformNTest, Identity) {
+TEST(TransformNTest, StdVectorIdentity) {
const std::vector<int> input{1, 2, 3, 4};
{
auto transformed = TransformN(input, 0u, [](int) {
@@ -129,7 +129,7 @@ TEST(TransformNTest, Identity) {
}
}
-TEST(TransformNTest, IdentityWithIndex) {
+TEST(TransformNTest, StdVectorIdentityWithIndex) {
const std::vector<int> input{1, 2, 3, 4};
{
auto transformed = TransformN(input, 0u, [](int, size_t) {
@@ -151,7 +151,7 @@ TEST(TransformNTest, IdentityWithIndex) {
}
}
-TEST(TransformNTest, Index) {
+TEST(TransformNTest, StdVectorIndex) {
const std::vector<int> input{10, 20, 30, 40};
{
auto transformed = TransformN(input, 0u, [](int, size_t) {
@@ -173,7 +173,7 @@ TEST(TransformNTest, Index) {
}
}
-TEST(TransformNTest, TransformSameType) {
+TEST(TransformNTest, StdVectorTransformSameType) {
const std::vector<int> input{1, 2, 3, 4};
{
auto transformed = TransformN(input, 0u, [](int, size_t) {
@@ -195,7 +195,7 @@ TEST(TransformNTest, TransformSameType) {
}
}
-TEST(TransformNTest, TransformDifferentType) {
+TEST(TransformNTest, StdVectorTransformDifferentType) {
const std::vector<int> input{1, 2, 3, 4};
{
auto transformed = TransformN(input, 0u, [](int) {
@@ -217,5 +217,133 @@ TEST(TransformNTest, TransformDifferentType) {
}
}
+TEST(TransformTest, TintVectorEmpty) {
+ const Vector<int, 4> empty{};
+ {
+ auto transformed = Transform(empty, [](int) -> int {
+ [] { FAIL() << "Callback should not be called for empty vector"; }();
+ return 0;
+ });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_EQ(transformed.Length(), 0u);
+ }
+ {
+ auto transformed = Transform(empty, [](int, size_t) -> int {
+ [] { FAIL() << "Callback should not be called for empty vector"; }();
+ return 0;
+ });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_EQ(transformed.Length(), 0u);
+ }
+}
+
+TEST(TransformTest, TintVectorIdentity) {
+ const Vector<int, 4> input{1, 2, 3, 4};
+ auto transformed = Transform(input, [](int i) { return i; });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
+}
+
+TEST(TransformTest, TintVectorIdentityWithIndex) {
+ const Vector<int, 4> input{1, 2, 3, 4};
+ auto transformed = Transform(input, [](int i, size_t) { return i; });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
+}
+
+TEST(TransformTest, TintVectorIndex) {
+ const Vector<int, 4> input{10, 20, 30, 40};
+ {
+ auto transformed = Transform(input, [](int, size_t idx) { return idx; });
+ CHECK_ELEMENT_TYPE(transformed, size_t);
+ EXPECT_THAT(transformed, testing::ElementsAre(0u, 1u, 2u, 3u));
+ }
+}
+
+TEST(TransformTest, TransformTintVectorSameType) {
+ const Vector<int, 4> input{1, 2, 3, 4};
+ {
+ auto transformed = Transform(input, [](int i) { return i * 10; });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_THAT(transformed, testing::ElementsAre(10, 20, 30, 40));
+ }
+}
+
+TEST(TransformTest, TransformTintVectorDifferentType) {
+ const Vector<int, 4> input{1, 2, 3, 4};
+ {
+ auto transformed = Transform(input, [](int i) { return std::to_string(i); });
+ CHECK_ELEMENT_TYPE(transformed, std::string);
+ EXPECT_THAT(transformed, testing::ElementsAre("1", "2", "3", "4"));
+ }
+}
+
+TEST(TransformTest, VectorRefEmpty) {
+ Vector<int, 4> empty{};
+ VectorRef<int> ref(empty);
+ {
+ auto transformed = Transform<4>(ref, [](int) -> int {
+ [] { FAIL() << "Callback should not be called for empty vector"; }();
+ return 0;
+ });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_EQ(transformed.Length(), 0u);
+ }
+ {
+ auto transformed = Transform<4>(ref, [](int, size_t) -> int {
+ [] { FAIL() << "Callback should not be called for empty vector"; }();
+ return 0;
+ });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_EQ(transformed.Length(), 0u);
+ }
+}
+
+TEST(TransformTest, VectorRefIdentity) {
+ Vector<int, 4> input{1, 2, 3, 4};
+ VectorRef<int> ref(input);
+ auto transformed = Transform<8>(ref, [](int i) { return i; });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
+}
+
+TEST(TransformTest, VectorRefIdentityWithIndex) {
+ Vector<int, 4> input{1, 2, 3, 4};
+ VectorRef<int> ref(input);
+ auto transformed = Transform<2>(ref, [](int i, size_t) { return i; });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
+}
+
+TEST(TransformTest, VectorRefIndex) {
+ Vector<int, 4> input{10, 20, 30, 40};
+ VectorRef<int> ref(input);
+ {
+ auto transformed = Transform<4>(ref, [](int, size_t idx) { return idx; });
+ CHECK_ELEMENT_TYPE(transformed, size_t);
+ EXPECT_THAT(transformed, testing::ElementsAre(0u, 1u, 2u, 3u));
+ }
+}
+
+TEST(TransformTest, TransformVectorRefSameType) {
+ Vector<int, 4> input{1, 2, 3, 4};
+ VectorRef<int> ref(input);
+ {
+ auto transformed = Transform<4>(ref, [](int i) { return i * 10; });
+ CHECK_ELEMENT_TYPE(transformed, int);
+ EXPECT_THAT(transformed, testing::ElementsAre(10, 20, 30, 40));
+ }
+}
+
+TEST(TransformTest, TransformVectorRefDifferentType) {
+ Vector<int, 4> input{1, 2, 3, 4};
+ VectorRef<int> ref(input);
+ {
+ auto transformed = Transform<4>(ref, [](int i) { return std::to_string(i); });
+ CHECK_ELEMENT_TYPE(transformed, std::string);
+ EXPECT_THAT(transformed, testing::ElementsAre("1", "2", "3", "4"));
+ }
+}
+
} // namespace
} // namespace tint::utils
diff --git a/chromium/third_party/dawn/src/tint/utils/unique_vector.h b/chromium/third_party/dawn/src/tint/utils/unique_vector.h
index 0f3f18d8a15..bda090cea0b 100644
--- a/chromium/third_party/dawn/src/tint/utils/unique_vector.h
+++ b/chromium/third_party/dawn/src/tint/utils/unique_vector.h
@@ -21,17 +21,15 @@
#include <utility>
#include <vector>
+#include "src/tint/utils/hashset.h"
+#include "src/tint/utils/vector.h"
+
namespace tint::utils {
/// UniqueVector is an ordered container that only contains unique items.
/// Attempting to add a duplicate is a no-op.
-template <typename T, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
+template <typename T, size_t N, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
struct UniqueVector {
- /// The iterator returned by begin() and end()
- using ConstIterator = typename std::vector<T>::const_iterator;
- /// The iterator returned by rbegin() and rend()
- using ConstReverseIterator = typename std::vector<T>::const_reverse_iterator;
-
/// Constructor
UniqueVector() = default;
@@ -40,7 +38,7 @@ struct UniqueVector {
/// elements will be removed.
explicit UniqueVector(std::vector<T>&& v) {
for (auto& el : v) {
- add(el);
+ Add(el);
}
}
@@ -48,10 +46,9 @@ struct UniqueVector {
/// already contain the given item.
/// @param item the item to append to the end of the vector
/// @returns true if the item was added, otherwise false.
- bool add(const T& item) {
- if (set.count(item) == 0) {
- vector.emplace_back(item);
- set.emplace(item);
+ bool Add(const T& item) {
+ if (set.Add(item)) {
+ vector.Push(item);
return true;
}
return false;
@@ -59,7 +56,7 @@ struct UniqueVector {
/// @returns true if the vector contains `item`
/// @param item the item
- bool contains(const T& item) const { return set.count(item); }
+ bool Contains(const T& item) const { return set.Contains(item); }
/// @param i the index of the element to retrieve
/// @returns the element at the index `i`
@@ -70,41 +67,50 @@ struct UniqueVector {
const T& operator[](size_t i) const { return vector[i]; }
/// @returns true if the vector is empty
- bool empty() const { return vector.empty(); }
+ bool IsEmpty() const { return vector.IsEmpty(); }
/// @returns the number of items in the vector
- size_t size() const { return vector.size(); }
+ size_t Length() const { return vector.Length(); }
/// @returns the pointer to the first element in the vector, or nullptr if the vector is empty.
- const T* data() const { return vector.empty() ? nullptr : vector.data(); }
+ const T* Data() const { return vector.IsEmpty() ? nullptr : &vector[0]; }
/// @returns an iterator to the beginning of the vector
- ConstIterator begin() const { return vector.begin(); }
+ auto begin() const { return vector.begin(); }
/// @returns an iterator to the end of the vector
- ConstIterator end() const { return vector.end(); }
+ auto end() const { return vector.end(); }
/// @returns an iterator to the beginning of the reversed vector
- ConstReverseIterator rbegin() const { return vector.rbegin(); }
+ auto rbegin() const { return vector.rbegin(); }
/// @returns an iterator to the end of the reversed vector
- ConstReverseIterator rend() const { return vector.rend(); }
+ auto rend() const { return vector.rend(); }
/// @returns a const reference to the internal vector
- operator const std::vector<T>&() const { return vector; }
+ operator const Vector<T, N>&() const { return vector; }
+
+ /// @returns the std::move()'d vector.
+ /// @note The UniqueVector must not be used after calling this method
+ VectorRef<T> Release() { return std::move(vector); }
+
+ /// Pre-allocates `count` elements in the vector and set
+ /// @param count the number of elements to pre-allocate
+ void Reserve(size_t count) {
+ vector.Reserve(count);
+ set.Reserve(count);
+ }
/// Removes the last element from the vector
/// @returns the popped element
- T pop_back() {
- auto el = std::move(vector.back());
- set.erase(el);
- vector.pop_back();
- return el;
+ T Pop() {
+ set.Remove(vector.Back());
+ return vector.Pop();
}
private:
- std::vector<T> vector;
- std::unordered_set<T, HASH, EQUAL> set;
+ Vector<T, N> vector;
+ Hashset<T, N, HASH, EQUAL> set;
};
} // namespace tint::utils
diff --git a/chromium/third_party/dawn/src/tint/utils/unique_vector_test.cc b/chromium/third_party/dawn/src/tint/utils/unique_vector_test.cc
index 035ebf8de72..9b015c2092b 100644
--- a/chromium/third_party/dawn/src/tint/utils/unique_vector_test.cc
+++ b/chromium/third_party/dawn/src/tint/utils/unique_vector_test.cc
@@ -13,6 +13,9 @@
// limitations under the License.
#include "src/tint/utils/unique_vector.h"
+
+#include <vector>
+
#include "src/tint/utils/reverse.h"
#include "gtest/gtest.h"
@@ -21,16 +24,16 @@ namespace tint::utils {
namespace {
TEST(UniqueVectorTest, Empty) {
- UniqueVector<int> unique_vec;
- EXPECT_EQ(unique_vec.size(), 0u);
- EXPECT_EQ(unique_vec.empty(), true);
+ UniqueVector<int, 4> unique_vec;
+ EXPECT_EQ(unique_vec.Length(), 0u);
+ EXPECT_EQ(unique_vec.IsEmpty(), true);
EXPECT_EQ(unique_vec.begin(), unique_vec.end());
}
TEST(UniqueVectorTest, MoveConstructor) {
- UniqueVector<int> unique_vec(std::vector<int>{0, 3, 2, 1, 2});
- EXPECT_EQ(unique_vec.size(), 4u);
- EXPECT_EQ(unique_vec.empty(), false);
+ UniqueVector<int, 4> unique_vec(std::vector<int>{0, 3, 2, 1, 2});
+ EXPECT_EQ(unique_vec.Length(), 4u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
EXPECT_EQ(unique_vec[1], 3);
EXPECT_EQ(unique_vec[2], 2);
@@ -38,12 +41,12 @@ TEST(UniqueVectorTest, MoveConstructor) {
}
TEST(UniqueVectorTest, AddUnique) {
- UniqueVector<int> unique_vec;
- unique_vec.add(0);
- unique_vec.add(1);
- unique_vec.add(2);
- EXPECT_EQ(unique_vec.size(), 3u);
- EXPECT_EQ(unique_vec.empty(), false);
+ UniqueVector<int, 4> unique_vec;
+ unique_vec.Add(0);
+ unique_vec.Add(1);
+ unique_vec.Add(2);
+ EXPECT_EQ(unique_vec.Length(), 3u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
int i = 0;
for (auto n : unique_vec) {
EXPECT_EQ(n, i);
@@ -59,15 +62,15 @@ TEST(UniqueVectorTest, AddUnique) {
}
TEST(UniqueVectorTest, AddDuplicates) {
- UniqueVector<int> unique_vec;
- unique_vec.add(0);
- unique_vec.add(0);
- unique_vec.add(0);
- unique_vec.add(1);
- unique_vec.add(1);
- unique_vec.add(2);
- EXPECT_EQ(unique_vec.size(), 3u);
- EXPECT_EQ(unique_vec.empty(), false);
+ UniqueVector<int, 4> unique_vec;
+ unique_vec.Add(0);
+ unique_vec.Add(0);
+ unique_vec.Add(0);
+ unique_vec.Add(1);
+ unique_vec.Add(1);
+ unique_vec.Add(2);
+ EXPECT_EQ(unique_vec.Length(), 3u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
int i = 0;
for (auto n : unique_vec) {
EXPECT_EQ(n, i);
@@ -83,17 +86,17 @@ TEST(UniqueVectorTest, AddDuplicates) {
}
TEST(UniqueVectorTest, AsVector) {
- UniqueVector<int> unique_vec;
- unique_vec.add(0);
- unique_vec.add(0);
- unique_vec.add(0);
- unique_vec.add(1);
- unique_vec.add(1);
- unique_vec.add(2);
-
- const std::vector<int>& vec = unique_vec;
- EXPECT_EQ(vec.size(), 3u);
- EXPECT_EQ(unique_vec.empty(), false);
+ UniqueVector<int, 4> unique_vec;
+ unique_vec.Add(0);
+ unique_vec.Add(0);
+ unique_vec.Add(0);
+ unique_vec.Add(1);
+ unique_vec.Add(1);
+ unique_vec.Add(2);
+
+ const utils::Vector<int, 4>& vec = unique_vec;
+ EXPECT_EQ(vec.Length(), 3u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
int i = 0;
for (auto n : vec) {
EXPECT_EQ(n, i);
@@ -106,46 +109,46 @@ TEST(UniqueVectorTest, AsVector) {
}
TEST(UniqueVectorTest, PopBack) {
- UniqueVector<int> unique_vec;
- unique_vec.add(0);
- unique_vec.add(2);
- unique_vec.add(1);
-
- EXPECT_EQ(unique_vec.pop_back(), 1);
- EXPECT_EQ(unique_vec.size(), 2u);
- EXPECT_EQ(unique_vec.empty(), false);
+ UniqueVector<int, 4> unique_vec;
+ unique_vec.Add(0);
+ unique_vec.Add(2);
+ unique_vec.Add(1);
+
+ EXPECT_EQ(unique_vec.Pop(), 1);
+ EXPECT_EQ(unique_vec.Length(), 2u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
EXPECT_EQ(unique_vec[1], 2);
- EXPECT_EQ(unique_vec.pop_back(), 2);
- EXPECT_EQ(unique_vec.size(), 1u);
- EXPECT_EQ(unique_vec.empty(), false);
+ EXPECT_EQ(unique_vec.Pop(), 2);
+ EXPECT_EQ(unique_vec.Length(), 1u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
- unique_vec.add(1);
+ unique_vec.Add(1);
- EXPECT_EQ(unique_vec.size(), 2u);
- EXPECT_EQ(unique_vec.empty(), false);
+ EXPECT_EQ(unique_vec.Length(), 2u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
EXPECT_EQ(unique_vec[1], 1);
- EXPECT_EQ(unique_vec.pop_back(), 1);
- EXPECT_EQ(unique_vec.size(), 1u);
- EXPECT_EQ(unique_vec.empty(), false);
+ EXPECT_EQ(unique_vec.Pop(), 1);
+ EXPECT_EQ(unique_vec.Length(), 1u);
+ EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
- EXPECT_EQ(unique_vec.pop_back(), 0);
- EXPECT_EQ(unique_vec.size(), 0u);
- EXPECT_EQ(unique_vec.empty(), true);
+ EXPECT_EQ(unique_vec.Pop(), 0);
+ EXPECT_EQ(unique_vec.Length(), 0u);
+ EXPECT_EQ(unique_vec.IsEmpty(), true);
}
TEST(UniqueVectorTest, Data) {
- UniqueVector<int> unique_vec;
- EXPECT_EQ(unique_vec.data(), nullptr);
+ UniqueVector<int, 4> unique_vec;
+ EXPECT_EQ(unique_vec.Data(), nullptr);
- unique_vec.add(42);
- EXPECT_EQ(unique_vec.data(), &unique_vec[0]);
- EXPECT_EQ(*unique_vec.data(), 42);
+ unique_vec.Add(42);
+ EXPECT_EQ(unique_vec.Data(), &unique_vec[0]);
+ EXPECT_EQ(*unique_vec.Data(), 42);
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/utils/vector.h b/chromium/third_party/dawn/src/tint/utils/vector.h
new file mode 100644
index 00000000000..b718840a5ce
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/vector.h
@@ -0,0 +1,826 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_UTILS_VECTOR_H_
+#define SRC_TINT_UTILS_VECTOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <array>
+#include <iterator>
+#include <utility>
+#include <vector>
+
+#include "src/tint/castable.h"
+#include "src/tint/traits.h"
+#include "src/tint/utils/bitcast.h"
+
+namespace tint::utils {
+
+/// Forward declarations
+template <typename>
+class VectorRef;
+template <typename>
+class VectorRef;
+
+} // namespace tint::utils
+
+namespace tint::utils {
+
+/// A type used to indicate an empty array.
+struct EmptyType {};
+
+/// An instance of the EmptyType.
+static constexpr EmptyType Empty;
+
+/// A slice represents a contigious array of elements of type T.
+template <typename T>
+struct Slice {
+ /// The pointer to the first element in the slice
+ T* data = nullptr;
+
+ /// The total number of elements in the slice
+ size_t len = 0;
+
+ /// The total capacity of the backing store for the slice
+ size_t cap = 0;
+
+ /// Index operator
+ /// @param i the element index. Must be less than `len`.
+ /// @returns a reference to the i'th element.
+ T& operator[](size_t i) { return data[i]; }
+
+ /// Index operator
+ /// @param i the element index. Must be less than `len`.
+ /// @returns a reference to the i'th element.
+ const T& operator[](size_t i) const { return data[i]; }
+
+ /// @returns a reference to the first element in the vector
+ T& Front() { return data[0]; }
+
+ /// @returns a reference to the first element in the vector
+ const T& Front() const { return data[0]; }
+
+ /// @returns a reference to the last element in the vector
+ T& Back() { return data[len - 1]; }
+
+ /// @returns a reference to the last element in the vector
+ const T& Back() const { return data[len - 1]; }
+
+ /// @returns a pointer to the first element in the vector
+ T* begin() { return data; }
+
+ /// @returns a pointer to the first element in the vector
+ const T* begin() const { return data; }
+
+ /// @returns a pointer to one past the last element in the vector
+ T* end() { return data + len; }
+
+ /// @returns a pointer to one past the last element in the vector
+ const T* end() const { return data + len; }
+
+ /// @returns a reverse iterator starting with the last element in the vector
+ auto rbegin() { return std::reverse_iterator<T*>(end()); }
+
+ /// @returns a reverse iterator starting with the last element in the vector
+ auto rbegin() const { return std::reverse_iterator<const T*>(end()); }
+
+ /// @returns the end for a reverse iterator
+ auto rend() { return std::reverse_iterator<T*>(begin()); }
+
+ /// @returns the end for a reverse iterator
+ auto rend() const { return std::reverse_iterator<const T*>(begin()); }
+};
+
+namespace detail {
+
+/// Private implementation of tint::utils::CanReinterpretSlice.
+/// Specialized for the case of TO equal to FROM, which is the common case, and avoids inspection of
+/// the base classes, which can be troublesome if the slice is of an incomplete type.
+template <typename TO, typename FROM>
+struct CanReinterpretSlice {
+ /// True if a slice of FROM can be reinterpreted as a slice of TO
+ static constexpr bool value =
+ // Both TO and FROM are pointers
+ (std::is_pointer_v<TO> && std::is_pointer_v<FROM>)&& //
+ // const can only be applied, not removed
+ (std::is_const_v<std::remove_pointer_t<TO>> ||
+ !std::is_const_v<std::remove_pointer_t<FROM>>)&& //
+ // TO and FROM are both Castable
+ IsCastable<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>> && //
+ // FROM is of, or derives from TO
+ traits::IsTypeOrDerived<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>>;
+};
+
+/// Specialization of 'CanReinterpretSlice' for when TO and FROM are equal types.
+template <typename T>
+struct CanReinterpretSlice<T, T> {
+ /// Always `true` as TO and FROM are the same type.
+ static constexpr bool value = true;
+};
+
+} // namespace detail
+
+/// Evaluates whether a `vector<FROM>` and be reinterpreted as a `vector<TO>`.
+/// Vectors can be reinterpreted if both `FROM` and `TO` are pointers to a type that derives from
+/// CastableBase, and the pointee type of `TO` is of the same type as, or is an ancestor of the
+/// pointee type of `FROM`. Vectors of non-`const` Castable pointers can be converted to a vector of
+/// `const` Castable pointers.
+template <typename TO, typename FROM>
+static constexpr bool CanReinterpretSlice = detail::CanReinterpretSlice<TO, FROM>::value;
+
+/// Reinterprets `const Slice<FROM>*` as `const Slice<TO>*`
+/// @param slice a pointer to the slice to reinterpret
+/// @returns the reinterpreted slice
+/// @see CanReinterpretSlice
+template <typename TO, typename FROM>
+const Slice<TO>* ReinterpretSlice(const Slice<FROM>* slice) {
+ static_assert(CanReinterpretSlice<TO, FROM>);
+ return Bitcast<const Slice<TO>*>(slice);
+}
+
+/// Reinterprets `Slice<FROM>*` as `Slice<TO>*`
+/// @param slice a pointer to the slice to reinterpret
+/// @returns the reinterpreted slice
+/// @see CanReinterpretSlice
+template <typename TO, typename FROM>
+Slice<TO>* ReinterpretSlice(Slice<FROM>* slice) {
+ static_assert(CanReinterpretSlice<TO, FROM>);
+ return Bitcast<Slice<TO>*>(slice);
+}
+
+/// Vector is a small-object-optimized, dynamically-sized vector of contigious elements of type T.
+///
+/// Vector will fit `N` elements internally before spilling to heap allocations. If `N` is greater
+/// than zero, the internal elements are stored in a 'small array' held internally by the Vector.
+///
+/// Vectors can be copied or moved.
+///
+/// Copying a vector will either copy to the 'small array' if the number of elements is equal to or
+/// less than N, otherwise elements will be copied into a new heap allocation.
+///
+/// Moving a vector will reassign ownership of the heap-allocation memory, if the source vector
+/// holds its elements in a heap allocation, otherwise a copy will be made as described above.
+///
+/// Vector is optimized for CPU performance over memory efficiency. For example:
+/// * Moving a vector that stores its elements in a heap allocation to another vector will simply
+/// assign the heap allocation, even if the target vector can hold the elements in its 'small
+/// array'. This reduces memory copying, but may incur additional memory usage.
+/// * Resizing, or popping elements from a vector that has spilled to a heap allocation does not
+/// revert back to using the 'small array'. Again, this is to reduce memory copying.
+template <typename T, size_t N>
+class Vector {
+ public:
+ /// Type of `T`.
+ using value_type = T;
+ /// Value of `N`
+ static constexpr size_t static_length = N;
+
+ /// Constructor
+ Vector() = default;
+
+ /// Constructor
+ Vector(EmptyType) {} // NOLINT(runtime/explicit)
+
+ /// Constructor
+ /// @param elements the elements to place into the vector
+ Vector(std::initializer_list<T> elements) {
+ Reserve(elements.size());
+ for (auto& el : elements) {
+ new (&impl_.slice.data[impl_.slice.len++]) T{el};
+ }
+ }
+
+ /// Copy constructor
+ /// @param other the vector to copy
+ Vector(const Vector& other) { Copy(other.impl_.slice); }
+
+ /// Move constructor
+ /// @param other the vector to move
+ Vector(Vector&& other) { MoveOrCopy(VectorRef<T>(std::move(other))); }
+
+ /// Copy constructor (differing N length)
+ /// @param other the vector to copy
+ template <size_t N2>
+ Vector(const Vector<T, N2>& other) {
+ Copy(other.impl_.slice);
+ }
+
+ /// Move constructor (differing N length)
+ /// @param other the vector to move
+ template <size_t N2>
+ Vector(Vector<T, N2>&& other) {
+ MoveOrCopy(VectorRef<T>(std::move(other)));
+ }
+
+ /// Copy constructor with covariance / const conversion
+ /// @param other the vector to copy
+ /// @see CanReinterpretSlice for rules about conversion
+ template <typename U, size_t N2, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
+ Vector(const Vector<U, N2>& other) { // NOLINT(runtime/explicit)
+ Copy(*ReinterpretSlice<T>(&other.impl_.slice));
+ }
+
+ /// Move constructor with covariance / const conversion
+ /// @param other the vector to move
+ /// @see CanReinterpretSlice for rules about conversion
+ template <typename U, size_t N2, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
+ Vector(Vector<U, N2>&& other) { // NOLINT(runtime/explicit)
+ MoveOrCopy(VectorRef<T>(std::move(other)));
+ }
+
+ /// Move constructor from a mutable vector reference
+ /// @param other the vector reference to move
+ explicit Vector(VectorRef<T>&& other) { MoveOrCopy(std::move(other)); }
+
+ /// Copy constructor from an immutable vector reference
+ /// @param other the vector reference to copy
+ explicit Vector(const VectorRef<T>& other) { Copy(other.slice_); }
+
+ /// Destructor
+ ~Vector() { ClearAndFree(); }
+
+ /// Assignment operator
+ /// @param other the vector to copy
+ /// @returns this vector so calls can be chained
+ Vector& operator=(const Vector& other) {
+ if (&other != this) {
+ Copy(other.impl_.slice);
+ }
+ return *this;
+ }
+
+ /// Move operator
+ /// @param other the vector to move
+ /// @returns this vector so calls can be chained
+ Vector& operator=(Vector&& other) {
+ if (&other != this) {
+ MoveOrCopy(VectorRef<T>(std::move(other)));
+ }
+ return *this;
+ }
+
+ /// Assignment operator (differing N length)
+ /// @param other the vector to copy
+ /// @returns this vector so calls can be chained
+ template <size_t N2>
+ Vector& operator=(const Vector<T, N2>& other) {
+ Copy(other.impl_.slice);
+ return *this;
+ }
+
+ /// Move operator (differing N length)
+ /// @param other the vector to copy
+ /// @returns this vector so calls can be chained
+ template <size_t N2>
+ Vector& operator=(Vector<T, N2>&& other) {
+ MoveOrCopy(VectorRef<T>(std::move(other)));
+ return *this;
+ }
+
+ /// Assignment operator (differing N length)
+ /// @param other the vector reference to copy
+ /// @returns this vector so calls can be chained
+ Vector& operator=(const VectorRef<T>& other) {
+ if (&other.slice_ != &impl_.slice) {
+ Copy(other.slice_);
+ }
+ return *this;
+ }
+
+ /// Move operator (differing N length)
+ /// @param other the vector reference to copy
+ /// @returns this vector so calls can be chained
+ Vector& operator=(VectorRef<T>&& other) {
+ if (&other.slice_ != &impl_.slice) {
+ MoveOrCopy(std::move(other));
+ }
+ return *this;
+ }
+
+ /// Index operator
+ /// @param i the element index. Must be less than `len`.
+ /// @returns a reference to the i'th element.
+ T& operator[](size_t i) { return impl_.slice[i]; }
+
+ /// Index operator
+ /// @param i the element index. Must be less than `len`.
+ /// @returns a reference to the i'th element.
+ const T& operator[](size_t i) const { return impl_.slice[i]; }
+
+ /// @return the number of elements in the vector
+ size_t Length() const { return impl_.slice.len; }
+
+ /// @return the number of elements that the vector could hold before a heap allocation needs to
+ /// be made
+ size_t Capacity() const { return impl_.slice.cap; }
+
+ /// Reserves memory to hold at least `new_cap` elements
+ /// @param new_cap the new vector capacity
+ void Reserve(size_t new_cap) {
+ if (new_cap > impl_.slice.cap) {
+ auto* old_data = impl_.slice.data;
+ impl_.Allocate(new_cap);
+ for (size_t i = 0; i < impl_.slice.len; i++) {
+ new (&impl_.slice.data[i]) T(std::move(old_data[i]));
+ old_data[i].~T();
+ }
+ impl_.Free(old_data);
+ }
+ }
+
+ /// Resizes the vector to the given length, expanding capacity if necessary.
+ /// New elements are zero-initialized
+ /// @param new_len the new vector length
+ void Resize(size_t new_len) {
+ Reserve(new_len);
+ for (size_t i = impl_.slice.len; i > new_len; i--) { // Shrink
+ impl_.slice.data[i - 1].~T();
+ }
+ for (size_t i = impl_.slice.len; i < new_len; i++) { // Grow
+ new (&impl_.slice.data[i]) T{};
+ }
+ impl_.slice.len = new_len;
+ }
+
+ /// Resizes the vector to the given length, expanding capacity if necessary.
+ /// @param new_len the new vector length
+ /// @param value the value to copy into the new elements
+ void Resize(size_t new_len, const T& value) {
+ Reserve(new_len);
+ for (size_t i = impl_.slice.len; i > new_len; i--) { // Shrink
+ impl_.slice.data[i - 1].~T();
+ }
+ for (size_t i = impl_.slice.len; i < new_len; i++) { // Grow
+ new (&impl_.slice.data[i]) T{value};
+ }
+ impl_.slice.len = new_len;
+ }
+
+ /// Copies all the elements from `other` to this vector, replacing the content of this vector.
+ /// @param other the
+ template <typename T2, size_t N2>
+ void Copy(const Vector<T2, N2>& other) {
+ Copy(other.impl_.slice);
+ }
+
+ /// Clears all elements from the vector, keeping the capacity the same.
+ void Clear() {
+ for (size_t i = 0; i < impl_.slice.len; i++) {
+ impl_.slice.data[i].~T();
+ }
+ impl_.slice.len = 0;
+ }
+
+ /// Appends a new element to the vector.
+ /// @param el the element to copy to the vector.
+ void Push(const T& el) {
+ if (impl_.slice.len >= impl_.slice.cap) {
+ Grow();
+ }
+ new (&impl_.slice.data[impl_.slice.len++]) T(el);
+ }
+
+ /// Appends a new element to the vector.
+ /// @param el the element to move to the vector.
+ void Push(T&& el) {
+ if (impl_.slice.len >= impl_.slice.cap) {
+ Grow();
+ }
+ new (&impl_.slice.data[impl_.slice.len++]) T(std::move(el));
+ }
+
+ /// Appends a new element to the vector.
+ /// @param args the arguments to pass to the element constructor.
+ template <typename... ARGS>
+ void Emplace(ARGS&&... args) {
+ if (impl_.slice.len >= impl_.slice.cap) {
+ Grow();
+ }
+ new (&impl_.slice.data[impl_.slice.len++]) T{std::forward<ARGS>(args)...};
+ }
+
+ /// Removes and returns the last element from the vector.
+ /// @returns the popped element
+ T Pop() {
+ auto& el = impl_.slice.data[--impl_.slice.len];
+ auto val = std::move(el);
+ el.~T();
+ return val;
+ }
+
+ /// @returns true if the vector is empty.
+ bool IsEmpty() const { return impl_.slice.len == 0; }
+
+ /// @returns a reference to the first element in the vector
+ T& Front() { return impl_.slice.Front(); }
+
+ /// @returns a reference to the first element in the vector
+ const T& Front() const { return impl_.slice.Front(); }
+
+ /// @returns a reference to the last element in the vector
+ T& Back() { return impl_.slice.Back(); }
+
+ /// @returns a reference to the last element in the vector
+ const T& Back() const { return impl_.slice.Back(); }
+
+ /// @returns a pointer to the first element in the vector
+ T* begin() { return impl_.slice.begin(); }
+
+ /// @returns a pointer to the first element in the vector
+ const T* begin() const { return impl_.slice.begin(); }
+
+ /// @returns a pointer to one past the last element in the vector
+ T* end() { return impl_.slice.end(); }
+
+ /// @returns a pointer to one past the last element in the vector
+ const T* end() const { return impl_.slice.end(); }
+
+ /// @returns a reverse iterator starting with the last element in the vector
+ auto rbegin() { return impl_.slice.rbegin(); }
+
+ /// @returns a reverse iterator starting with the last element in the vector
+ auto rbegin() const { return impl_.slice.rbegin(); }
+
+ /// @returns the end for a reverse iterator
+ auto rend() { return impl_.slice.rend(); }
+
+ /// @returns the end for a reverse iterator
+ auto rend() const { return impl_.slice.rend(); }
+
+ /// Equality operator
+ /// @param other the other vector
+ /// @returns true if this vector is the same length as `other`, and all elements are equal.
+ bool operator==(const Vector& other) const {
+ const size_t len = Length();
+ if (len == other.Length()) {
+ for (size_t i = 0; i < len; i++) {
+ if ((*this)[i] != other[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private:
+ /// Friend class (differing specializations of this class)
+ template <typename, size_t>
+ friend class Vector;
+
+ /// Friend class
+ template <typename>
+ friend class VectorRef;
+
+ /// Friend class
+ template <typename>
+ friend class VectorRef;
+
+ /// The slice type used by this vector
+ using Slice = utils::Slice<T>;
+
+ template <typename... Ts>
+ void AppendVariadic(Ts&&... args) {
+ ((new (&impl_.slice.data[impl_.slice.len++]) T(std::forward<Ts>(args))), ...);
+ }
+
+ /// Expands the capacity of the vector
+ void Grow() { Reserve(std::max(impl_.slice.cap, static_cast<size_t>(1)) * 2); }
+
+ /// Moves 'other' to this vector, if possible, otherwise performs a copy.
+ void MoveOrCopy(VectorRef<T>&& other) {
+ if (other.can_move_) {
+ ClearAndFree();
+ impl_.slice = other.slice_;
+ other.slice_ = {};
+ } else {
+ Copy(other.slice_);
+ }
+ }
+
+ /// Copies all the elements from `other` to this vector, replacing the content of this vector.
+ /// @param other the
+ void Copy(const Slice& other) {
+ if (impl_.slice.cap < other.len) {
+ ClearAndFree();
+ impl_.Allocate(other.len);
+ } else {
+ Clear();
+ }
+
+ impl_.slice.len = other.len;
+ for (size_t i = 0; i < impl_.slice.len; i++) {
+ new (&impl_.slice.data[i]) T{other.data[i]};
+ }
+ }
+
+ /// Clears the vector, then frees the slice data.
+ void ClearAndFree() {
+ Clear();
+ impl_.Free(impl_.slice.data);
+ }
+
+ /// True if this vector uses a small array for small object optimization.
+ constexpr static bool HasSmallArray = N > 0;
+
+ /// A structure that has the same size and alignment as T.
+ /// Replacement for std::aligned_storage as this is broken on earlier versions of MSVC.
+ struct alignas(alignof(T)) TStorage {
+ /// @returns the storage reinterpreted as a T*
+ T* Get() { return Bitcast<T*>(&data[0]); }
+ /// @returns the storage reinterpreted as a T*
+ const T* Get() const { return Bitcast<const T*>(&data[0]); }
+ /// Byte array of length sizeof(T)
+ uint8_t data[sizeof(T)];
+ };
+
+ /// The internal structure for the vector with a small array.
+ struct ImplWithSmallArray {
+ std::array<TStorage, N> small_arr;
+ Slice slice = {small_arr[0].Get(), 0, N};
+
+ /// Allocates a new vector of `T` either from #small_arr, or from the heap, then assigns the
+ /// pointer it to #slice.data, and updates #slice.cap.
+ void Allocate(size_t new_cap) {
+ if (new_cap < N) {
+ slice.data = small_arr[0].Get();
+ slice.cap = N;
+ } else {
+ slice.data = Bitcast<T*>(new TStorage[new_cap]);
+ slice.cap = new_cap;
+ }
+ }
+
+ /// Frees `data`, if not nullptr and isn't a pointer to #small_arr
+ void Free(T* data) const {
+ if (data && data != small_arr[0].Get()) {
+ delete[] Bitcast<TStorage*>(data);
+ }
+ }
+
+ /// Indicates whether the slice structure can be std::move()d.
+ /// @returns true if #slice.data does not point to #small_arr
+ bool CanMove() const { return slice.data != small_arr[0].Get(); }
+ };
+
+ /// The internal structure for the vector without a small array.
+ struct ImplWithoutSmallArray {
+ Slice slice = {nullptr, 0, 0};
+
+ /// Allocates a new vector of `T` and assigns it to #slice.data, and updates #slice.cap.
+ void Allocate(size_t new_cap) {
+ slice.data = Bitcast<T*>(new TStorage[new_cap]);
+ slice.cap = new_cap;
+ }
+
+ /// Frees `data`, if not nullptr.
+ void Free(T* data) const {
+ if (data) {
+ delete[] Bitcast<TStorage*>(data);
+ }
+ }
+
+ /// Indicates whether the slice structure can be std::move()d.
+ /// @returns true
+ bool CanMove() const { return true; }
+ };
+
+ /// Either a ImplWithSmallArray or ImplWithoutSmallArray based on N.
+ std::conditional_t<HasSmallArray, ImplWithSmallArray, ImplWithoutSmallArray> impl_;
+};
+
+namespace detail {
+
+/// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments
+/// @tparam IS_CASTABLE true if the types of `Ts` derive from CastableBase
+/// @tparam Ts the vector constructor argument types to infer the vector element type from.
+template <bool IS_CASTABLE, typename... Ts>
+struct VectorCommonType;
+
+/// VectorCommonType specialization for non-castable types.
+template <typename... Ts>
+struct VectorCommonType</*IS_CASTABLE*/ false, Ts...> {
+ /// The common T type to use for the vector
+ using type = std::common_type_t<Ts...>;
+};
+
+/// VectorCommonType specialization for castable types.
+template <typename... Ts>
+struct VectorCommonType</*IS_CASTABLE*/ true, Ts...> {
+ /// The common Castable type (excluding pointer)
+ using common_ty = CastableCommonBase<std::remove_pointer_t<Ts>...>;
+ /// The common T type to use for the vector
+ using type = std::conditional_t<(std::is_const_v<std::remove_pointer_t<Ts>> || ...),
+ const common_ty*,
+ common_ty*>;
+};
+
+} // namespace detail
+
+/// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments
+template <typename... Ts>
+using VectorCommonType =
+ typename detail::VectorCommonType<IsCastable<std::remove_pointer_t<Ts>...>, Ts...>::type;
+
+/// Deduction guide for Vector
+template <typename... Ts>
+Vector(Ts...) -> Vector<VectorCommonType<Ts...>, sizeof...(Ts)>;
+
+/// VectorRef is a weak reference to a Vector, used to pass vectors as parameters, avoiding copies
+/// between the caller and the callee. VectorRef can accept a Vector of any 'N' value, decoupling
+/// the caller's vector internal size from the callee's vector size. A VectorRef tracks the usage of
+/// moves either side of the call. If at the call site, a Vector argument is moved to a VectorRef
+/// parameter, and within the callee, the VectorRef parameter is moved to a Vector, then the Vector
+/// heap allocation will be moved. For example:
+///
+/// ```
+/// void func_a() {
+/// Vector<std::string, 4> vec;
+/// // logic to populate 'vec'.
+/// func_b(std::move(vec)); // Constructs a VectorRef tracking the move here.
+/// }
+///
+/// void func_b(VectorRef<std::string> vec_ref) {
+/// // A move was made when calling func_b, so the vector can be moved instead of copied.
+/// Vector<std::string, 2> vec(std::move(vec_ref));
+/// }
+/// ```
+template <typename T>
+class VectorRef {
+ /// The slice type used by this vector reference
+ using Slice = utils::Slice<T>;
+
+ /// @returns an empty slice.
+ static Slice& EmptySlice() {
+ static Slice empty;
+ return empty;
+ }
+
+ public:
+ /// Constructor - empty reference
+ VectorRef() : slice_(EmptySlice()) {}
+
+ /// Constructor
+ VectorRef(EmptyType) : slice_(EmptySlice()) {} // NOLINT(runtime/explicit)
+
+ /// Constructor from a Vector
+ /// @param vector the vector to create a reference of
+ template <size_t N>
+ VectorRef(Vector<T, N>& vector) // NOLINT(runtime/explicit)
+ : slice_(vector.impl_.slice) {}
+
+ /// Constructor from a const Vector
+ /// @param vector the vector to create a reference of
+ template <size_t N>
+ VectorRef(const Vector<T, N>& vector) // NOLINT(runtime/explicit)
+ : slice_(const_cast<Slice&>(vector.impl_.slice)) {}
+
+ /// Constructor from a moved Vector
+ /// @param vector the vector being moved
+ template <size_t N>
+ VectorRef(Vector<T, N>&& vector) // NOLINT(runtime/explicit)
+ : slice_(vector.impl_.slice), can_move_(vector.impl_.CanMove()) {}
+
+ /// Copy constructor
+ /// @param other the vector reference
+ VectorRef(const VectorRef& other) : slice_(other.slice_) {}
+
+ /// Move constructor
+ /// @param other the vector reference
+ VectorRef(VectorRef&& other) = default;
+
+ /// Copy constructor with covariance / const conversion
+ /// @param other the other vector reference
+ template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
+ VectorRef(const VectorRef<U>& other) // NOLINT(runtime/explicit)
+ : slice_(*ReinterpretSlice<T>(&other.slice_)) {}
+
+ /// Move constructor with covariance / const conversion
+ /// @param other the vector reference
+ template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
+ VectorRef(VectorRef<U>&& other) // NOLINT(runtime/explicit)
+ : slice_(*ReinterpretSlice<T>(&other.slice_)), can_move_(other.can_move_) {}
+
+ /// Constructor from a Vector with covariance / const conversion
+ /// @param vector the vector to create a reference of
+ /// @see CanReinterpretSlice for rules about conversion
+ template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
+ VectorRef(Vector<U, N>& vector) // NOLINT(runtime/explicit)
+ : slice_(*ReinterpretSlice<T>(&vector.impl_.slice)) {}
+
+ /// Constructor from a moved Vector with covariance / const conversion
+ /// @param vector the vector to create a reference of
+ /// @see CanReinterpretSlice for rules about conversion
+ template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
+ VectorRef(Vector<U, N>&& vector) // NOLINT(runtime/explicit)
+ : slice_(*ReinterpretSlice<T>(&vector.impl_.slice)), can_move_(vector.impl_.CanMove()) {}
+
+ /// Index operator
+ /// @param i the element index. Must be less than `len`.
+ /// @returns a reference to the i'th element.
+ const T& operator[](size_t i) const { return slice_[i]; }
+
+ /// @return the number of elements in the vector
+ size_t Length() const { return slice_.len; }
+
+ /// @return the number of elements that the vector could hold before a heap allocation needs to
+ /// be made
+ size_t Capacity() const { return slice_.cap; }
+
+ /// @returns true if the vector is empty.
+ bool IsEmpty() const { return slice_.len == 0; }
+
+ /// @returns a reference to the first element in the vector
+ T& Front() { return slice_.Front(); }
+
+ /// @returns a reference to the first element in the vector
+ const T& Front() const { return slice_.Front(); }
+
+ /// @returns a reference to the last element in the vector
+ T& Back() { return slice_.Back(); }
+
+ /// @returns a reference to the last element in the vector
+ const T& Back() const { return slice_.Back(); }
+
+ /// @returns a pointer to the first element in the vector
+ T* begin() { return slice_.begin(); }
+
+ /// @returns a pointer to the first element in the vector
+ const T* begin() const { return slice_.begin(); }
+
+ /// @returns a pointer to one past the last element in the vector
+ T* end() { return slice_.end(); }
+
+ /// @returns a pointer to one past the last element in the vector
+ const T* end() const { return slice_.end(); }
+
+ /// @returns a reverse iterator starting with the last element in the vector
+ auto rbegin() { return slice_.rbegin(); }
+
+ /// @returns a reverse iterator starting with the last element in the vector
+ auto rbegin() const { return slice_.rbegin(); }
+
+ /// @returns the end for a reverse iterator
+ auto rend() { return slice_.rend(); }
+
+ /// @returns the end for a reverse iterator
+ auto rend() const { return slice_.rend(); }
+
+ private:
+ /// Friend class
+ template <typename, size_t>
+ friend class Vector;
+
+ /// Friend class
+ template <typename>
+ friend class VectorRef;
+
+ /// Friend class
+ template <typename>
+ friend class VectorRef;
+
+ /// The slice of the vector being referenced.
+ Slice& slice_;
+ /// Whether the slice data is passed by r-value reference, and can be moved.
+ bool can_move_ = false;
+};
+
+/// Helper for converting a Vector to a std::vector.
+/// @note This helper exists to help code migration. Avoid if possible.
+template <typename T, size_t N>
+std::vector<T> ToStdVector(const Vector<T, N>& vector) {
+ std::vector<T> out;
+ out.reserve(vector.Length());
+ for (auto& el : vector) {
+ out.emplace_back(el);
+ }
+ return out;
+}
+
+/// Helper for converting a std::vector to a Vector.
+/// @note This helper exists to help code migration. Avoid if possible.
+template <typename T, size_t N = 0>
+Vector<T, N> ToVector(const std::vector<T>& vector) {
+ Vector<T, N> out;
+ out.Reserve(vector.size());
+ for (auto& el : vector) {
+ out.Push(el);
+ }
+ return out;
+}
+
+} // namespace tint::utils
+
+#endif // SRC_TINT_UTILS_VECTOR_H_
diff --git a/chromium/third_party/dawn/src/tint/utils/vector_test.cc b/chromium/third_party/dawn/src/tint/utils/vector_test.cc
new file mode 100644
index 00000000000..b4e9fb52f6e
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/utils/vector_test.cc
@@ -0,0 +1,2069 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/vector.h"
+
+#include <string>
+#include <tuple>
+
+#include "gtest/gtest.h"
+
+#include "src/tint/utils/bitcast.h"
+
+namespace tint::utils {
+namespace {
+
+class C0 : public Castable<C0> {};
+class C1 : public Castable<C1, C0> {};
+class C2a : public Castable<C2a, C1> {};
+class C2b : public Castable<C2b, C1> {};
+
+/// @returns true if the address of el is within the memory of the vector vec.
+template <typename T, size_t N, typename E>
+bool IsInternal(Vector<T, N>& vec, E& el) {
+ auto ptr = Bitcast<uintptr_t>(&el);
+ auto base = Bitcast<uintptr_t>(&vec);
+ return ptr >= base && ptr < base + sizeof(vec);
+}
+
+/// @returns true if all elements of the vector `vec` are held within the memory of `vec`.
+template <typename T, size_t N>
+bool AllInternallyHeld(Vector<T, N>& vec) {
+ for (auto& el : vec) {
+ if (!IsInternal(vec, el)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/// @returns true if all elements of the vector `vec` are held outside the memory of `vec`.
+template <typename T, size_t N>
+bool AllExternallyHeld(Vector<T, N>& vec) {
+ for (auto& el : vec) {
+ if (IsInternal(vec, el)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Static asserts
+////////////////////////////////////////////////////////////////////////////////
+static_assert(std::is_same_v<VectorCommonType<int>, int>);
+static_assert(std::is_same_v<VectorCommonType<int, int>, int>);
+static_assert(std::is_same_v<VectorCommonType<int, float>, float>);
+
+static_assert(std::is_same_v<VectorCommonType<C0*>, C0*>);
+static_assert(std::is_same_v<VectorCommonType<const C0*>, const C0*>);
+
+static_assert(std::is_same_v<VectorCommonType<C0*, C1*>, C0*>);
+static_assert(std::is_same_v<VectorCommonType<const C0*, C1*>, const C0*>);
+static_assert(std::is_same_v<VectorCommonType<C0*, const C1*>, const C0*>);
+static_assert(std::is_same_v<VectorCommonType<const C0*, const C1*>, const C0*>);
+
+static_assert(std::is_same_v<VectorCommonType<C2a*, C2b*>, C1*>);
+static_assert(std::is_same_v<VectorCommonType<const C2a*, C2b*>, const C1*>);
+static_assert(std::is_same_v<VectorCommonType<C2a*, const C2b*>, const C1*>);
+static_assert(std::is_same_v<VectorCommonType<const C2a*, const C2b*>, const C1*>);
+
+static_assert(CanReinterpretSlice<const C0*, C0*>, "apply const");
+static_assert(!CanReinterpretSlice<C0*, const C0*>, "remove const");
+static_assert(CanReinterpretSlice<C0*, C1*>, "up cast");
+static_assert(CanReinterpretSlice<const C0*, const C1*>, "up cast");
+static_assert(CanReinterpretSlice<const C0*, C1*>, "up cast, apply const");
+static_assert(!CanReinterpretSlice<C0*, const C1*>, "up cast, remove const");
+static_assert(!CanReinterpretSlice<C1*, C0*>, "down cast");
+static_assert(!CanReinterpretSlice<const C1*, const C0*>, "down cast");
+static_assert(!CanReinterpretSlice<const C1*, C0*>, "down cast, apply const");
+static_assert(!CanReinterpretSlice<C1*, const C0*>, "down cast, remove const");
+static_assert(!CanReinterpretSlice<const C1*, C0*>, "down cast, apply const");
+static_assert(!CanReinterpretSlice<C1*, const C0*>, "down cast, remove const");
+static_assert(!CanReinterpretSlice<C2a*, C2b*>, "sideways cast");
+static_assert(!CanReinterpretSlice<const C2a*, const C2b*>, "sideways cast");
+static_assert(!CanReinterpretSlice<const C2a*, C2b*>, "sideways cast, apply const");
+static_assert(!CanReinterpretSlice<C2a*, const C2b*>, "sideways cast, remove const");
+
+////////////////////////////////////////////////////////////////////////////////
+// TintVectorTest
+////////////////////////////////////////////////////////////////////////////////
+TEST(TintVectorTest, SmallArray_Empty) {
+ Vector<int, 2> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+}
+
+TEST(TintVectorTest, NoSmallArray) {
+ Vector<int, 0> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 0u);
+}
+
+TEST(TintVectorTest, Empty_SmallArray_Empty) {
+ Vector<int, 2> vec(Empty);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+}
+
+TEST(TintVectorTest, Empty_NoSmallArray) {
+ Vector<int, 0> vec(Empty);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 0u);
+}
+
+TEST(TintVectorTest, InitializerList_NoSpill) {
+ Vector<std::string, 2> vec{"one", "two"};
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "one");
+ EXPECT_EQ(vec[1], "two");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InitializerList_WithSpill) {
+ Vector<std::string, 2> vec{"one", "two", "three"};
+ EXPECT_EQ(vec.Length(), 3u);
+ EXPECT_EQ(vec.Capacity(), 3u);
+ EXPECT_EQ(vec[0], "one");
+ EXPECT_EQ(vec[1], "two");
+ EXPECT_EQ(vec[2], "three");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InitializerList_NoSmallArray) {
+ Vector<std::string, 0> vec{"one", "two"};
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "one");
+ EXPECT_EQ(vec[1], "two");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, Push_NoSmallArray) {
+ Vector<std::string, 0> vec;
+ vec.Push("one");
+ vec.Push("two");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "one");
+ EXPECT_EQ(vec[1], "two");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_1CString) {
+ auto vec = Vector{"one"};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const char*>);
+ static_assert(decltype(vec)::static_length == 1u);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ EXPECT_STREQ(vec[0], "one");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_2CStrings) {
+ auto vec = Vector{"one", "two"};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const char*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_STREQ(vec[0], "one");
+ EXPECT_STREQ(vec[1], "two");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_IntFloat) {
+ auto vec = Vector{1, 2.0f};
+ static_assert(std::is_same_v<decltype(vec)::value_type, float>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], 1.0f);
+ EXPECT_EQ(vec[1], 2.0f);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_IntDoubleIntDouble) {
+ auto vec = Vector{1, 2.0, 3, 4.0};
+ static_assert(std::is_same_v<decltype(vec)::value_type, double>);
+ static_assert(decltype(vec)::static_length == 4u);
+ EXPECT_EQ(vec.Length(), 4u);
+ EXPECT_EQ(vec.Capacity(), 4u);
+ EXPECT_EQ(vec[0], 1.0);
+ EXPECT_EQ(vec[1], 2.0);
+ EXPECT_EQ(vec[2], 3.0);
+ EXPECT_EQ(vec[3], 4.0);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_C0) {
+ C0 c0;
+ auto vec = Vector{&c0};
+ static_assert(std::is_same_v<decltype(vec)::value_type, C0*>);
+ static_assert(decltype(vec)::static_length == 1u);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ EXPECT_EQ(vec[0], &c0);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_ConstC0) {
+ const C0 c0;
+ auto vec = Vector{&c0};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const C0*>);
+ static_assert(decltype(vec)::static_length == 1u);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ EXPECT_EQ(vec[0], &c0);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_C0C1) {
+ C0 c0;
+ C1 c1;
+ auto vec = Vector{&c0, &c1};
+ static_assert(std::is_same_v<decltype(vec)::value_type, C0*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c0);
+ EXPECT_EQ(vec[1], &c1);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_ConstC0C1) {
+ const C0 c0;
+ C1 c1;
+ auto vec = Vector{&c0, &c1};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const C0*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c0);
+ EXPECT_EQ(vec[1], &c1);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_C0ConstC1) {
+ C0 c0;
+ const C1 c1;
+ auto vec = Vector{&c0, &c1};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const C0*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c0);
+ EXPECT_EQ(vec[1], &c1);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_ConstC0ConstC1) {
+ const C0 c0;
+ const C1 c1;
+ auto vec = Vector{&c0, &c1};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const C0*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c0);
+ EXPECT_EQ(vec[1], &c1);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_C2aC2b) {
+ C2a c2a;
+ C2b c2b;
+ auto vec = Vector{&c2a, &c2b};
+ static_assert(std::is_same_v<decltype(vec)::value_type, C1*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c2a);
+ EXPECT_EQ(vec[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_ConstC2aC2b) {
+ const C2a c2a;
+ C2b c2b;
+ auto vec = Vector{&c2a, &c2b};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const C1*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c2a);
+ EXPECT_EQ(vec[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_C2aConstC2b) {
+ C2a c2a;
+ const C2b c2b;
+ auto vec = Vector{&c2a, &c2b};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const C1*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c2a);
+ EXPECT_EQ(vec[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, InferTN_ConstC2aConstC2b) {
+ const C2a c2a;
+ const C2b c2b;
+ auto vec = Vector{&c2a, &c2b};
+ static_assert(std::is_same_v<decltype(vec)::value_type, const C1*>);
+ static_assert(decltype(vec)::static_length == 2u);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], &c2a);
+ EXPECT_EQ(vec[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, CopyVector_NoSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 2> vec_b(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyVector_WithSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 2> vec_b(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyVector_NoSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyVector_WithSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 1> vec_b(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyVector_NoSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyVector_WithSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 3> vec_b(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyVector_NoMoveUpcast_NoSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 2> vec_a{&c2a, &c2b};
+ Vector<C0*, 2> vec_b(vec_a); // No move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, CopyVector_NoMoveUpcast_WithSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ Vector<C0*, 2> vec_b(vec_a); // No move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, CopyVector_NoMoveAddConst_NoSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 2> vec_a{&c2a, &c2b};
+ Vector<const C1*, 2> vec_b(vec_a); // No move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, CopyVector_NoMoveAddConst_WithSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ Vector<const C1*, 2> vec_b(vec_a); // No move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, CopyVector_NoMoveUpcastAndAddConst_NoSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 2> vec_a{&c2a, &c2b};
+ Vector<const C0*, 2> vec_b(vec_a); // No move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, CopyVector_NoMoveUpcastAndAddConst_WithSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ Vector<const C0*, 2> vec_b(vec_a); // No move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, MoveVector_NoSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 2> vec_b(std::move(vec_a));
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveVector_WithSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 2> vec_b(std::move(vec_a));
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveVector_NoSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b(std::move(vec_a));
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveVector_WithSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 1> vec_b(std::move(vec_a));
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveVector_NoSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b(std::move(vec_a));
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveVector_WithSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 3> vec_b(std::move(vec_a));
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveVector_Upcast_NoSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 2> vec_a{&c2a, &c2b};
+ Vector<C0*, 2> vec_b(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, MoveVector_Upcast_WithSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ Vector<C0*, 2> vec_b(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorTest, MoveVector_AddConst_NoSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 2> vec_a{&c2a, &c2b};
+ Vector<const C1*, 2> vec_b(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, MoveVector_AddConst_WithSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ Vector<const C1*, 2> vec_b(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorTest, MoveVector_UpcastAndAddConst_NoSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 2> vec_a{&c2a, &c2b};
+ Vector<const C0*, 2> vec_b(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorTest, MoveVector_UpcastAndAddConst_WithSpill) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ Vector<const C0*, 2> vec_b(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorTest, CopyAssign_NoSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 2> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 2> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_NoSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 1> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_NoSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 3> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_NoSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 0> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 0> vec_b;
+ vec_b = vec_a;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssign_Self_NoSpill) {
+ Vector<std::string, 2> vec{"hello", "world"};
+ auto* vec_ptr = &vec; // Used to avoid -Wself-assign-overloaded
+ vec = *vec_ptr;
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, CopyAssign_Self_WithSpill) {
+ Vector<std::string, 1> vec{"hello", "world"};
+ auto* vec_ptr = &vec; // Used to avoid -Wself-assign-overloaded
+ vec = *vec_ptr;
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 2> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_WithSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 2> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_SpillSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 1> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_WithSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 3> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 0> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_WithSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 0> vec_b;
+ vec_b = std::move(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssign_Self_NoSpill) {
+ Vector<std::string, 2> vec{"hello", "world"};
+ auto* vec_ptr = &vec; // Used to avoid -Wself-move
+ vec = std::move(*vec_ptr);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, MoveAssign_Self_WithSpill) {
+ Vector<std::string, 1> vec{"hello", "world"};
+ auto* vec_ptr = &vec; // Used to avoid -Wself-move
+ vec = std::move(*vec_ptr);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, RepeatMoveAssign_NoSpill) {
+ Vector<std::string, 3> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b{"Ciao", "mondo"};
+ Vector<std::string, 3> vec_c{"Bonjour", "le", "monde"};
+ Vector<std::string, 3> vec;
+ vec = std::move(vec_a);
+ vec = std::move(vec_b);
+ vec = std::move(vec_c);
+ EXPECT_EQ(vec.Length(), 3u);
+ EXPECT_EQ(vec.Capacity(), 3u);
+ EXPECT_EQ(vec[0], "Bonjour");
+ EXPECT_EQ(vec[1], "le");
+ EXPECT_EQ(vec[2], "monde");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, RepeatMoveAssign_WithSpill) {
+ Vector<std::string, 1> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b{"Ciao", "mondo"};
+ Vector<std::string, 1> vec_c{"bonjour", "le", "monde"};
+ Vector<std::string, 1> vec;
+ vec = std::move(vec_a);
+ vec = std::move(vec_b);
+ vec = std::move(vec_c);
+ EXPECT_EQ(vec.Length(), 3u);
+ EXPECT_EQ(vec.Capacity(), 3u);
+ EXPECT_EQ(vec[0], "bonjour");
+ EXPECT_EQ(vec[1], "le");
+ EXPECT_EQ(vec[2], "monde");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 2> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 2> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 1> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 1> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 3> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 3> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 0> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 0> vec_b;
+ vec_b = ref;
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, CopyAssignRef_Self_NoSpill) {
+ Vector<std::string, 2> vec{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec)};
+ vec = ref;
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, CopyAssignRef_Self_WithSpill) {
+ Vector<std::string, 1> vec{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec)};
+ vec = ref;
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 2> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_WithSpill_N2_to_N2) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 2> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 1> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_SpillSpill_N2_to_N1) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 1> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 3> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_WithSpill_N2_to_N3) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 3> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 0> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_WithSpill_N2_to_N0) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ VectorRef<std::string> ref{std::move(vec_a)};
+ Vector<std::string, 0> vec_b;
+ vec_b = std::move(ref);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, MoveAssignRef_Self_NoSpill) {
+ Vector<std::string, 2> vec{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec)};
+ vec = std::move(ref);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, MoveAssignRef_Self_WithSpill) {
+ Vector<std::string, 1> vec{"hello", "world"};
+ VectorRef<std::string> ref{std::move(vec)};
+ vec = std::move(ref);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, RepeatMoveAssignRef_NoSpill) {
+ Vector<std::string, 3> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b{"Ciao", "mondo"};
+ Vector<std::string, 3> vec_c{"Bonjour", "le", "monde"};
+ VectorRef<std::string> ref_a{std::move(vec_a)};
+ VectorRef<std::string> ref_b{std::move(vec_b)};
+ VectorRef<std::string> ref_c{std::move(vec_c)};
+ Vector<std::string, 3> vec;
+ vec = std::move(ref_a);
+ vec = std::move(ref_b);
+ vec = std::move(ref_c);
+ EXPECT_EQ(vec.Length(), 3u);
+ EXPECT_EQ(vec.Capacity(), 3u);
+ EXPECT_EQ(vec[0], "Bonjour");
+ EXPECT_EQ(vec[1], "le");
+ EXPECT_EQ(vec[2], "monde");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, RepeatMoveAssignRef_WithSpill) {
+ Vector<std::string, 1> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b{"Ciao", "mondo"};
+ Vector<std::string, 1> vec_c{"bonjour", "le", "monde"};
+ VectorRef<std::string> ref_a{std::move(vec_a)};
+ VectorRef<std::string> ref_b{std::move(vec_b)};
+ VectorRef<std::string> ref_c{std::move(vec_c)};
+ Vector<std::string, 1> vec;
+ vec = std::move(ref_a);
+ vec = std::move(ref_b);
+ vec = std::move(ref_c);
+ EXPECT_EQ(vec.Length(), 3u);
+ EXPECT_EQ(vec.Capacity(), 3u);
+ EXPECT_EQ(vec[0], "bonjour");
+ EXPECT_EQ(vec[1], "le");
+ EXPECT_EQ(vec[2], "monde");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, Index) {
+ Vector<std::string, 2> vec{"hello", "world"};
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec[0])>>);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+}
+
+TEST(TintVectorTest, ConstIndex) {
+ const Vector<std::string, 2> vec{"hello", "world"};
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec[0])>>);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "world");
+}
+
+TEST(TintVectorTest, Reserve_NoSpill) {
+ Vector<std::string, 2> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ vec.Reserve(1);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ vec.Reserve(2);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ vec.Push("hello");
+ vec.Push("world");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec.Reserve(1);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, Reserve_WithSpill) {
+ Vector<std::string, 1> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ vec.Reserve(1);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ vec.Reserve(2);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ vec.Push("hello");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec.Push("world");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec.Reserve(1);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, ResizeZero_NoSpill) {
+ Vector<std::string, 2> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ vec.Resize(1);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec[0] = "hello";
+ vec.Resize(2);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec[1] = "world";
+ vec.Resize(1);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec.Resize(2);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, ResizeZero_WithSpill) {
+ Vector<std::string, 1> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ vec.Resize(1);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ EXPECT_EQ(vec[0], "");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec[0] = "hello";
+ vec.Resize(2);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec[1] = "world";
+ vec.Resize(1);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec.Resize(2);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, ResizeValue_NoSpill) {
+ Vector<std::string, 2> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ vec.Resize(1, "meow");
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "meow");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec[0] = "hello";
+ vec.Resize(2, "woof");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "woof");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec[1] = "world";
+ vec.Resize(1, "quack");
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec.Resize(2, "hiss");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "hiss");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, ResizeValue_WithSpill) {
+ Vector<std::string, 1> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ vec.Resize(1, "meow");
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ EXPECT_EQ(vec[0], "meow");
+ EXPECT_TRUE(AllInternallyHeld(vec));
+ vec[0] = "hello";
+ vec.Resize(2, "woof");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "woof");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec[1] = "world";
+ vec.Resize(1, "quack");
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec.Resize(2, "hiss");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "hiss");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, Reserve_NoSmallArray) {
+ Vector<std::string, 0> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 0u);
+ vec.Reserve(1);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ vec.Reserve(2);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ vec.Push("hello");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec.Push("world");
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec.Reserve(1);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, Resize_NoSmallArray) {
+ Vector<std::string, 0> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 0u);
+ vec.Resize(1);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 1u);
+ EXPECT_EQ(vec[0], "");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec[0] = "hello";
+ vec.Resize(2);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec[1] = "world";
+ vec.Resize(1);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+ vec.Resize(2);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+ EXPECT_EQ(vec[0], "hello");
+ EXPECT_EQ(vec[1], "");
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N2_Empty) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 2> vec_b;
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N2_NonEmpty) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 2> vec_b{"hallo", "wereld"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N2_Spill) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 2> vec_b{"hallo", "wereld", "spill"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N2_Empty) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 2> vec_b;
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N2_NonEmpty) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 2> vec_b{"hallo", "wereld"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N2_Spill) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 2> vec_b{"hallo", "wereld", "morsen"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N1_Empty) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b;
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N1_NonEmpty) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b{"hallo"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N1_Spill) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 1> vec_b{"hallo", "morsen"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 2u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N1_Empty) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 1> vec_b;
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N1_NonEmpty) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 1> vec_b{"hallo"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N1_Spill) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 1> vec_b{"hallo", "wereld"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N3_Empty) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b;
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N3_NonEmpty) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b{"hallo", "fijne", "wereld"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_NoSpill_N2_to_N3_Spill) {
+ Vector<std::string, 2> vec_a{"hello", "world"};
+ Vector<std::string, 3> vec_b{"hallo", "fijne", "wereld", "morsen"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 2u);
+ EXPECT_EQ(vec_b.Capacity(), 4u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N3_Empty) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 3> vec_b;
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N3_NonEmpty) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 3> vec_b{"hallo", "fijne", "wereld"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 3u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllInternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Copy_WithSpill_N2_to_N3_Spill) {
+ Vector<std::string, 2> vec_a{"hello", "world", "spill"};
+ Vector<std::string, 3> vec_b{"hallo", "fijne", "wereld", "morsen"};
+ vec_b.Copy(vec_a);
+ EXPECT_EQ(vec_b.Length(), 3u);
+ EXPECT_EQ(vec_b.Capacity(), 4u);
+ EXPECT_EQ(vec_b[0], "hello");
+ EXPECT_EQ(vec_b[1], "world");
+ EXPECT_EQ(vec_b[2], "spill");
+ EXPECT_TRUE(AllExternallyHeld(vec_b));
+}
+
+TEST(TintVectorTest, Clear_Empty) {
+ Vector<std::string, 2> vec;
+ vec.Clear();
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+}
+
+TEST(TintVectorTest, Clear_NoSpill) {
+ Vector<std::string, 2> vec{"hello", "world"};
+ vec.Clear();
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 2u);
+}
+
+TEST(TintVectorTest, Clear_WithSpill) {
+ Vector<std::string, 2> vec{"hello", "world", "spill"};
+ vec.Clear();
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_EQ(vec.Capacity(), 3u);
+}
+
+TEST(TintVectorTest, PushPop_StringNoSpill) {
+ const std::string hello = "hello";
+ const std::string world = "world";
+
+ Vector<std::string, 2> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(hello);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(world);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), world);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), hello);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, PushPop_StringWithSpill) {
+ const std::string hello = "hello";
+ const std::string world = "world";
+
+ Vector<std::string, 1> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(hello);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(world);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), world);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), hello);
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, PushPop_StringMoveNoSpill) {
+ std::string hello = "hello";
+ std::string world = "world";
+
+ Vector<std::string, 2> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(std::move(hello));
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(std::move(world));
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), "world");
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), "hello");
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, PushPop_StringMoveWithSpill) {
+ std::string hello = "hello";
+ std::string world = "world";
+
+ Vector<std::string, 1> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(std::move(hello));
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Push(std::move(world));
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), "world");
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), "hello");
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, EmplacePop_TupleVarArgNoSpill) {
+ Vector<std::tuple<int, float, bool>, 2> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Emplace(1, 2.0, false);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Emplace(3, 4.0, true);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), std::make_tuple(3, 4.0, true));
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), std::make_tuple(1, 2.0, false));
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+}
+
+TEST(TintVectorTest, EmplacePop_TupleVarArgWithSpill) {
+ Vector<std::tuple<int, float, bool>, 1> vec;
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Emplace(1, 2.0, false);
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllInternallyHeld(vec));
+
+ vec.Emplace(3, 4.0, true);
+ EXPECT_EQ(vec.Length(), 2u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), std::make_tuple(3, 4.0, true));
+ EXPECT_EQ(vec.Length(), 1u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+
+ EXPECT_EQ(vec.Pop(), std::make_tuple(1, 2.0, false));
+ EXPECT_EQ(vec.Length(), 0u);
+ EXPECT_TRUE(AllExternallyHeld(vec));
+}
+
+TEST(TintVectorTest, IsEmpty) {
+ Vector<std::string, 1> vec;
+ EXPECT_TRUE(vec.IsEmpty());
+ vec.Push("one");
+ EXPECT_FALSE(vec.IsEmpty());
+ vec.Pop();
+ EXPECT_TRUE(vec.IsEmpty());
+}
+
+TEST(TintVectorTest, FrontBack_NoSpill) {
+ Vector<std::string, 3> vec{"front", "mid", "back"};
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec.Front())>>);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec.Back())>>);
+ EXPECT_EQ(vec.Front(), "front");
+ EXPECT_EQ(vec.Back(), "back");
+}
+
+TEST(TintVectorTest, FrontBack_WithSpill) {
+ Vector<std::string, 2> vec{"front", "mid", "back"};
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec.Front())>>);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec.Back())>>);
+ EXPECT_EQ(vec.Front(), "front");
+ EXPECT_EQ(vec.Back(), "back");
+}
+
+TEST(TintVectorTest, ConstFrontBack_NoSpill) {
+ const Vector<std::string, 3> vec{"front", "mid", "back"};
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec.Front())>>);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec.Back())>>);
+ EXPECT_EQ(vec.Front(), "front");
+ EXPECT_EQ(vec.Back(), "back");
+}
+
+TEST(TintVectorTest, ConstFrontBack_WithSpill) {
+ const Vector<std::string, 2> vec{"front", "mid", "back"};
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec.Front())>>);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec.Back())>>);
+ EXPECT_EQ(vec.Front(), "front");
+ EXPECT_EQ(vec.Back(), "back");
+}
+
+TEST(TintVectorTest, BeginEnd_NoSpill) {
+ Vector<std::string, 3> vec{"front", "mid", "back"};
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(*vec.begin())>>);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(*vec.end())>>);
+ EXPECT_EQ(vec.begin(), &vec[0]);
+ EXPECT_EQ(vec.end(), &vec[0] + 3);
+}
+
+TEST(TintVectorTest, BeginEnd_WithSpill) {
+ Vector<std::string, 2> vec{"front", "mid", "back"};
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(*vec.begin())>>);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(*vec.end())>>);
+ EXPECT_EQ(vec.begin(), &vec[0]);
+ EXPECT_EQ(vec.end(), &vec[0] + 3);
+}
+
+TEST(TintVectorTest, ConstBeginEnd_NoSpill) {
+ const Vector<std::string, 3> vec{"front", "mid", "back"};
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec.begin())>>);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec.end())>>);
+ EXPECT_EQ(vec.begin(), &vec[0]);
+ EXPECT_EQ(vec.end(), &vec[0] + 3);
+}
+
+TEST(TintVectorTest, ConstBeginEnd_WithSpill) {
+ const Vector<std::string, 2> vec{"front", "mid", "back"};
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec.begin())>>);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec.end())>>);
+ EXPECT_EQ(vec.begin(), &vec[0]);
+ EXPECT_EQ(vec.end(), &vec[0] + 3);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TintVectorRefTest
+////////////////////////////////////////////////////////////////////////////////
+TEST(TintVectorRefTest, CopyVectorRef) {
+ Vector<std::string, 1> vec_a{"one", "two"};
+ VectorRef<std::string> vec_ref_a(std::move(vec_a));
+ VectorRef<std::string> vec_ref_b(vec_ref_a); // No move
+ Vector<std::string, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], "one");
+ EXPECT_EQ(vec_b[1], "two");
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, CopyVectorRef_Upcast) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C1*> vec_ref_a(std::move(vec_a));
+ VectorRef<C0*> vec_ref_b(vec_ref_a); // No-move. Up-cast
+ Vector<C0*, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, CopyVectorRef_AddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C1*> vec_ref_a(std::move(vec_a));
+ VectorRef<const C1*> vec_ref_b(vec_ref_a); // No-move. Up-cast
+ Vector<const C1*, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, CopyVectorRef_UpcastAndAddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C1*> vec_ref_a(std::move(vec_a));
+ VectorRef<const C0*> vec_ref_b(vec_ref_a); // No-move. Up-cast
+ Vector<const C0*, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, MoveVectorRef) {
+ Vector<std::string, 1> vec_a{"one", "two"};
+ VectorRef<std::string> vec_ref_a(std::move(vec_a)); // Move
+ VectorRef<std::string> vec_ref_b(std::move(vec_ref_a));
+ Vector<std::string, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], "one");
+ EXPECT_EQ(vec_b[1], "two");
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, MoveVectorRef_Upcast) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C1*> vec_ref_a(std::move(vec_a));
+ VectorRef<C0*> vec_ref_b(std::move(vec_ref_a)); // Moved. Up-cast
+ Vector<C0*, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, MoveVectorRef_AddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C1*> vec_ref_a(std::move(vec_a));
+ VectorRef<const C1*> vec_ref_b(std::move(vec_ref_a)); // Moved. Up-cast
+ Vector<const C1*, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, MoveVectorRef_UpcastAndAddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C1*> vec_ref_a(std::move(vec_a));
+ VectorRef<const C0*> vec_ref_b(std::move(vec_ref_a)); // Moved. Up-cast
+ Vector<const C0*, 2> vec_b(std::move(vec_ref_b));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, CopyVector) {
+ Vector<std::string, 1> vec_a{"one", "two"};
+ VectorRef<std::string> vec_ref(vec_a); // No move
+ Vector<std::string, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], "one");
+ EXPECT_EQ(vec_b[1], "two");
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, CopyVector_Upcast) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C0*> vec_ref(vec_a); // No move
+ EXPECT_EQ(vec_ref[0], &c2a);
+ EXPECT_EQ(vec_ref[1], &c2b);
+ Vector<C0*, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, CopyVector_AddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<const C1*> vec_ref(vec_a); // No move
+ EXPECT_EQ(vec_ref[0], &c2a);
+ EXPECT_EQ(vec_ref[1], &c2b);
+ Vector<const C1*, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, CopyVector_UpcastAndAddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<const C0*> vec_ref(vec_a); // No move
+ EXPECT_EQ(vec_ref[0], &c2a);
+ EXPECT_EQ(vec_ref[1], &c2b);
+ Vector<const C0*, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
+}
+
+TEST(TintVectorRefTest, MoveVector) {
+ Vector<std::string, 1> vec_a{"one", "two"};
+ VectorRef<std::string> vec_ref(std::move(vec_a)); // Move
+ Vector<std::string, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], "one");
+ EXPECT_EQ(vec_b[1], "two");
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, MoveVector_Upcast) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<C0*> vec_ref(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_ref[0], &c2a);
+ EXPECT_EQ(vec_ref[1], &c2b);
+ Vector<C0*, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, MoveVector_AddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<const C1*> vec_ref(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_ref[0], &c2a);
+ EXPECT_EQ(vec_ref[1], &c2b);
+ Vector<const C1*, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, MoveVector_UpcastAndAddConst) {
+ C2a c2a;
+ C2b c2b;
+ Vector<C1*, 1> vec_a{&c2a, &c2b};
+ VectorRef<const C0*> vec_ref(std::move(vec_a)); // Move
+ EXPECT_EQ(vec_ref[0], &c2a);
+ EXPECT_EQ(vec_ref[1], &c2b);
+ Vector<const C0*, 2> vec_b(std::move(vec_ref));
+ EXPECT_EQ(vec_b[0], &c2a);
+ EXPECT_EQ(vec_b[1], &c2b);
+ EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied
+}
+
+TEST(TintVectorRefTest, Index) {
+ Vector<std::string, 2> vec{"one", "two"};
+ VectorRef<std::string> vec_ref(vec);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref[0])>>);
+ EXPECT_EQ(vec_ref[0], "one");
+ EXPECT_EQ(vec_ref[1], "two");
+}
+
+TEST(TintVectorRefTest, ConstIndex) {
+ Vector<std::string, 2> vec{"one", "two"};
+ const VectorRef<std::string> vec_ref(vec);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref[0])>>);
+ EXPECT_EQ(vec_ref[0], "one");
+ EXPECT_EQ(vec_ref[1], "two");
+}
+
+TEST(TintVectorRefTest, Length) {
+ Vector<std::string, 2> vec{"one", "two", "three"};
+ VectorRef<std::string> vec_ref(vec);
+ EXPECT_EQ(vec_ref.Length(), 3u);
+}
+
+TEST(TintVectorRefTest, Capacity) {
+ Vector<std::string, 5> vec{"one", "two", "three"};
+ VectorRef<std::string> vec_ref(vec);
+ EXPECT_EQ(vec_ref.Capacity(), 5u);
+}
+
+TEST(TintVectorRefTest, IsEmpty) {
+ Vector<std::string, 1> vec;
+ VectorRef<std::string> vec_ref(vec);
+ EXPECT_TRUE(vec_ref.IsEmpty());
+ vec.Push("one");
+ EXPECT_FALSE(vec_ref.IsEmpty());
+ vec.Pop();
+ EXPECT_TRUE(vec_ref.IsEmpty());
+}
+
+TEST(TintVectorRefTest, FrontBack) {
+ Vector<std::string, 3> vec{"front", "mid", "back"};
+ VectorRef<std::string> vec_ref(vec);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec_ref.Front())>>);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec_ref.Back())>>);
+ EXPECT_EQ(vec_ref.Front(), "front");
+ EXPECT_EQ(vec_ref.Back(), "back");
+}
+
+TEST(TintVectorRefTest, ConstFrontBack) {
+ Vector<std::string, 3> vec{"front", "mid", "back"};
+ const VectorRef<std::string> vec_ref(vec);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref.Front())>>);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref.Back())>>);
+ EXPECT_EQ(vec_ref.Front(), "front");
+ EXPECT_EQ(vec_ref.Back(), "back");
+}
+
+TEST(TintVectorRefTest, BeginEnd) {
+ Vector<std::string, 3> vec{"front", "mid", "back"};
+ VectorRef<std::string> vec_ref(vec);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(*vec_ref.begin())>>);
+ static_assert(!std::is_const_v<std::remove_reference_t<decltype(*vec_ref.end())>>);
+ EXPECT_EQ(vec_ref.begin(), &vec[0]);
+ EXPECT_EQ(vec_ref.end(), &vec[0] + 3);
+}
+
+TEST(TintVectorRefTest, ConstBeginEnd) {
+ Vector<std::string, 3> vec{"front", "mid", "back"};
+ const VectorRef<std::string> vec_ref(vec);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec_ref.begin())>>);
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec_ref.end())>>);
+ EXPECT_EQ(vec_ref.begin(), &vec[0]);
+ EXPECT_EQ(vec_ref.end(), &vec[0] + 3);
+}
+
+} // namespace
+} // namespace tint::utils
+
+TINT_INSTANTIATE_TYPEINFO(tint::utils::C0);
+TINT_INSTANTIATE_TYPEINFO(tint::utils::C1);
+TINT_INSTANTIATE_TYPEINFO(tint::utils::C2a);
+TINT_INSTANTIATE_TYPEINFO(tint::utils::C2b);
diff --git a/chromium/third_party/dawn/src/tint/val/hlsl.cc b/chromium/third_party/dawn/src/tint/val/hlsl.cc
index 49c38501a9e..eabbe684881 100644
--- a/chromium/third_party/dawn/src/tint/val/hlsl.cc
+++ b/chromium/third_party/dawn/src/tint/val/hlsl.cc
@@ -12,10 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <string>
+
#include "src/tint/val/val.h"
#include "src/tint/utils/io/command.h"
#include "src/tint/utils/io/tmpfile.h"
+#include "src/tint/utils/string.h"
#ifdef _WIN32
#include <Windows.h>
@@ -31,7 +34,7 @@ namespace tint::val {
Result HlslUsingDXC(const std::string& dxc_path,
const std::string& source,
const EntryPointList& entry_points,
- const std::vector<std::string>& overrides) {
+ bool require_16bit_types) {
Result result;
auto dxc = utils::Command(dxc_path);
@@ -41,11 +44,14 @@ Result HlslUsingDXC(const std::string& dxc_path,
return result;
}
+ // Native 16-bit types, e.g. float16_t, require SM6.2. Otherwise we use SM6.0.
+ const char* shader_model_version = require_16bit_types ? "6_2" : "6_0";
+
utils::TmpFile file;
file << source;
for (auto ep : entry_points) {
- const char* profile = "";
+ const char* stage_prefix = "";
switch (ep.second) {
case ast::PipelineStage::kNone:
@@ -53,30 +59,26 @@ Result HlslUsingDXC(const std::string& dxc_path,
result.failed = true;
return result;
case ast::PipelineStage::kVertex:
- profile = "-T vs_6_0";
+ stage_prefix = "vs";
break;
case ast::PipelineStage::kFragment:
- profile = "-T ps_6_0";
+ stage_prefix = "ps";
break;
case ast::PipelineStage::kCompute:
- profile = "-T cs_6_0";
+ stage_prefix = "cs";
break;
}
// Match Dawn's compile flags
// See dawn\src\dawn_native\d3d12\RenderPipelineD3D12.cpp
// and dawn_native\d3d12\ShaderModuleD3D12.cpp (GetDXCArguments)
- const char* compileFlags =
- "/Zpr " // D3DCOMPILE_PACK_MATRIX_ROW_MAJOR
- "/Gis"; // D3DCOMPILE_IEEE_STRICTNESS
-
- std::string defs;
- defs.reserve(overrides.size() * 20);
- for (auto& o : overrides) {
- defs += "/D" + o + " ";
- }
-
- auto res = dxc(profile, "-E " + ep.first, compileFlags, file.Path(), defs);
+ auto res = dxc(
+ "-T " + std::string(stage_prefix) + "_" + std::string(shader_model_version), // Profile
+ "-E " + ep.first, // Entry point
+ "/Zpr", // D3DCOMPILE_PACK_MATRIX_ROW_MAJOR
+ "/Gis", // D3DCOMPILE_IEEE_STRICTNESS
+ require_16bit_types ? "-enable-16bit-types" : "", // Enable 16-bit if required
+ file.Path());
if (!res.out.empty()) {
if (!result.output.empty()) {
result.output += "\n";
@@ -90,6 +92,9 @@ Result HlslUsingDXC(const std::string& dxc_path,
result.output += res.err;
}
result.failed = (res.error_code != 0);
+
+ // Remove the temporary file name from the output to keep output deterministic
+ result.output = utils::ReplaceAll(result.output, file.Path(), "shader.hlsl");
}
if (entry_points.empty()) {
@@ -102,28 +107,36 @@ Result HlslUsingDXC(const std::string& dxc_path,
}
#ifdef _WIN32
-Result HlslUsingFXC(const std::string& source,
- const EntryPointList& entry_points,
- const std::vector<std::string>& overrides) {
+Result HlslUsingFXC(const std::string& fxc_path,
+ const std::string& source,
+ const EntryPointList& entry_points) {
Result result;
// This library leaks if an error happens in this function, but it is ok
// because it is loaded at most once, and the executables using HlslUsingFXC
// are short-lived.
- HMODULE fxcLib = LoadLibraryA("d3dcompiler_47.dll");
+ HMODULE fxcLib = LoadLibraryA(fxc_path.c_str());
if (fxcLib == nullptr) {
result.output = "Couldn't load FXC";
result.failed = true;
return result;
}
- pD3DCompile d3dCompile = reinterpret_cast<pD3DCompile>(
+ auto* d3dCompile = reinterpret_cast<pD3DCompile>(
reinterpret_cast<void*>(GetProcAddress(fxcLib, "D3DCompile")));
+ auto* d3dDisassemble = reinterpret_cast<pD3DDisassemble>(
+ reinterpret_cast<void*>(GetProcAddress(fxcLib, "D3DDisassemble")));
+
if (d3dCompile == nullptr) {
result.output = "Couldn't load D3DCompile from FXC";
result.failed = true;
return result;
}
+ if (d3dDisassemble == nullptr) {
+ result.output = "Couldn't load D3DDisassemble from FXC";
+ result.failed = true;
+ return result;
+ }
for (auto ep : entry_points) {
const char* profile = "";
@@ -148,37 +161,32 @@ Result HlslUsingFXC(const std::string& source,
UINT compileFlags = D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR |
D3DCOMPILE_IEEE_STRICTNESS;
- auto overrides_copy = overrides; // Copy so that we can replace '=' with '\0'
- std::vector<D3D_SHADER_MACRO> macros;
- macros.reserve(overrides_copy.size() * 2);
- for (auto& o : overrides_copy) {
- if (auto sep = o.find_first_of('='); sep != std::string::npos) {
- // Replace '=' with '\0' so we can point directly into the allocated string buffer
- o[sep] = '\0';
- macros.push_back(D3D_SHADER_MACRO{&o[0], &o[sep + 1]});
- } else {
- macros.emplace_back(D3D_SHADER_MACRO{o.c_str(), NULL});
- }
- }
- macros.emplace_back(D3D_SHADER_MACRO{NULL, NULL});
-
ComPtr<ID3DBlob> compiledShader;
ComPtr<ID3DBlob> errors;
- HRESULT cr = d3dCompile(source.c_str(), // pSrcData
- source.length(), // SrcDataSize
- nullptr, // pSourceName
- macros.data(), // pDefines
- nullptr, // pInclude
- ep.first.c_str(), // pEntrypoint
- profile, // pTarget
- compileFlags, // Flags1
- 0, // Flags2
- &compiledShader, // ppCode
- &errors); // ppErrorMsgs
- if (FAILED(cr)) {
+ HRESULT res = d3dCompile(source.c_str(), // pSrcData
+ source.length(), // SrcDataSize
+ nullptr, // pSourceName
+ nullptr, // pDefines
+ nullptr, // pInclude
+ ep.first.c_str(), // pEntrypoint
+ profile, // pTarget
+ compileFlags, // Flags1
+ 0, // Flags2
+ &compiledShader, // ppCode
+ &errors); // ppErrorMsgs
+ if (FAILED(res)) {
result.output = static_cast<char*>(errors->GetBufferPointer());
result.failed = true;
return result;
+ } else {
+ ComPtr<ID3DBlob> disassembly;
+ res = d3dDisassemble(compiledShader->GetBufferPointer(),
+ compiledShader->GetBufferSize(), 0, "", &disassembly);
+ if (FAILED(res)) {
+ result.output = "failed to disassemble shader";
+ } else {
+ result.output = static_cast<char*>(disassembly->GetBufferPointer());
+ }
}
}
diff --git a/chromium/third_party/dawn/src/tint/val/val.h b/chromium/third_party/dawn/src/tint/val/val.h
index c869efb7aa8..02ffc780cfe 100644
--- a/chromium/third_party/dawn/src/tint/val/val.h
+++ b/chromium/third_party/dawn/src/tint/val/val.h
@@ -30,6 +30,9 @@ namespace tint::val {
using EntryPointList = std::vector<std::pair<std::string, ast::PipelineStage>>;
+/// Name of the FXC compiler DLL
+static constexpr const char kFxcDLLName[] = "d3dcompiler_47.dll";
+
/// The return structure of Validate()
struct Result {
/// True if validation passed
@@ -43,23 +46,22 @@ struct Result {
/// @param dxc_path path to DXC
/// @param source the generated HLSL source
/// @param entry_points the list of entry points to validate
-/// @param overrides optional list of pipeline overrides
/// @return the result of the compile
Result HlslUsingDXC(const std::string& dxc_path,
const std::string& source,
const EntryPointList& entry_points,
- const std::vector<std::string>& overrides);
+ bool require_16bit_types);
#ifdef _WIN32
/// Hlsl attempts to compile the shader with FXC, verifying that the shader
/// compiles successfully.
+/// @param fxc_path path to the FXC DLL
/// @param source the generated HLSL source
/// @param entry_points the list of entry points to validate
-/// @param overrides optional list of pipeline overrides
/// @return the result of the compile
-Result HlslUsingFXC(const std::string& source,
- const EntryPointList& entry_points,
- const std::vector<std::string>& overrides);
+Result HlslUsingFXC(const std::string& fxc_path,
+ const std::string& source,
+ const EntryPointList& entry_points);
#endif // _WIN32
/// Msl attempts to compile the shader with the Metal Shader Compiler,
diff --git a/chromium/third_party/dawn/src/tint/writer/append_vector.cc b/chromium/third_party/dawn/src/tint/writer/append_vector.cc
index bc89d1f0d87..527560edc39 100644
--- a/chromium/third_party/dawn/src/tint/writer/append_vector.cc
+++ b/chromium/third_party/dawn/src/tint/writer/append_vector.cc
@@ -59,7 +59,8 @@ const sem::Expression* Zero(ProgramBuilder& b, const sem::Type* ty, const sem::S
<< "unsupported vector element type: " << ty->TypeInfo().name;
return nullptr;
}
- auto* sem = b.create<sem::Expression>(expr, ty, stmt, sem::Constant{},
+ auto* sem = b.create<sem::Expression>(expr, ty, sem::EvaluationStage::kRuntime, stmt,
+ /* constant_value */ nullptr,
/* has_side_effects */ false);
b.Sem().Add(expr, sem);
return sem;
@@ -111,23 +112,23 @@ const sem::Call* AppendVector(ProgramBuilder* b,
// to convert a vector of a different type, e.g. vec2<i32>(vec2<u32>()).
// In that case, preserve the original argument, or you'll get a type error.
- std::vector<const sem::Expression*> packed;
+ utils::Vector<const sem::Expression*, 4> packed;
if (auto vc = AsVectorConstructor(vector_sem)) {
- const auto num_supplied = vc.call->Arguments().size();
+ const auto num_supplied = vc.call->Arguments().Length();
if (num_supplied == 0) {
// Zero-value vector constructor. Populate with zeros
for (uint32_t i = 0; i < packed_size - 1; i++) {
auto* zero = Zero(*b, packed_el_sem_ty, statement);
- packed.emplace_back(zero);
+ packed.Push(zero);
}
} else if (num_supplied + 1 == packed_size) {
// All vector components were supplied as scalars. Pass them through.
packed = vc.call->Arguments();
}
}
- if (packed.empty()) {
+ if (packed.IsEmpty()) {
// The special cases didn't occur. Use the vector argument as-is.
- packed.emplace_back(vector_sem);
+ packed.Push(vector_sem);
}
if (packed_el_sem_ty != scalar_sem->Type()->UnwrapRef()) {
@@ -135,15 +136,17 @@ const sem::Call* AppendVector(ProgramBuilder* b,
auto* scalar_cast_ast = b->Construct(packed_el_ast_ty, scalar_ast);
auto* scalar_cast_target = b->create<sem::TypeConversion>(
packed_el_sem_ty,
- b->create<sem::Parameter>(nullptr, 0, scalar_sem->Type()->UnwrapRef(),
- ast::StorageClass::kNone, ast::Access::kUndefined));
+ b->create<sem::Parameter>(nullptr, 0u, scalar_sem->Type()->UnwrapRef(),
+ ast::StorageClass::kNone, ast::Access::kUndefined),
+ sem::EvaluationStage::kRuntime);
auto* scalar_cast_sem = b->create<sem::Call>(
- scalar_cast_ast, scalar_cast_target, std::vector<const sem::Expression*>{scalar_sem},
- statement, sem::Constant{}, /* has_side_effects */ false);
+ scalar_cast_ast, scalar_cast_target, sem::EvaluationStage::kRuntime,
+ utils::Vector<const sem::Expression*, 1>{scalar_sem}, statement,
+ /* constant_value */ nullptr, /* has_side_effects */ false);
b->Sem().Add(scalar_cast_ast, scalar_cast_sem);
- packed.emplace_back(scalar_cast_sem);
+ packed.Push(scalar_cast_sem);
} else {
- packed.emplace_back(scalar_sem);
+ packed.Push(scalar_sem);
}
auto* constructor_ast = b->Construct(
@@ -151,15 +154,18 @@ const sem::Call* AppendVector(ProgramBuilder* b,
utils::Transform(packed, [&](const sem::Expression* expr) { return expr->Declaration(); }));
auto* constructor_target = b->create<sem::TypeConstructor>(
packed_sem_ty,
- utils::Transform(
- packed, [&](const tint::sem::Expression* arg, size_t i) -> const sem::Parameter* {
- return b->create<sem::Parameter>(nullptr, static_cast<uint32_t>(i),
- arg->Type()->UnwrapRef(), ast::StorageClass::kNone,
- ast::Access::kUndefined);
- }));
- auto* constructor_sem = b->create<sem::Call>(constructor_ast, constructor_target, packed,
- statement, sem::Constant{},
- /* has_side_effects */ false);
+ utils::Transform(packed,
+ [&](const tint::sem::Expression* arg, size_t i) -> const sem::Parameter* {
+ return b->create<sem::Parameter>(
+ nullptr, static_cast<uint32_t>(i), arg->Type()->UnwrapRef(),
+ ast::StorageClass::kNone, ast::Access::kUndefined);
+ }),
+ sem::EvaluationStage::kRuntime);
+ auto* constructor_sem =
+ b->create<sem::Call>(constructor_ast, constructor_target, sem::EvaluationStage::kRuntime,
+ std::move(packed), statement,
+ /* constant_value */ nullptr,
+ /* has_side_effects */ false);
b->Sem().Add(constructor_ast, constructor_sem);
return constructor_sem;
}
diff --git a/chromium/third_party/dawn/src/tint/writer/append_vector.h b/chromium/third_party/dawn/src/tint/writer/append_vector.h
index e6a72382d40..353e20e292e 100644
--- a/chromium/third_party/dawn/src/tint/writer/append_vector.h
+++ b/chromium/third_party/dawn/src/tint/writer/append_vector.h
@@ -17,11 +17,14 @@
#include "src/tint/program_builder.h"
-// Forward Declarations
+// Forward declarations
namespace tint::ast {
class CallExpression;
class Expression;
} // namespace tint::ast
+namespace tint::sem {
+class Call;
+} // namespace tint::sem
namespace tint::writer {
diff --git a/chromium/third_party/dawn/src/tint/writer/append_vector_test.cc b/chromium/third_party/dawn/src/tint/writer/append_vector_test.cc
index 8169039210f..a8608f98f66 100644
--- a/chromium/third_party/dawn/src/tint/writer/append_vector_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/append_vector_test.cc
@@ -41,14 +41,14 @@ TEST_F(AppendVectorTest, Vec2i32_i32) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 3u);
+ ASSERT_EQ(vec_123->args.Length(), 3u);
EXPECT_EQ(vec_123->args[0], scalar_1);
EXPECT_EQ(vec_123->args[1], scalar_2);
EXPECT_EQ(vec_123->args[2], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 3u);
+ ASSERT_EQ(call->Arguments().Length(), 3u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
@@ -60,7 +60,7 @@ TEST_F(AppendVectorTest, Vec2i32_i32) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
@@ -81,18 +81,18 @@ TEST_F(AppendVectorTest, Vec2i32_u32) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 3u);
+ ASSERT_EQ(vec_123->args.Length(), 3u);
EXPECT_EQ(vec_123->args[0], scalar_1);
EXPECT_EQ(vec_123->args[1], scalar_2);
auto* u32_to_i32 = vec_123->args[2]->As<ast::CallExpression>();
ASSERT_NE(u32_to_i32, nullptr);
EXPECT_TRUE(u32_to_i32->target.type->Is<ast::I32>());
- ASSERT_EQ(u32_to_i32->args.size(), 1u);
+ ASSERT_EQ(u32_to_i32->args.Length(), 1u);
EXPECT_EQ(u32_to_i32->args[0], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 3u);
+ ASSERT_EQ(call->Arguments().Length(), 3u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
EXPECT_EQ(call->Arguments()[2], Sem().Get(u32_to_i32));
@@ -104,7 +104,7 @@ TEST_F(AppendVectorTest, Vec2i32_u32) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
@@ -127,24 +127,24 @@ TEST_F(AppendVectorTest, Vec2i32FromVec2u32_u32) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 2u);
+ ASSERT_EQ(vec_123->args.Length(), 2u);
auto* v2u32_to_v2i32 = vec_123->args[0]->As<ast::CallExpression>();
ASSERT_NE(v2u32_to_v2i32, nullptr);
ASSERT_TRUE(v2u32_to_v2i32->target.type->Is<ast::Vector>());
EXPECT_EQ(v2u32_to_v2i32->target.type->As<ast::Vector>()->width, 2u);
EXPECT_TRUE(v2u32_to_v2i32->target.type->As<ast::Vector>()->type->Is<ast::I32>());
- EXPECT_EQ(v2u32_to_v2i32->args.size(), 1u);
+ EXPECT_EQ(v2u32_to_v2i32->args.Length(), 1u);
EXPECT_EQ(v2u32_to_v2i32->args[0], uvec_12);
auto* u32_to_i32 = vec_123->args[1]->As<ast::CallExpression>();
ASSERT_NE(u32_to_i32, nullptr);
EXPECT_TRUE(u32_to_i32->target.type->Is<ast::I32>());
- ASSERT_EQ(u32_to_i32->args.size(), 1u);
+ ASSERT_EQ(u32_to_i32->args.Length(), 1u);
EXPECT_EQ(u32_to_i32->args[0], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 2u);
+ ASSERT_EQ(call->Arguments().Length(), 2u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
EXPECT_EQ(call->Arguments()[1], Sem().Get(u32_to_i32));
@@ -155,7 +155,7 @@ TEST_F(AppendVectorTest, Vec2i32FromVec2u32_u32) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
}
@@ -175,18 +175,18 @@ TEST_F(AppendVectorTest, Vec2i32_f32) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 3u);
+ ASSERT_EQ(vec_123->args.Length(), 3u);
EXPECT_EQ(vec_123->args[0], scalar_1);
EXPECT_EQ(vec_123->args[1], scalar_2);
auto* f32_to_i32 = vec_123->args[2]->As<ast::CallExpression>();
ASSERT_NE(f32_to_i32, nullptr);
EXPECT_TRUE(f32_to_i32->target.type->Is<ast::I32>());
- ASSERT_EQ(f32_to_i32->args.size(), 1u);
+ ASSERT_EQ(f32_to_i32->args.Length(), 1u);
EXPECT_EQ(f32_to_i32->args[0], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 3u);
+ ASSERT_EQ(call->Arguments().Length(), 3u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
EXPECT_EQ(call->Arguments()[2], Sem().Get(f32_to_i32));
@@ -198,7 +198,7 @@ TEST_F(AppendVectorTest, Vec2i32_f32) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
@@ -220,7 +220,7 @@ TEST_F(AppendVectorTest, Vec3i32_i32) {
auto* vec_1234 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_1234, nullptr);
- ASSERT_EQ(vec_1234->args.size(), 4u);
+ ASSERT_EQ(vec_1234->args.Length(), 4u);
EXPECT_EQ(vec_1234->args[0], scalar_1);
EXPECT_EQ(vec_1234->args[1], scalar_2);
EXPECT_EQ(vec_1234->args[2], scalar_3);
@@ -228,7 +228,7 @@ TEST_F(AppendVectorTest, Vec3i32_i32) {
auto* call = Sem().Get<sem::Call>(vec_1234);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 4u);
+ ASSERT_EQ(call->Arguments().Length(), 4u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
@@ -241,7 +241,7 @@ TEST_F(AppendVectorTest, Vec3i32_i32) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 4u);
+ ASSERT_EQ(ctor->Parameters().Length(), 4u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
@@ -250,7 +250,7 @@ TEST_F(AppendVectorTest, Vec3i32_i32) {
// AppendVector(vec_12, 3) -> vec3<i32>(vec_12, 3)
TEST_F(AppendVectorTest, Vec2i32Var_i32) {
- Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr(3_i);
WrapInFunction(vec_12, scalar_3);
@@ -262,13 +262,13 @@ TEST_F(AppendVectorTest, Vec2i32Var_i32) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 2u);
+ ASSERT_EQ(vec_123->args.Length(), 2u);
EXPECT_EQ(vec_123->args[0], vec_12);
EXPECT_EQ(vec_123->args[1], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 2u);
+ ASSERT_EQ(call->Arguments().Length(), 2u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
@@ -279,14 +279,14 @@ TEST_F(AppendVectorTest, Vec2i32Var_i32) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
}
// AppendVector(1, 2, scalar_3) -> vec3<i32>(1, 2, scalar_3)
TEST_F(AppendVectorTest, Vec2i32_i32Var) {
- Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
auto* scalar_1 = Expr(1_i);
auto* scalar_2 = Expr(2_i);
auto* scalar_3 = Expr("scalar_3");
@@ -300,14 +300,14 @@ TEST_F(AppendVectorTest, Vec2i32_i32Var) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 3u);
+ ASSERT_EQ(vec_123->args.Length(), 3u);
EXPECT_EQ(vec_123->args[0], scalar_1);
EXPECT_EQ(vec_123->args[1], scalar_2);
EXPECT_EQ(vec_123->args[2], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 3u);
+ ASSERT_EQ(call->Arguments().Length(), 3u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
@@ -319,7 +319,7 @@ TEST_F(AppendVectorTest, Vec2i32_i32Var) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 3u);
+ ASSERT_EQ(ctor->Parameters().Length(), 3u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
@@ -327,8 +327,8 @@ TEST_F(AppendVectorTest, Vec2i32_i32Var) {
// AppendVector(vec_12, scalar_3) -> vec3<i32>(vec_12, scalar_3)
TEST_F(AppendVectorTest, Vec2i32Var_i32Var) {
- Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
- Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr("scalar_3");
WrapInFunction(vec_12, scalar_3);
@@ -340,13 +340,13 @@ TEST_F(AppendVectorTest, Vec2i32Var_i32Var) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 2u);
+ ASSERT_EQ(vec_123->args.Length(), 2u);
EXPECT_EQ(vec_123->args[0], vec_12);
EXPECT_EQ(vec_123->args[1], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 2u);
+ ASSERT_EQ(call->Arguments().Length(), 2u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
@@ -357,15 +357,15 @@ TEST_F(AppendVectorTest, Vec2i32Var_i32Var) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
}
// AppendVector(vec_12, scalar_3) -> vec3<i32>(vec_12, i32(scalar_3))
TEST_F(AppendVectorTest, Vec2i32Var_f32Var) {
- Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
- Global("scalar_3", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("scalar_3", ty.f32(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr("scalar_3");
WrapInFunction(vec_12, scalar_3);
@@ -377,17 +377,17 @@ TEST_F(AppendVectorTest, Vec2i32Var_f32Var) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 2u);
+ ASSERT_EQ(vec_123->args.Length(), 2u);
EXPECT_EQ(vec_123->args[0], vec_12);
auto* f32_to_i32 = vec_123->args[1]->As<ast::CallExpression>();
ASSERT_NE(f32_to_i32, nullptr);
EXPECT_TRUE(f32_to_i32->target.type->Is<ast::I32>());
- ASSERT_EQ(f32_to_i32->args.size(), 1u);
+ ASSERT_EQ(f32_to_i32->args.Length(), 1u);
EXPECT_EQ(f32_to_i32->args[0], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 2u);
+ ASSERT_EQ(call->Arguments().Length(), 2u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
EXPECT_EQ(call->Arguments()[1], Sem().Get(f32_to_i32));
@@ -398,15 +398,15 @@ TEST_F(AppendVectorTest, Vec2i32Var_f32Var) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
}
// AppendVector(vec_12, scalar_3) -> vec3<bool>(vec_12, scalar_3)
TEST_F(AppendVectorTest, Vec2boolVar_boolVar) {
- Global("vec_12", ty.vec2<bool>(), ast::StorageClass::kPrivate);
- Global("scalar_3", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("vec_12", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("scalar_3", ty.bool_(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr("scalar_3");
WrapInFunction(vec_12, scalar_3);
@@ -418,13 +418,13 @@ TEST_F(AppendVectorTest, Vec2boolVar_boolVar) {
auto* vec_123 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_123, nullptr);
- ASSERT_EQ(vec_123->args.size(), 2u);
+ ASSERT_EQ(vec_123->args.Length(), 2u);
EXPECT_EQ(vec_123->args[0], vec_12);
EXPECT_EQ(vec_123->args[1], scalar_3);
auto* call = Sem().Get<sem::Call>(vec_123);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 2u);
+ ASSERT_EQ(call->Arguments().Length(), 2u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
@@ -435,7 +435,7 @@ TEST_F(AppendVectorTest, Vec2boolVar_boolVar) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 2u);
+ ASSERT_EQ(ctor->Parameters().Length(), 2u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
}
@@ -453,7 +453,7 @@ TEST_F(AppendVectorTest, ZeroVec3i32_i32) {
auto* vec_0004 = As<ast::CallExpression>(append->Declaration());
ASSERT_NE(vec_0004, nullptr);
- ASSERT_EQ(vec_0004->args.size(), 4u);
+ ASSERT_EQ(vec_0004->args.Length(), 4u);
for (size_t i = 0; i < 3; i++) {
auto* literal = As<ast::IntLiteralExpression>(vec_0004->args[i]);
ASSERT_NE(literal, nullptr);
@@ -463,7 +463,7 @@ TEST_F(AppendVectorTest, ZeroVec3i32_i32) {
auto* call = Sem().Get<sem::Call>(vec_0004);
ASSERT_NE(call, nullptr);
- ASSERT_EQ(call->Arguments().size(), 4u);
+ ASSERT_EQ(call->Arguments().Length(), 4u);
EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_0004->args[0]));
EXPECT_EQ(call->Arguments()[1], Sem().Get(vec_0004->args[1]));
EXPECT_EQ(call->Arguments()[2], Sem().Get(vec_0004->args[2]));
@@ -476,7 +476,7 @@ TEST_F(AppendVectorTest, ZeroVec3i32_i32) {
EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
EXPECT_EQ(ctor->ReturnType(), call->Type());
- ASSERT_EQ(ctor->Parameters().size(), 4u);
+ ASSERT_EQ(ctor->Parameters().Length(), 4u);
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
diff --git a/chromium/third_party/dawn/src/tint/writer/flatten_bindings_test.cc b/chromium/third_party/dawn/src/tint/writer/flatten_bindings_test.cc
index 1c516c92e5f..be5fb423c63 100644
--- a/chromium/third_party/dawn/src/tint/writer/flatten_bindings_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/flatten_bindings_test.cc
@@ -28,7 +28,6 @@ class FlattenBindingsTest : public ::testing::Test {};
TEST_F(FlattenBindingsTest, NoBindings) {
ProgramBuilder b;
- b.WrapInFunction();
resolver::Resolver resolver(&b);
@@ -41,10 +40,9 @@ TEST_F(FlattenBindingsTest, NoBindings) {
TEST_F(FlattenBindingsTest, AlreadyFlat) {
ProgramBuilder b;
- b.Global("a", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
- b.Global("b", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 1));
- b.Global("c", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 2));
- b.WrapInFunction();
+ b.GlobalVar("a", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ b.GlobalVar("b", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 1));
+ b.GlobalVar("c", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 2));
resolver::Resolver resolver(&b);
@@ -57,9 +55,9 @@ TEST_F(FlattenBindingsTest, AlreadyFlat) {
TEST_F(FlattenBindingsTest, NotFlat_SingleNamespace) {
ProgramBuilder b;
- b.Global("a", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
- b.Global("b", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(1, 1));
- b.Global("c", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(2, 2));
+ b.GlobalVar("a", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ b.GlobalVar("b", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(1, 1));
+ b.GlobalVar("c", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(2, 2));
b.WrapInFunction(b.Expr("a"), b.Expr("b"), b.Expr("c"));
resolver::Resolver resolver(&b);
@@ -83,29 +81,30 @@ TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) {
ProgramBuilder b;
const size_t num_buffers = 3;
- b.Global("buffer1", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
- b.Global("buffer2", b.ty.i32(), ast::StorageClass::kStorage, b.GroupAndBinding(1, 1));
- b.Global("buffer3", b.ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
- b.GroupAndBinding(2, 2));
+ b.GlobalVar("buffer1", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+ b.GlobalVar("buffer2", b.ty.i32(), ast::StorageClass::kStorage, b.GroupAndBinding(1, 1));
+ b.GlobalVar("buffer3", b.ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
+ b.GroupAndBinding(2, 2));
const size_t num_samplers = 2;
- b.Global("sampler1", b.ty.sampler(ast::SamplerKind::kSampler), b.GroupAndBinding(3, 3));
- b.Global("sampler2", b.ty.sampler(ast::SamplerKind::kComparisonSampler),
- b.GroupAndBinding(4, 4));
+ b.GlobalVar("sampler1", b.ty.sampler(ast::SamplerKind::kSampler), b.GroupAndBinding(3, 3));
+ b.GlobalVar("sampler2", b.ty.sampler(ast::SamplerKind::kComparisonSampler),
+ b.GroupAndBinding(4, 4));
const size_t num_textures = 6;
- b.Global("texture1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
- b.GroupAndBinding(5, 5));
- b.Global("texture2", b.ty.multisampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
- b.GroupAndBinding(6, 6));
- b.Global("texture3",
- b.ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
- ast::Access::kWrite),
- b.GroupAndBinding(7, 7));
- b.Global("texture4", b.ty.depth_texture(ast::TextureDimension::k2d), b.GroupAndBinding(8, 8));
- b.Global("texture5", b.ty.depth_multisampled_texture(ast::TextureDimension::k2d),
- b.GroupAndBinding(9, 9));
- b.Global("texture6", b.ty.external_texture(), b.GroupAndBinding(10, 10));
+ b.GlobalVar("texture1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
+ b.GroupAndBinding(5, 5));
+ b.GlobalVar("texture2", b.ty.multisampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
+ b.GroupAndBinding(6, 6));
+ b.GlobalVar("texture3",
+ b.ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+ ast::Access::kWrite),
+ b.GroupAndBinding(7, 7));
+ b.GlobalVar("texture4", b.ty.depth_texture(ast::TextureDimension::k2d),
+ b.GroupAndBinding(8, 8));
+ b.GlobalVar("texture5", b.ty.depth_multisampled_texture(ast::TextureDimension::k2d),
+ b.GroupAndBinding(9, 9));
+ b.GlobalVar("texture6", b.ty.external_texture(), b.GroupAndBinding(10, 10));
b.WrapInFunction(b.Assign(b.Phony(), "buffer1"), b.Assign(b.Phony(), "buffer2"),
b.Assign(b.Phony(), "buffer3"), b.Assign(b.Phony(), "sampler1"),
diff --git a/chromium/third_party/dawn/src/tint/writer/float_to_string_test.cc b/chromium/third_party/dawn/src/tint/writer/float_to_string_test.cc
index 2596be79982..b629b50dc75 100644
--- a/chromium/third_party/dawn/src/tint/writer/float_to_string_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/float_to_string_test.cc
@@ -27,7 +27,7 @@ namespace {
// - 0 sign if sign is 0, 1 otherwise
// - 'exponent_bits' is placed in the exponent space.
// So, the exponent bias must already be included.
-float MakeFloat(int sign, int biased_exponent, int mantissa) {
+float MakeFloat(uint32_t sign, uint32_t biased_exponent, uint32_t mantissa) {
const uint32_t sign_bit = sign ? 0x80000000u : 0u;
// The binary32 exponent is 8 bits, just below the sign.
const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
diff --git a/chromium/third_party/dawn/src/tint/writer/generate_external_texture_bindings_test.cc b/chromium/third_party/dawn/src/tint/writer/generate_external_texture_bindings_test.cc
index d0918c322d3..ee3fc4758a8 100644
--- a/chromium/third_party/dawn/src/tint/writer/generate_external_texture_bindings_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/generate_external_texture_bindings_test.cc
@@ -27,7 +27,6 @@ class GenerateExternalTextureBindingsTest : public ::testing::Test {};
TEST_F(GenerateExternalTextureBindingsTest, None) {
ProgramBuilder b;
- b.WrapInFunction();
tint::Program program(std::move(b));
ASSERT_TRUE(program.IsValid());
@@ -37,8 +36,7 @@ TEST_F(GenerateExternalTextureBindingsTest, None) {
TEST_F(GenerateExternalTextureBindingsTest, One) {
ProgramBuilder b;
- b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
- b.WrapInFunction();
+ b.GlobalVar("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
tint::Program program(std::move(b));
ASSERT_TRUE(program.IsValid());
@@ -54,9 +52,8 @@ TEST_F(GenerateExternalTextureBindingsTest, One) {
TEST_F(GenerateExternalTextureBindingsTest, Two_SameGroup) {
ProgramBuilder b;
- b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
- b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
- b.WrapInFunction();
+ b.GlobalVar("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
+ b.GlobalVar("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
tint::Program program(std::move(b));
ASSERT_TRUE(program.IsValid());
@@ -78,9 +75,8 @@ TEST_F(GenerateExternalTextureBindingsTest, Two_SameGroup) {
TEST_F(GenerateExternalTextureBindingsTest, Two_DifferentGroup) {
ProgramBuilder b;
- b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
- b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(1, 0));
- b.WrapInFunction();
+ b.GlobalVar("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
+ b.GlobalVar("v1", b.ty.external_texture(), b.GroupAndBinding(1, 0));
tint::Program program(std::move(b));
ASSERT_TRUE(program.IsValid());
@@ -102,12 +98,11 @@ TEST_F(GenerateExternalTextureBindingsTest, Two_DifferentGroup) {
TEST_F(GenerateExternalTextureBindingsTest, Two_WithOtherBindingsInSameGroup) {
ProgramBuilder b;
- b.Global("v0", b.ty.i32(), b.GroupAndBinding(0, 0), kUniform);
- b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
- b.Global("v2", b.ty.i32(), b.GroupAndBinding(0, 2), kUniform);
- b.Global("v3", b.ty.external_texture(), b.GroupAndBinding(0, 3));
- b.Global("v4", b.ty.i32(), b.GroupAndBinding(0, 4), kUniform);
- b.WrapInFunction();
+ b.GlobalVar("v0", b.ty.i32(), b.GroupAndBinding(0, 0), kUniform);
+ b.GlobalVar("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
+ b.GlobalVar("v2", b.ty.i32(), b.GroupAndBinding(0, 2), kUniform);
+ b.GlobalVar("v3", b.ty.external_texture(), b.GroupAndBinding(0, 3));
+ b.GlobalVar("v4", b.ty.i32(), b.GroupAndBinding(0, 4), kUniform);
tint::Program program(std::move(b));
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.cc
index e07139bc8e2..c66e1744b9a 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.cc
@@ -58,7 +58,7 @@
#include "src/tint/transform/fold_trivial_single_use_lets.h"
#include "src/tint/transform/loop_to_for_loop.h"
#include "src/tint/transform/manager.h"
-#include "src/tint/transform/promote_initializers_to_const_var.h"
+#include "src/tint/transform/promote_initializers_to_let.h"
#include "src/tint/transform/promote_side_effects_to_decl.h"
#include "src/tint/transform/remove_phonies.h"
#include "src/tint/transform/renamer.h"
@@ -70,6 +70,7 @@
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/string.h"
#include "src/tint/writer/append_vector.h"
#include "src/tint/writer/float_to_string.h"
#include "src/tint/writer/generate_external_texture_bindings.h"
@@ -85,10 +86,10 @@ bool IsRelational(tint::ast::BinaryOp op) {
op == tint::ast::BinaryOp::kGreaterThanEqual;
}
-bool RequiresOESSampleVariables(tint::ast::Builtin builtin) {
+bool RequiresOESSampleVariables(tint::ast::BuiltinValue builtin) {
switch (builtin) {
- case tint::ast::Builtin::kSampleIndex:
- case tint::ast::Builtin::kSampleMask:
+ case tint::ast::BuiltinValue::kSampleIndex:
+ case tint::ast::BuiltinValue::kSampleMask:
return true;
default:
return false;
@@ -141,7 +142,7 @@ const char* convert_texel_format_to_glsl(const ast::TexelFormat format) {
return "rgba32i";
case ast::TexelFormat::kRgba32Float:
return "rgba32f";
- case ast::TexelFormat::kNone:
+ case ast::TexelFormat::kInvalid:
return "unknown";
}
return "unknown";
@@ -159,6 +160,17 @@ void PrintF32(std::ostream& out, float value) {
}
}
+bool PrintF16(std::ostream& out, float value) {
+ // Note: Currently inf and nan should not be constructable, and there is no solid way to
+ // generate constant/literal f16 Inf or NaN.
+ if (std::isinf(value) || std::isnan(value)) {
+ return false;
+ } else {
+ out << FloatToString(value) << "hf";
+ return true;
+ }
+}
+
} // namespace
SanitizedResult::SanitizedResult() = default;
@@ -175,6 +187,8 @@ SanitizedResult Sanitize(const Program* in,
{ // Builtin polyfills
transform::BuiltinPolyfill::Builtins polyfills;
+ polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
+ polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
polyfills.count_leading_zeros = true;
polyfills.count_trailing_zeros = true;
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
@@ -226,7 +240,7 @@ SanitizedResult Sanitize(const Program* in,
options.binding_points, options.access_controls, options.allow_collisions);
manager.Add<transform::BindingRemapper>();
- manager.Add<transform::PromoteInitializersToConstVar>();
+ manager.Add<transform::PromoteInitializersToLet>();
manager.Add<transform::AddEmptyEntryPoint>();
manager.Add<transform::AddSpirvBlockAttribute>();
data.Add<transform::CanonicalizeEntryPointIO::Config>(
@@ -259,8 +273,8 @@ bool GeneratorImpl::Generate() {
auto* mod = builder_.Sem().Module();
for (auto* decl : mod->DependencyOrderedDeclarations()) {
- if (decl->Is<ast::Alias>()) {
- continue; // Ignore aliases.
+ if (decl->IsAnyOf<ast::Alias, ast::StaticAssert>()) {
+ continue; // These are not emitted.
}
if (auto* global = decl->As<ast::Variable>()) {
@@ -311,6 +325,10 @@ bool GeneratorImpl::Generate() {
extensions.Append("#extension GL_OES_sample_variables : require");
}
+ if (requires_f16_extension_) {
+ extensions.Append("#extension GL_AMD_gpu_shader_half_float : require");
+ }
+
auto indent = current_buffer_->current_indent;
if (!extensions.lines.empty()) {
@@ -331,17 +349,12 @@ bool GeneratorImpl::Generate() {
return true;
}
-bool GeneratorImpl::RecordExtension(const ast::Enable*) {
- /*
- Deal with extension node here, recording it within the generator for
- later emition.
- For example:
- ```
- if (ext->kind == ast::Enable::ExtensionKind::kF16) {
- require_fp16_ = true;
- }
- ```
- */
+bool GeneratorImpl::RecordExtension(const ast::Enable* ext) {
+ // Deal with extension node here, recording it within the generator for later emition.
+
+ if (ext->extension == ast::Extension::kF16) {
+ requires_f16_extension_ = true;
+ }
return true;
}
@@ -388,11 +401,10 @@ bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression*
return false;
}
}
- out << "(";
+ ScopedParen sp(out);
if (!EmitExpression(out, expr->expr)) {
return false;
}
- out << ")";
return true;
}
@@ -432,7 +444,7 @@ bool GeneratorImpl::EmitVectorRelational(std::ostream& out, const ast::BinaryExp
default:
break;
}
- out << "(";
+ ScopedParen sp(out);
if (!EmitExpression(out, expr->lhs)) {
return false;
}
@@ -440,7 +452,6 @@ bool GeneratorImpl::EmitVectorRelational(std::ostream& out, const ast::BinaryExp
if (!EmitExpression(out, expr->rhs)) {
return false;
}
- out << ")";
return true;
}
@@ -490,42 +501,45 @@ bool GeneratorImpl::EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpres
bool GeneratorImpl::EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr) {
std::string fn;
auto* ret_ty = TypeOf(expr)->UnwrapRef();
- fn = utils::GetOrCreate(float_modulo_funcs_, ret_ty, [&]() -> std::string {
- TextBuffer b;
- TINT_DEFER(helpers_.Append(b));
-
- auto fn_name = UniqueIdentifier("tint_float_modulo");
- std::vector<std::string> parameter_names;
- {
- auto decl = line(&b);
- if (!EmitTypeAndName(decl, ret_ty, ast::StorageClass::kNone, ast::Access::kUndefined,
- fn_name)) {
- return "";
- }
- {
- ScopedParen sp(decl);
- const auto* ty = TypeOf(expr->lhs)->UnwrapRef();
- if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone, ast::Access::kUndefined,
- "lhs")) {
- return "";
- }
- decl << ", ";
- ty = TypeOf(expr->rhs)->UnwrapRef();
- if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone, ast::Access::kUndefined,
- "rhs")) {
- return "";
- }
- }
- decl << " {";
- }
- {
- ScopedIndent si(&b);
- line(&b) << "return (lhs - rhs * trunc(lhs / rhs));";
- }
- line(&b) << "}";
- line(&b);
- return fn_name;
- });
+ auto* lhs_ty = TypeOf(expr->lhs)->UnwrapRef();
+ auto* rhs_ty = TypeOf(expr->rhs)->UnwrapRef();
+ fn = utils::GetOrCreate(float_modulo_funcs_, BinaryOperandType{{lhs_ty, rhs_ty}},
+ [&]() -> std::string {
+ TextBuffer b;
+ TINT_DEFER(helpers_.Append(b));
+
+ auto fn_name = UniqueIdentifier("tint_float_modulo");
+ std::vector<std::string> parameter_names;
+ {
+ auto decl = line(&b);
+ if (!EmitTypeAndName(decl, ret_ty, ast::StorageClass::kNone,
+ ast::Access::kUndefined, fn_name)) {
+ return "";
+ }
+ {
+ ScopedParen sp(decl);
+ const auto* ty = TypeOf(expr->lhs)->UnwrapRef();
+ if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
+ ast::Access::kUndefined, "lhs")) {
+ return "";
+ }
+ decl << ", ";
+ ty = TypeOf(expr->rhs)->UnwrapRef();
+ if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
+ ast::Access::kUndefined, "rhs")) {
+ return "";
+ }
+ }
+ decl << " {";
+ }
+ {
+ ScopedIndent si(&b);
+ line(&b) << "return (lhs - rhs * trunc(lhs / rhs));";
+ }
+ line(&b) << "}";
+ line(&b);
+ return fn_name;
+ });
if (fn.empty()) {
return false;
@@ -594,7 +608,7 @@ bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* e
return EmitFloatModulo(out, expr);
}
- out << "(";
+ ScopedParen sp(out);
if (!EmitExpression(out, expr->lhs)) {
return false;
}
@@ -670,11 +684,10 @@ bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* e
return false;
}
- out << ")";
return true;
}
-bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatements(utils::VectorRef<const ast::Statement*> stmts) {
for (auto* s : stmts) {
if (!EmitStatement(s)) {
return false;
@@ -683,7 +696,7 @@ bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
return true;
}
-bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts) {
ScopedIndent si(this);
return EmitStatements(stmts);
}
@@ -730,7 +743,8 @@ bool GeneratorImpl::EmitFunctionCall(std::ostream& out, const sem::Call* call) {
auto name = builder_.Symbols().NameFor(ident->symbol);
auto caller_sym = ident->symbol;
- out << name << "(";
+ out << name;
+ ScopedParen sp(out);
bool first = true;
for (auto* arg : args) {
@@ -744,7 +758,6 @@ bool GeneratorImpl::EmitFunctionCall(std::ostream& out, const sem::Call* call) {
}
}
- out << ")";
return true;
}
@@ -809,7 +822,8 @@ bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
return false;
}
- out << name << "(";
+ out << name;
+ ScopedParen sp(out);
bool first = true;
for (auto* arg : call->Arguments()) {
@@ -823,7 +837,6 @@ bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
}
}
- out << ")";
return true;
}
@@ -833,13 +846,12 @@ bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
if (!EmitType(out, conv->Target(), ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
return false;
}
- out << "(";
+ ScopedParen sp(out);
if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
return false;
}
- out << ")";
return true;
}
@@ -850,19 +862,14 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
// If the type constructor is empty then we need to construct with the zero
// value for all components.
- if (call->Arguments().empty()) {
+ if (call->Arguments().IsEmpty()) {
return EmitZeroValue(out, type);
}
- auto it = structure_builders_.find(As<sem::Struct>(type));
- if (it != structure_builders_.end()) {
- out << it->second << "(";
- } else {
- if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
- return false;
- }
- out << "(";
+ if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+ return false;
}
+ ScopedParen sp(out);
bool first = true;
for (auto* arg : call->Arguments()) {
@@ -876,7 +883,6 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
}
}
- out << ")";
return true;
}
@@ -887,7 +893,7 @@ bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
out << name;
{
ScopedParen sp(out);
- for (size_t i = 0; i < expr->args.size(); i++) {
+ for (size_t i = 0; i < expr->args.Length(); i++) {
auto* arg = expr->args[i];
if (i > 0) {
out << ", ";
@@ -1183,7 +1189,9 @@ bool GeneratorImpl::EmitDotCall(std::ostream& out,
}
}
- out << fn << "(";
+ out << fn;
+ ScopedParen sp(out);
+
if (!EmitExpression(out, expr->args[0])) {
return false;
}
@@ -1191,104 +1199,57 @@ bool GeneratorImpl::EmitDotCall(std::ostream& out,
if (!EmitExpression(out, expr->args[1])) {
return false;
}
- out << ")";
return true;
}
bool GeneratorImpl::EmitModfCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
- if (expr->args.size() == 1) {
- return CallBuiltinHelper(
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- // Emit the builtin return type unique to this overload. This does not
- // exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
- return false;
- }
+ TINT_ASSERT(Writer, expr->args.Length() == 1);
+ return CallBuiltinHelper(
+ out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+ // Emit the builtin return type unique to this overload. This does not
+ // exist in the AST, so it will not be generated in Generate().
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ return false;
+ }
- {
- auto l = line(b);
- if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
- ast::Access::kUndefined, "")) {
- return false;
- }
- l << " result;";
+ {
+ auto l = line(b);
+ if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
+ ast::Access::kUndefined, "")) {
+ return false;
}
- line(b) << "result.fract = modf(" << params[0] << ", result.whole);";
- line(b) << "return result;";
- return true;
- });
- }
-
- // DEPRECATED
- out << "modf";
- ScopedParen sp(out);
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, expr->args[1])) {
- return false;
- }
- return true;
+ l << " result;";
+ }
+ line(b) << "result.fract = modf(" << params[0] << ", result.whole);";
+ line(b) << "return result;";
+ return true;
+ });
}
bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
- if (expr->args.size() == 1) {
- return CallBuiltinHelper(
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- // Emit the builtin return type unique to this overload. This does not
- // exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
- return false;
- }
-
- {
- auto l = line(b);
- if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
- ast::Access::kUndefined, "")) {
- return false;
- }
- l << " result;";
- }
- line(b) << "result.sig = frexp(" << params[0] << ", result.exp);";
- line(b) << "return result;";
- return true;
- });
- }
- // DEPRECATED
- // Exponent is an integer in WGSL, but HLSL wants a float.
- // We need to make the call with a temporary float, and then cast.
+ TINT_ASSERT(Writer, expr->args.Length() == 1);
return CallBuiltinHelper(
out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- auto* significand_ty = builtin->Parameters()[0]->Type();
- auto significand = params[0];
- auto* exponent_ty = builtin->Parameters()[1]->Type();
- auto exponent = params[1];
-
- std::string width;
- if (auto* vec = significand_ty->As<sem::Vector>()) {
- width = std::to_string(vec->Width());
+ // Emit the builtin return type unique to this overload. This does not
+ // exist in the AST, so it will not be generated in Generate().
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ return false;
}
- // Exponent is an integer, which HLSL does not have an overload for.
- // We need to cast from a float.
- line(b) << "float" << width << " float_exp;";
- line(b) << "float" << width << " significand = frexp(" << significand
- << ", float_exp);";
{
auto l = line(b);
- l << exponent << " = ";
- if (!EmitType(l, exponent_ty->UnwrapPtr(), ast::StorageClass::kNone,
+ if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
ast::Access::kUndefined, "")) {
return false;
}
- l << "(float_exp);";
+ l << " result;";
}
- line(b) << "return significand;";
+ line(b) << "result.sig = frexp(" << params[0] << ", result.exp);";
+ line(b) << "return result;";
return true;
});
}
@@ -1296,10 +1257,12 @@ bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
+ auto* return_elem_type = sem::Type::DeepestElementOf(builtin->ReturnType());
+ const std::string suffix = Is<sem::F16>(return_elem_type) ? "hf" : "f";
return CallBuiltinHelper(out, expr, builtin,
[&](TextBuffer* b, const std::vector<std::string>& params) {
line(b) << "return " << params[0] << " * " << std::setprecision(20)
- << sem::kRadToDeg << ";";
+ << sem::kRadToDeg << suffix << ";";
return true;
});
}
@@ -1307,10 +1270,12 @@ bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
+ auto* return_elem_type = sem::Type::DeepestElementOf(builtin->ReturnType());
+ const std::string suffix = Is<sem::F16>(return_elem_type) ? "hf" : "f";
return CallBuiltinHelper(out, expr, builtin,
[&](TextBuffer* b, const std::vector<std::string>& params) {
line(b) << "return " << params[0] << " * " << std::setprecision(20)
- << sem::kDegToRad << ";";
+ << sem::kDegToRad << suffix << ";";
return true;
});
}
@@ -1333,7 +1298,8 @@ bool GeneratorImpl::EmitBarrierCall(std::ostream& out, const sem::Builtin* built
const ast::Expression* GeneratorImpl::CreateF32Zero(const sem::Statement* stmt) {
auto* zero = builder_.Expr(0_f);
auto* f32 = builder_.create<sem::F32>();
- auto* sem_zero = builder_.create<sem::Expression>(zero, f32, stmt, sem::Constant{},
+ auto* sem_zero = builder_.create<sem::Expression>(zero, f32, sem::EvaluationStage::kRuntime,
+ stmt, /* constant_value */ nullptr,
/* has_side_effects */ false);
builder_.Sem().Add(zero, sem_zero);
return zero;
@@ -1350,8 +1316,8 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
// Returns the argument with the given usage
auto arg = [&](Usage usage) {
- int idx = signature.IndexOf(usage);
- return (idx >= 0) ? arguments[idx] : nullptr;
+ auto idx = signature.IndexOf(usage);
+ return (idx >= 0) ? arguments[static_cast<size_t>(idx)] : nullptr;
};
auto* texture = arg(Usage::kTexture);
@@ -1608,10 +1574,13 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
switch (builtin->Type()) {
case sem::BuiltinType::kAbs:
case sem::BuiltinType::kAcos:
+ case sem::BuiltinType::kAcosh:
case sem::BuiltinType::kAll:
case sem::BuiltinType::kAny:
case sem::BuiltinType::kAsin:
+ case sem::BuiltinType::kAsinh:
case sem::BuiltinType::kAtan:
+ case sem::BuiltinType::kAtanh:
case sem::BuiltinType::kCeil:
case sem::BuiltinType::kClamp:
case sem::BuiltinType::kCos:
@@ -1701,7 +1670,6 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
case sem::BuiltinType::kReverseBits:
return "bitfieldReverse";
case sem::BuiltinType::kSmoothstep:
- case sem::BuiltinType::kSmoothStep:
return "smoothstep";
case sem::BuiltinType::kUnpack2x16float:
return "unpackHalf2x16";
@@ -1732,7 +1700,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
return false;
}
out << ":";
- if (selector == stmt->selectors.back()) {
+ if (selector == stmt->selectors.Back()) {
out << " {";
}
}
@@ -1754,7 +1722,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
}
bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
- if (!emit_continuing_()) {
+ if (!emit_continuing_ || !emit_continuing_()) {
return false;
}
line() << "continue;";
@@ -1770,7 +1738,7 @@ bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().Get(expr)) {
- if (auto constant = sem->ConstantValue()) {
+ if (auto* constant = sem->ConstantValue()) {
return EmitConstant(out, constant);
}
}
@@ -1833,7 +1801,7 @@ bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
return false;
}
} else {
- if (!EmitStatementsWithIndent({stmt->else_statement})) {
+ if (!EmitStatementsWithIndent(utils::Vector{stmt->else_statement})) {
return false;
}
}
@@ -1905,42 +1873,56 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
}
bool GeneratorImpl::EmitGlobalVariable(const ast::Variable* global) {
- if (global->is_const) {
- return EmitProgramConstVariable(global);
- }
-
- auto* sem = builder_.Sem().Get(global);
- switch (sem->StorageClass()) {
- case ast::StorageClass::kUniform:
- return EmitUniformVariable(sem);
- case ast::StorageClass::kStorage:
- return EmitStorageVariable(sem);
- case ast::StorageClass::kHandle:
- return EmitHandleVariable(sem);
- case ast::StorageClass::kPrivate:
- return EmitPrivateVariable(sem);
- case ast::StorageClass::kWorkgroup:
- return EmitWorkgroupVariable(sem);
- case ast::StorageClass::kInput:
- case ast::StorageClass::kOutput:
- return EmitIOVariable(sem);
- default:
- break;
- }
-
- TINT_ICE(Writer, diagnostics_) << "unhandled storage class " << sem->StorageClass();
- return false;
+ return Switch(
+ global, //
+ [&](const ast::Var* var) {
+ auto* sem = builder_.Sem().Get(global);
+ switch (sem->StorageClass()) {
+ case ast::StorageClass::kUniform:
+ return EmitUniformVariable(var, sem);
+ case ast::StorageClass::kStorage:
+ return EmitStorageVariable(var, sem);
+ case ast::StorageClass::kHandle:
+ return EmitHandleVariable(var, sem);
+ case ast::StorageClass::kPrivate:
+ return EmitPrivateVariable(sem);
+ case ast::StorageClass::kWorkgroup:
+ return EmitWorkgroupVariable(sem);
+ case ast::StorageClass::kIn:
+ case ast::StorageClass::kOut:
+ return EmitIOVariable(sem);
+ case ast::StorageClass::kPushConstant:
+ diagnostics_.add_error(
+ diag::System::Writer,
+ "unhandled storage class " + utils::ToString(sem->StorageClass()));
+ return false;
+ default: {
+ TINT_ICE(Writer, diagnostics_)
+ << "unhandled storage class " << sem->StorageClass();
+ return false;
+ }
+ }
+ },
+ [&](const ast::Let* let) { return EmitProgramConstVariable(let); },
+ [&](const ast::Override* override) { return EmitOverride(override); },
+ [&](const ast::Const*) {
+ return true; // Constants are embedded at their use
+ },
+ [&](Default) {
+ TINT_ICE(Writer, diagnostics_)
+ << "unhandled global variable type " << global->TypeInfo().name;
+ return false;
+ });
}
-bool GeneratorImpl::EmitUniformVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
- auto* type = var->Type()->UnwrapRef();
+bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) {
+ auto* type = sem->Type()->UnwrapRef();
auto* str = type->As<sem::Struct>();
if (!str) {
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
return false;
}
- ast::VariableBindingPoint bp = decl->BindingPoint();
+ ast::VariableBindingPoint bp = var->BindingPoint();
{
auto out = line();
out << "layout(binding = " << bp.binding->value;
@@ -1950,36 +1932,34 @@ bool GeneratorImpl::EmitUniformVariable(const sem::Variable* var) {
out << ") uniform " << UniqueIdentifier(StructName(str)) << " {";
}
EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
- auto name = builder_.Symbols().NameFor(decl->symbol);
+ auto name = builder_.Symbols().NameFor(var->symbol);
line() << "} " << name << ";";
line();
return true;
}
-bool GeneratorImpl::EmitStorageVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
- auto* type = var->Type()->UnwrapRef();
+bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable* sem) {
+ auto* type = sem->Type()->UnwrapRef();
auto* str = type->As<sem::Struct>();
if (!str) {
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
return false;
}
- ast::VariableBindingPoint bp = decl->BindingPoint();
+ ast::VariableBindingPoint bp = var->BindingPoint();
line() << "layout(binding = " << bp.binding->value << ", std430) buffer "
<< UniqueIdentifier(StructName(str)) << " {";
EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
- auto name = builder_.Symbols().NameFor(decl->symbol);
+ auto name = builder_.Symbols().NameFor(var->symbol);
line() << "} " << name << ";";
return true;
}
-bool GeneratorImpl::EmitHandleVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
+bool GeneratorImpl::EmitHandleVariable(const ast::Var* var, const sem::Variable* sem) {
auto out = line();
- auto name = builder_.Symbols().NameFor(decl->symbol);
- auto* type = var->Type()->UnwrapRef();
+ auto name = builder_.Symbols().NameFor(var->symbol);
+ auto* type = sem->Type()->UnwrapRef();
if (type->Is<sem::Sampler>()) {
// GLSL ignores Sampler variables.
return true;
@@ -1987,7 +1967,7 @@ bool GeneratorImpl::EmitHandleVariable(const sem::Variable* var) {
if (auto* storage = type->As<sem::StorageTexture>()) {
out << "layout(" << convert_texel_format_to_glsl(storage->texel_format()) << ") ";
}
- if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+ if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(), name)) {
return false;
}
@@ -2076,8 +2056,9 @@ bool GeneratorImpl::EmitIOVariable(const sem::Variable* var) {
return true;
}
-void GeneratorImpl::EmitInterpolationQualifiers(std::ostream& out,
- const ast::AttributeList& attributes) {
+void GeneratorImpl::EmitInterpolationQualifiers(
+ std::ostream& out,
+ utils::VectorRef<const ast::Attribute*> attributes) {
for (auto* attr : attributes) {
if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
switch (interpolate->type) {
@@ -2101,8 +2082,9 @@ void GeneratorImpl::EmitInterpolationQualifiers(std::ostream& out,
}
}
-bool GeneratorImpl::EmitAttributes(std::ostream& out, const ast::AttributeList& attributes) {
- if (attributes.empty()) {
+bool GeneratorImpl::EmitAttributes(std::ostream& out,
+ utils::VectorRef<const ast::Attribute*> attributes) {
+ if (attributes.IsEmpty()) {
return true;
}
bool first = true;
@@ -2131,7 +2113,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
// Emit the layout(local_size) attributes.
auto wgsize = func_sem->WorkgroupSize();
out << "layout(";
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (i > 0) {
out << ", ";
}
@@ -2139,11 +2121,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
if (wgsize[i].overridable_const) {
auto* global = builder_.Sem().Get<sem::GlobalVariable>(wgsize[i].overridable_const);
- if (!global->IsOverridable()) {
+ if (!global->Declaration()->Is<ast::Override>()) {
TINT_ICE(Writer, builder_.Diagnostics())
<< "expected a pipeline-overridable constant";
}
- out << kSpecConstantPrefix << global->ConstantId();
+ out << kSpecConstantPrefix << global->OverrideId().value;
} else {
out << std::to_string(wgsize[i].value);
}
@@ -2195,7 +2177,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
}
if (!Is<ast::ReturnStatement>(func->body->Last())) {
- ast::ReturnStatement ret(ProgramID(), Source{});
+ ast::ReturnStatement ret(ProgramID{}, ast::NodeID{}, Source{});
if (!EmitStatement(&ret)) {
return false;
}
@@ -2207,90 +2189,104 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
return true;
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant& constant) {
- auto emit_bool = [&](size_t element_idx) {
- out << (constant.Element<AInt>(element_idx) ? "true" : "false");
- return true;
- };
- auto emit_f32 = [&](size_t element_idx) {
- PrintF32(out, static_cast<float>(constant.Element<AFloat>(element_idx)));
- return true;
- };
- auto emit_i32 = [&](size_t element_idx) {
- out << constant.Element<AInt>(element_idx).value;
- return true;
- };
- auto emit_u32 = [&](size_t element_idx) {
- out << constant.Element<AInt>(element_idx).value << "u";
- return true;
- };
- auto emit_vector = [&](const sem::Vector* vec_ty, size_t start, size_t end) {
- if (!EmitType(out, vec_ty, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
- return false;
- }
+bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constant) {
+ return Switch(
+ constant->Type(), //
+ [&](const sem::Bool*) {
+ out << (constant->As<AInt>() ? "true" : "false");
+ return true;
+ },
+ [&](const sem::F32*) {
+ PrintF32(out, constant->As<float>());
+ return true;
+ },
+ [&](const sem::F16*) { return PrintF16(out, constant->As<float>()); },
+ [&](const sem::I32*) {
+ out << constant->As<AInt>();
+ return true;
+ },
+ [&](const sem::U32*) {
+ out << constant->As<AInt>() << "u";
+ return true;
+ },
+ [&](const sem::Vector* v) {
+ if (!EmitType(out, v, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+ return false;
+ }
- ScopedParen sp(out);
+ ScopedParen sp(out);
- auto emit_els = [&](auto emit_el) {
- if (constant.AllEqual(start, end)) {
- return emit_el(start);
+ if (constant->AllEqual()) {
+ return EmitConstant(out, constant->Index(0));
}
- for (size_t i = start; i < end; i++) {
- if (i > start) {
+
+ for (size_t i = 0; i < v->Width(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!emit_el(i)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
return true;
- };
+ },
+ [&](const sem::Matrix* m) {
+ if (!EmitType(out, m, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+ return false;
+ }
- return Switch(
- vec_ty->type(), //
- [&](const sem::Bool*) { return emit_els(emit_bool); }, //
- [&](const sem::F32*) { return emit_els(emit_f32); }, //
- [&](const sem::I32*) { return emit_els(emit_i32); }, //
- [&](const sem::U32*) { return emit_els(emit_u32); }, //
- [&](Default) {
- diagnostics_.add_error(diag::System::Writer,
- "unhandled constant vector element type: " +
- builder_.FriendlyName(vec_ty->type()));
+ ScopedParen sp(out);
+
+ for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
+ if (column_idx > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(column_idx))) {
+ return false;
+ }
+ }
+ return true;
+ },
+ [&](const sem::Array* a) {
+ if (!EmitType(out, a, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return false;
- });
- };
- auto emit_matrix = [&](const sem::Matrix* m) {
- if (!EmitType(out, constant.Type(), ast::StorageClass::kNone, ast::Access::kUndefined,
- "")) {
- return false;
- }
+ }
- ScopedParen sp(out);
+ ScopedParen sp(out);
- for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
- if (column_idx > 0) {
- out << ", ";
+ for (size_t i = 0; i < a->Count(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
}
- size_t start = m->rows() * column_idx;
- size_t end = m->rows() * (column_idx + 1);
- if (!emit_vector(m->ColumnType(), start, end)) {
+
+ return true;
+ },
+ [&](const sem::Struct* s) {
+ if (!EmitType(out, s, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return false;
}
- }
- return true;
- };
- return Switch(
- constant.Type(), //
- [&](const sem::Bool*) { return emit_bool(0); }, //
- [&](const sem::F32*) { return emit_f32(0); }, //
- [&](const sem::I32*) { return emit_i32(0); }, //
- [&](const sem::U32*) { return emit_u32(0); }, //
- [&](const sem::Vector* v) { return emit_vector(v, 0, constant.ElementCount()); }, //
- [&](const sem::Matrix* m) { return emit_matrix(m); }, //
+
+ ScopedParen sp(out);
+
+ for (size_t i = 0; i < s->Members().size(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ },
[&](Default) {
diagnostics_.add_error(
diag::System::Writer,
- "unhandled constant type: " + builder_.FriendlyName(constant.Type()));
+ "unhandled constant type: " + builder_.FriendlyName(constant->Type()));
return false;
});
}
@@ -2303,6 +2299,9 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
return true;
},
[&](const ast::FloatLiteralExpression* l) {
+ if (l->suffix == ast::FloatLiteralExpression::Suffix::kH) {
+ return PrintF16(out, static_cast<float>(l->value));
+ }
PrintF32(out, static_cast<float>(l->value));
return true;
},
@@ -2324,6 +2323,8 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
out << "false";
} else if (type->Is<sem::F32>()) {
out << "0.0f";
+ } else if (type->Is<sem::F16>()) {
+ out << "0.0hf";
} else if (type->Is<sem::I32>()) {
out << "0";
} else if (type->Is<sem::U32>()) {
@@ -2359,7 +2360,7 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
return false;
}
bool first = true;
- out << "(";
+ ScopedParen sp(out);
for (auto* member : str->Members()) {
if (!first) {
out << ", ";
@@ -2368,19 +2369,17 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
}
EmitZeroValue(out, member->Type());
}
- out << ")";
} else if (auto* array = type->As<sem::Array>()) {
if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return false;
}
- out << "(";
+ ScopedParen sp(out);
for (uint32_t i = 0; i < array->Count(); i++) {
if (i != 0) {
out << ", ";
}
EmitZeroValue(out, array->ElemType());
}
- out << ")";
} else {
diagnostics_.add_error(diag::System::Writer, "Invalid type for zero emission: " +
type->FriendlyName(builder_.Symbols()));
@@ -2524,6 +2523,57 @@ bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
return true;
}
+bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
+ TextBuffer cond_pre;
+ std::stringstream cond_buf;
+ {
+ auto* cond = stmt->condition;
+ TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
+ if (!EmitExpression(cond_buf, cond)) {
+ return false;
+ }
+ }
+
+ auto emit_continuing = [&]() { return true; };
+ TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+
+ // If the whilehas a multi-statement conditional, then we cannot emit this
+ // as a regular while in GLSL. Instead we need to generate a `while(true)` loop.
+ bool emit_as_loop = cond_pre.lines.size() > 0;
+ if (emit_as_loop) {
+ line() << "while (true) {";
+ increment_indent();
+ TINT_DEFER({
+ decrement_indent();
+ line() << "}";
+ });
+
+ current_buffer_->Append(cond_pre);
+ line() << "if (!(" << cond_buf.str() << ")) { break; }";
+
+ if (!EmitStatements(stmt->body->statements)) {
+ return false;
+ }
+ } else {
+ // While can be generated.
+ {
+ auto out = line();
+ out << "while";
+ {
+ ScopedParen sp(out);
+ out << cond_buf.str();
+ }
+ out << " {";
+ }
+ if (!EmitStatementsWithIndent(stmt->body->statements)) {
+ return false;
+ }
+ line() << "}";
+ }
+
+ return true;
+}
+
bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
const ast::MemberAccessorExpression* expr) {
if (!EmitExpression(out, expr->structure)) {
@@ -2556,55 +2606,53 @@ bool GeneratorImpl::EmitReturn(const ast::ReturnStatement* stmt) {
}
bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
- if (auto* a = stmt->As<ast::AssignmentStatement>()) {
- return EmitAssign(a);
- }
- if (auto* b = stmt->As<ast::BlockStatement>()) {
- return EmitBlock(b);
- }
- if (auto* b = stmt->As<ast::BreakStatement>()) {
- return EmitBreak(b);
- }
- if (auto* c = stmt->As<ast::CallStatement>()) {
- auto out = line();
- if (!EmitCall(out, c->expr)) {
+ return Switch(
+ stmt, //
+ [&](const ast::AssignmentStatement* a) { return EmitAssign(a); },
+ [&](const ast::BlockStatement* b) { return EmitBlock(b); },
+ [&](const ast::BreakStatement* b) { return EmitBreak(b); },
+ [&](const ast::CallStatement* c) {
+ auto out = line();
+ if (!EmitCall(out, c->expr)) {
+ return false;
+ }
+ out << ";";
+ return true;
+ },
+ [&](const ast::ContinueStatement* c) { return EmitContinue(c); },
+ [&](const ast::DiscardStatement* d) { return EmitDiscard(d); },
+ [&](const ast::FallthroughStatement*) {
+ line() << "/* fallthrough */";
+ return true;
+ },
+ [&](const ast::IfStatement* i) { return EmitIf(i); },
+ [&](const ast::LoopStatement* l) { return EmitLoop(l); },
+ [&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
+ [&](const ast::WhileStatement* l) { return EmitWhile(l); },
+ [&](const ast::ReturnStatement* r) { return EmitReturn(r); },
+ [&](const ast::SwitchStatement* s) { return EmitSwitch(s); },
+ [&](const ast::VariableDeclStatement* v) {
+ return Switch(
+ v->variable, //
+ [&](const ast::Var* var) { return EmitVar(var); },
+ [&](const ast::Let* let) { return EmitLet(let); },
+ [&](const ast::Const*) {
+ return true; // Constants are embedded at their use
+ },
+ [&](Default) { //
+ TINT_ICE(Writer, diagnostics_)
+ << "unknown variable type: " << v->variable->TypeInfo().name;
+ return false;
+ });
+ },
+ [&](const ast::StaticAssert*) {
+ return true; // Not emitted
+ },
+ [&](Default) {
+ diagnostics_.add_error(diag::System::Writer,
+ "unknown statement type: " + std::string(stmt->TypeInfo().name));
return false;
- }
- out << ";";
- return true;
- }
- if (auto* c = stmt->As<ast::ContinueStatement>()) {
- return EmitContinue(c);
- }
- if (auto* d = stmt->As<ast::DiscardStatement>()) {
- return EmitDiscard(d);
- }
- if (stmt->As<ast::FallthroughStatement>()) {
- line() << "/* fallthrough */";
- return true;
- }
- if (auto* i = stmt->As<ast::IfStatement>()) {
- return EmitIf(i);
- }
- if (auto* l = stmt->As<ast::LoopStatement>()) {
- return EmitLoop(l);
- }
- if (auto* l = stmt->As<ast::ForLoopStatement>()) {
- return EmitForLoop(l);
- }
- if (auto* r = stmt->As<ast::ReturnStatement>()) {
- return EmitReturn(r);
- }
- if (auto* s = stmt->As<ast::SwitchStatement>()) {
- return EmitSwitch(s);
- }
- if (auto* v = stmt->As<ast::VariableDeclStatement>()) {
- return EmitVariable(v->variable);
- }
-
- diagnostics_.add_error(diag::System::Writer,
- "unknown statement type: " + std::string(stmt->TypeInfo().name));
- return false;
+ });
}
bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
@@ -2641,11 +2689,11 @@ bool GeneratorImpl::EmitType(std::ostream& out,
*name_printed = false;
}
switch (storage_class) {
- case ast::StorageClass::kInput: {
+ case ast::StorageClass::kIn: {
out << "in ";
break;
}
- case ast::StorageClass::kOutput: {
+ case ast::StorageClass::kOut: {
out << "out ";
break;
}
@@ -2686,12 +2734,14 @@ bool GeneratorImpl::EmitType(std::ostream& out,
} else if (type->Is<sem::F32>()) {
out << "float";
} else if (type->Is<sem::F16>()) {
- diagnostics_.add_error(diag::System::Writer, "Type f16 is not completely implemented yet.");
- return false;
+ out << "float16_t";
} else if (type->Is<sem::I32>()) {
out << "int";
} else if (auto* mat = type->As<sem::Matrix>()) {
- TINT_ASSERT(Writer, mat->type()->Is<sem::F32>());
+ TINT_ASSERT(Writer, (mat->type()->IsAnyOf<sem::F32, sem::F16>()));
+ if (mat->type()->Is<sem::F16>()) {
+ out << "f16";
+ }
out << "mat" << mat->columns();
if (mat->rows() != mat->columns()) {
out << "x" << mat->rows();
@@ -2770,6 +2820,8 @@ bool GeneratorImpl::EmitType(std::ostream& out,
auto width = vec->Width();
if (vec->type()->Is<sem::F32>() && width >= 1 && width <= 4) {
out << "vec" << width;
+ } else if (vec->type()->Is<sem::F16>() && width >= 1 && width <= 4) {
+ out << "f16vec" << width;
} else if (vec->type()->Is<sem::I32>() && width >= 1 && width <= 4) {
out << "ivec" << width;
} else if (vec->type()->Is<sem::U32>() && width >= 1 && width <= 4) {
@@ -2870,29 +2922,20 @@ bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression*
out << "-";
break;
}
- out << "(";
+ ScopedParen sp(out);
if (!EmitExpression(out, expr->expr)) {
return false;
}
- out << ")";
-
return true;
}
-bool GeneratorImpl::EmitVariable(const ast::Variable* var) {
+bool GeneratorImpl::EmitVar(const ast::Var* var) {
auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type()->UnwrapRef();
- // TODO(dsinclair): Handle variable attributes
- if (!var->attributes.empty()) {
- diagnostics_.add_error(diag::System::Writer, "Variable attributes are not handled yet");
- return false;
- }
-
auto out = line();
- // TODO(senorblanco): handle const
if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
builder_.Symbols().NameFor(var->symbol))) {
return false;
@@ -2914,58 +2957,74 @@ bool GeneratorImpl::EmitVariable(const ast::Variable* var) {
return true;
}
-bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
- for (auto* d : var->attributes) {
- if (!d->Is<ast::IdAttribute>()) {
- diagnostics_.add_error(diag::System::Writer, "Decorated const values not valid");
- return false;
- }
+bool GeneratorImpl::EmitLet(const ast::Let* let) {
+ auto* sem = builder_.Sem().Get(let);
+ auto* type = sem->Type()->UnwrapRef();
+
+ auto out = line();
+ // TODO(senorblanco): handle const
+ if (!EmitTypeAndName(out, type, ast::StorageClass::kNone, ast::Access::kUndefined,
+ builder_.Symbols().NameFor(let->symbol))) {
+ return false;
}
- if (!var->is_const) {
- diagnostics_.add_error(diag::System::Writer, "Expected a const value");
+
+ out << " = ";
+
+ if (!EmitExpression(out, let->constructor)) {
return false;
}
+ out << ";";
+
+ return true;
+}
+
+bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type();
+ auto out = line();
+ out << "const ";
+ if (!EmitTypeAndName(out, type, ast::StorageClass::kNone, ast::Access::kUndefined,
+ builder_.Symbols().NameFor(var->symbol))) {
+ return false;
+ }
+ out << " = ";
+ if (!EmitExpression(out, var->constructor)) {
+ return false;
+ }
+ out << ";";
+
+ return true;
+}
+
+bool GeneratorImpl::EmitOverride(const ast::Override* override) {
+ auto* sem = builder_.Sem().Get(override);
+ auto* type = sem->Type();
+
auto* global = sem->As<sem::GlobalVariable>();
- if (global && global->IsOverridable()) {
- auto const_id = global->ConstantId();
+ auto override_id = global->OverrideId();
- line() << "#ifndef " << kSpecConstantPrefix << const_id;
+ line() << "#ifndef " << kSpecConstantPrefix << override_id.value;
- if (var->constructor != nullptr) {
- auto out = line();
- out << "#define " << kSpecConstantPrefix << const_id << " ";
- if (!EmitExpression(out, var->constructor)) {
- return false;
- }
- } else {
- line() << "#error spec constant required for constant id " << const_id;
- }
- line() << "#endif";
- {
- auto out = line();
- out << "const ";
- if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
- builder_.Symbols().NameFor(var->symbol))) {
- return false;
- }
- out << " = " << kSpecConstantPrefix << const_id << ";";
+ if (override->constructor != nullptr) {
+ auto out = line();
+ out << "#define " << kSpecConstantPrefix << override_id.value << " ";
+ if (!EmitExpression(out, override->constructor)) {
+ return false;
}
} else {
+ line() << "#error spec constant required for constant id " << override_id.value;
+ }
+ line() << "#endif";
+ {
auto out = line();
out << "const ";
- if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
- builder_.Symbols().NameFor(var->symbol))) {
+ if (!EmitTypeAndName(out, type, ast::StorageClass::kNone, ast::Access::kUndefined,
+ builder_.Symbols().NameFor(override->symbol))) {
return false;
}
- out << " = ";
- if (!EmitExpression(out, var->constructor)) {
- return false;
- }
- out << ";";
+ out << " = " << kSpecConstantPrefix << override_id.value << ";";
}
return true;
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.h b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.h
index 819c79b973e..502df8b245f 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.h
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl.h
@@ -16,6 +16,7 @@
#define SRC_TINT_WRITER_GLSL_GENERATOR_IMPL_H_
#include <string>
+#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
@@ -125,11 +126,11 @@ class GeneratorImpl : public TextGenerator {
/// Emits a list of statements
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
- bool EmitStatements(const ast::StatementList& stmts);
+ bool EmitStatements(utils::VectorRef<const ast::Statement*> stmts);
/// Emits a list of statements with an indentation
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
- bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+ bool EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts);
/// Handles a block statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -293,19 +294,22 @@ class GeneratorImpl : public TextGenerator {
bool EmitGlobalVariable(const ast::Variable* global);
/// Handles emitting a global variable with the uniform storage class
- /// @param var the global variable
+ /// @param var the AST node for the 'var'
+ /// @param sem the semantic node for the 'var'
/// @returns true on success
- bool EmitUniformVariable(const sem::Variable* var);
+ bool EmitUniformVariable(const ast::Var* var, const sem::Variable* sem);
/// Handles emitting a global variable with the storage storage class
- /// @param var the global variable
+ /// @param var the AST node for the 'var'
+ /// @param sem the semantic node for the 'var'
/// @returns true on success
- bool EmitStorageVariable(const sem::Variable* var);
+ bool EmitStorageVariable(const ast::Var* var, const sem::Variable* sem);
/// Handles emitting a global variable with the handle storage class
- /// @param var the global variable
+ /// @param var the AST node for the 'var'
+ /// @param sem the semantic node for the 'var'
/// @returns true on success
- bool EmitHandleVariable(const sem::Variable* var);
+ bool EmitHandleVariable(const ast::Var* var, const sem::Variable* sem);
/// Handles emitting a global variable with the private storage class
/// @param var the global variable
@@ -325,12 +329,13 @@ class GeneratorImpl : public TextGenerator {
/// Handles emitting interpolation qualifiers
/// @param out the output of the expression stream
/// @param attrs the attributes
- void EmitInterpolationQualifiers(std::ostream& out, const ast::AttributeList& attrs);
+ void EmitInterpolationQualifiers(std::ostream& out,
+ utils::VectorRef<const ast::Attribute*> attrs);
/// Handles emitting attributes
/// @param out the output of the expression stream
/// @param attrs the attributes
/// @returns true if the attributes were emitted
- bool EmitAttributes(std::ostream& out, const ast::AttributeList& attrs);
+ bool EmitAttributes(std::ostream& out, utils::VectorRef<const ast::Attribute*> attrs);
/// Handles emitting the entry point function
/// @param func the entry point
/// @returns true if the entry point function was emitted
@@ -343,7 +348,7 @@ class GeneratorImpl : public TextGenerator {
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const sem::Constant& constant);
+ bool EmitConstant(std::ostream& out, const sem::Constant* constant);
/// Handles a literal
/// @param out the output stream
/// @param lit the literal to emit
@@ -357,6 +362,10 @@ class GeneratorImpl : public TextGenerator {
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
bool EmitForLoop(const ast::ForLoopStatement* stmt);
+ /// Handles a while statement
+ /// @param stmt the statement to emit
+ /// @returns true if the statement was emitted
+ bool EmitWhile(const ast::WhileStatement* stmt);
/// Handles generating an identifier expression
/// @param out the output of the expression stream
/// @param expr the identifier expression
@@ -433,14 +442,22 @@ class GeneratorImpl : public TextGenerator {
/// @param type the type to emit the value for
/// @returns true if the zero value was successfully emitted.
bool EmitZeroValue(std::ostream& out, const sem::Type* type);
- /// Handles generating a variable
+ /// Handles generating a 'var' declaration
/// @param var the variable to generate
/// @returns true if the variable was emitted
- bool EmitVariable(const ast::Variable* var);
- /// Handles generating a program scope constant variable
- /// @param var the variable to emit
+ bool EmitVar(const ast::Var* var);
+ /// Handles generating a function-scope 'let' declaration
+ /// @param let the variable to generate
+ /// @returns true if the variable was emitted
+ bool EmitLet(const ast::Let* let);
+ /// Handles generating a module-scope 'let' declaration
+ /// @param let the 'let' to emit
/// @returns true if the variable was emitted
- bool EmitProgramConstVariable(const ast::Variable* var);
+ bool EmitProgramConstVariable(const ast::Variable* let);
+ /// Handles generating a module-scope 'override' declaration
+ /// @param override the 'override' to emit
+ /// @returns true if the variable was emitted
+ bool EmitOverride(const ast::Override* override);
/// Handles generating a builtin method name
/// @param builtin the semantic info for the builtin
/// @returns the name or "" if not valid
@@ -449,11 +466,11 @@ class GeneratorImpl : public TextGenerator {
/// @param builtin the builtin to convert
/// @param stage pipeline stage in which this builtin is used
/// @returns the string name of the builtin or blank on error
- const char* builtin_to_string(ast::Builtin builtin, ast::PipelineStage stage);
+ const char* builtin_to_string(ast::BuiltinValue builtin, ast::PipelineStage stage);
/// Converts a builtin to a sem::Type appropriate for GLSL.
/// @param builtin the builtin to convert
/// @returns the appropriate semantic type or null on error.
- sem::Type* builtin_type(ast::Builtin builtin);
+ sem::Type* builtin_type(ast::BuiltinValue builtin);
private:
enum class VarType { kIn, kOut };
@@ -463,19 +480,9 @@ class GeneratorImpl : public TextGenerator {
std::string var_name;
};
- struct DMAIntrinsic {
- transform::DecomposeMemoryAccess::Intrinsic::Op op;
- transform::DecomposeMemoryAccess::Intrinsic::DataType type;
- bool operator==(const DMAIntrinsic& rhs) const { return op == rhs.op && type == rhs.type; }
- /// Hasher is a std::hash function for DMAIntrinsic
- struct Hasher {
- /// @param i the DMAIntrinsic to hash
- /// @returns the hash of `i`
- inline std::size_t operator()(const DMAIntrinsic& i) const {
- return utils::Hash(i.op, i.type);
- }
- };
- };
+ /// The map key for two semantic types.
+ using BinaryOperandType =
+ utils::UnorderedKeyWrapper<std::tuple<const sem::Type*, const sem::Type*>>;
/// CallBuiltinHelper will call the builtin helper function, creating it
/// if it hasn't been built already. If the builtin needs to be built then
@@ -503,15 +510,14 @@ class GeneratorImpl : public TextGenerator {
TextBuffer helpers_; // Helper functions emitted at the top of the output
std::function<bool()> emit_continuing_;
- std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher> dma_intrinsics_;
std::unordered_map<const sem::Builtin*, std::string> builtins_;
- std::unordered_map<const sem::Struct*, std::string> structure_builders_;
std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_;
std::unordered_map<const sem::Vector*, std::string> int_dot_funcs_;
- std::unordered_map<const sem::Type*, std::string> float_modulo_funcs_;
+ std::unordered_map<BinaryOperandType, std::string> float_modulo_funcs_;
std::unordered_set<const sem::Struct*> emitted_structs_;
bool requires_oes_sample_variables_ = false;
bool requires_default_precision_qualifier_ = false;
+ bool requires_f16_extension_ = false;
Version version_;
};
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_array_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
index d28e5607d8c..bbf90fe8a11 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
@@ -22,7 +22,7 @@ namespace {
using GlslGeneratorImplTest_Expression = TestHelper;
TEST_F(GlslGeneratorImplTest_Expression, IndexAccessor) {
- Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+ GlobalVar("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
auto* expr = IndexAccessor("ary", 5_i);
WrapInFunction(expr);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_assign_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_assign_test.cc
index fbd9f6262c8..84b6b30c696 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_assign_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_assign_test.cc
@@ -20,8 +20,8 @@ namespace {
using GlslGeneratorImplTest_Assign = TestHelper;
TEST_F(GlslGeneratorImplTest_Assign, Emit_Assign) {
- Global("lhs", ty.i32(), ast::StorageClass::kPrivate);
- Global("rhs", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("lhs", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.i32(), ast::StorageClass::kPrivate);
auto* assign = Assign("lhs", "rhs");
WrapInFunction(assign);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_binary_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_binary_test.cc
index 0d019a98f81..2a4994aa18c 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_binary_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_binary_test.cc
@@ -43,8 +43,36 @@ TEST_P(GlslBinaryTest, Emit_f32) {
return;
}
- Global("left", ty.f32(), ast::StorageClass::kPrivate);
- Global("right", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("left", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.f32(), ast::StorageClass::kPrivate);
+
+ auto* left = Expr("left");
+ auto* right = Expr("right");
+
+ auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), params.result);
+}
+TEST_P(GlslBinaryTest, Emit_f16) {
+ auto params = GetParam();
+
+ // Skip ops that are illegal for this type
+ if (params.op == ast::BinaryOp::kAnd || params.op == ast::BinaryOp::kOr ||
+ params.op == ast::BinaryOp::kXor || params.op == ast::BinaryOp::kShiftLeft ||
+ params.op == ast::BinaryOp::kShiftRight || params.op == ast::BinaryOp::kModulo) {
+ return;
+ }
+
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("left", ty.f16(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.f16(), ast::StorageClass::kPrivate);
auto* left = Expr("left");
auto* right = Expr("right");
@@ -62,8 +90,8 @@ TEST_P(GlslBinaryTest, Emit_f32) {
TEST_P(GlslBinaryTest, Emit_u32) {
auto params = GetParam();
- Global("left", ty.u32(), ast::StorageClass::kPrivate);
- Global("right", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("left", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.u32(), ast::StorageClass::kPrivate);
auto* left = Expr("left");
auto* right = Expr("right");
@@ -86,8 +114,8 @@ TEST_P(GlslBinaryTest, Emit_i32) {
return;
}
- Global("left", ty.i32(), ast::StorageClass::kPrivate);
- Global("right", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("left", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.i32(), ast::StorageClass::kPrivate);
auto* left = Expr("left");
auto* right = Expr("right");
@@ -122,7 +150,7 @@ INSTANTIATE_TEST_SUITE_P(
BinaryData{"(left / right)", ast::BinaryOp::kDivide},
BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
-TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar) {
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar_f32) {
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
auto* rhs = Expr(1_f);
@@ -137,7 +165,24 @@ TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar) {
EXPECT_EQ(out.str(), "(vec3(1.0f) * 1.0f)");
}
-TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector) {
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+ auto* rhs = Expr(1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(f16vec3(1.0hf) * 1.0hf)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector_f32) {
auto* lhs = Expr(1_f);
auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -152,8 +197,25 @@ TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector) {
EXPECT_EQ(out.str(), "(1.0f * vec3(1.0f))");
}
-TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* lhs = Expr(1_h);
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(1.0hf * f16vec3(1.0hf))");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = Expr("mat");
auto* rhs = Expr(1_f);
@@ -167,8 +229,25 @@ TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar) {
EXPECT_EQ(out.str(), "(mat * 1.0f)");
}
-TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = Expr("mat");
+ auto* rhs = Expr(1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(mat * 1.0hf)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = Expr(1_f);
auto* rhs = Expr("mat");
@@ -182,8 +261,25 @@ TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix) {
EXPECT_EQ(out.str(), "(1.0f * mat)");
}
-TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = Expr(1_h);
+ auto* rhs = Expr("mat");
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(1.0hf * mat)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = Expr("mat");
auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -197,8 +293,25 @@ TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector) {
EXPECT_EQ(out.str(), "(mat * vec3(1.0f))");
}
-TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = Expr("mat");
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(mat * f16vec3(1.0hf))");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
auto* rhs = Expr("mat");
@@ -212,9 +325,26 @@ TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix) {
EXPECT_EQ(out.str(), "(vec3(1.0f) * mat)");
}
-TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix) {
- Global("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
- Global("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+ auto* rhs = Expr("mat");
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(f16vec3(1.0hf) * mat)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f32) {
+ GlobalVar("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
@@ -226,28 +356,41 @@ TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix) {
EXPECT_EQ(out.str(), "(lhs * rhs)");
}
-TEST_F(GlslGeneratorImplTest_Binary, Logical_And) {
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f16) {
+ Enable(ast::Extension::kF16);
- auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
+ GlobalVar("lhs", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
GeneratorImpl& gen = Build();
std::stringstream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
- EXPECT_EQ(out.str(), "(tint_tmp)");
- EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
-if (tint_tmp) {
- tint_tmp = b;
-}
-)");
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(lhs * rhs)");
}
TEST_F(GlslGeneratorImplTest_Binary, ModF32) {
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
- Global("b", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.f32(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, ModF16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.f16(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.f16(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
WrapInFunction(expr);
@@ -260,8 +403,84 @@ TEST_F(GlslGeneratorImplTest_Binary, ModF32) {
}
TEST_F(GlslGeneratorImplTest_Binary, ModVec3F32) {
- Global("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, ModVec3F16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, ModVec3F32ScalarF32) {
+ GlobalVar("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.f32(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, ModVec3F16ScalarF16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.f16(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, ModScalarF32Vec3F32) {
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, ModScalarF16Vec3F16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.f16(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.vec3<f16>(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
WrapInFunction(expr);
@@ -273,12 +492,118 @@ TEST_F(GlslGeneratorImplTest_Binary, ModVec3F32) {
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
+TEST_F(GlslGeneratorImplTest_Binary, ModMixedVec3ScalarF32) {
+ GlobalVar("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.f32(), ast::StorageClass::kPrivate);
+
+ auto* expr_vec_mod_vec =
+ create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("a"));
+ auto* expr_vec_mod_scalar =
+ create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ auto* expr_scalar_mod_vec =
+ create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("b"), Expr("a"));
+ WrapInFunction(expr_vec_mod_vec, expr_vec_mod_scalar, expr_scalar_mod_vec);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+vec3 tint_float_modulo(vec3 lhs, vec3 rhs) {
+ return (lhs - rhs * trunc(lhs / rhs));
+}
+
+vec3 tint_float_modulo_1(vec3 lhs, float rhs) {
+ return (lhs - rhs * trunc(lhs / rhs));
+}
+
+vec3 tint_float_modulo_2(float lhs, vec3 rhs) {
+ return (lhs - rhs * trunc(lhs / rhs));
+}
+
+
+vec3 a = vec3(0.0f, 0.0f, 0.0f);
+float b = 0.0f;
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void test_function() {
+ vec3 tint_symbol = tint_float_modulo(a, a);
+ vec3 tint_symbol_1 = tint_float_modulo_1(a, b);
+ vec3 tint_symbol_2 = tint_float_modulo_2(b, a);
+ return;
+}
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, ModMixedVec3ScalarF16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.f16(), ast::StorageClass::kPrivate);
+
+ auto* expr_vec_mod_vec =
+ create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("a"));
+ auto* expr_vec_mod_scalar =
+ create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+ auto* expr_scalar_mod_vec =
+ create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("b"), Expr("a"));
+ WrapInFunction(expr_vec_mod_vec, expr_vec_mod_scalar, expr_scalar_mod_vec);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+f16vec3 tint_float_modulo(f16vec3 lhs, f16vec3 rhs) {
+ return (lhs - rhs * trunc(lhs / rhs));
+}
+
+f16vec3 tint_float_modulo_1(f16vec3 lhs, float16_t rhs) {
+ return (lhs - rhs * trunc(lhs / rhs));
+}
+
+f16vec3 tint_float_modulo_2(float16_t lhs, f16vec3 rhs) {
+ return (lhs - rhs * trunc(lhs / rhs));
+}
+
+
+f16vec3 a = f16vec3(0.0hf, 0.0hf, 0.0hf);
+float16_t b = 0.0hf;
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void test_function() {
+ f16vec3 tint_symbol = tint_float_modulo(a, a);
+ f16vec3 tint_symbol_1 = tint_float_modulo_1(a, b);
+ f16vec3 tint_symbol_2 = tint_float_modulo_2(b, a);
+ return;
+}
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Binary, Logical_And) {
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(tint_tmp)");
+ EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+if (tint_tmp) {
+ tint_tmp = b;
+}
+)");
+}
+
TEST_F(GlslGeneratorImplTest_Binary, Logical_Multi) {
// (a && b) || (c || d)
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(
ast::BinaryOp::kLogicalOr,
@@ -307,8 +632,8 @@ if (!tint_tmp) {
}
TEST_F(GlslGeneratorImplTest_Binary, Logical_Or) {
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
WrapInFunction(expr);
@@ -334,16 +659,16 @@ TEST_F(GlslGeneratorImplTest_Binary, If_WithLogical) {
// return 3i;
// }
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr =
If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
Block(Return(1_i)),
Else(If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
Block(Return(2_i)), Else(Block(Return(3_i))))));
- Func("func", {}, ty.i32(), {WrapInStatement(expr)});
+ Func("func", utils::Empty, ty.i32(), utils::Vector{WrapInStatement(expr)});
GeneratorImpl& gen = Build();
@@ -371,15 +696,15 @@ if ((tint_tmp)) {
TEST_F(GlslGeneratorImplTest_Binary, Return_WithLogical) {
// return (a && b) || c;
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = Return(create<ast::BinaryExpression>(
ast::BinaryOp::kLogicalOr,
create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
Expr("c")));
- Func("func", {}, ty.bool_(), {WrapInStatement(expr)});
+ Func("func", utils::Empty, ty.bool_(), utils::Vector{WrapInStatement(expr)});
GeneratorImpl& gen = Build();
@@ -399,10 +724,10 @@ return (tint_tmp);
TEST_F(GlslGeneratorImplTest_Binary, Assign_WithLogical) {
// a = (b || c) && d;
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr =
Assign(Expr("a"),
@@ -430,9 +755,9 @@ a = (tint_tmp);
TEST_F(GlslGeneratorImplTest_Binary, Decl_WithLogical) {
// var a : bool = (b && c) || d;
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
auto* var =
Var("a", ty.bool_(), ast::StorageClass::kNone,
@@ -463,26 +788,25 @@ TEST_F(GlslGeneratorImplTest_Binary, Call_WithLogical) {
// foo(a && b, c || d, (a || c) && (b || d))
Func("foo",
- {
+ utils::Vector{
Param(Sym(), ty.bool_()),
Param(Sym(), ty.bool_()),
Param(Sym(), ty.bool_()),
},
- ty.void_(), ast::StatementList{}, ast::AttributeList{});
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
-
- ast::ExpressionList params;
- params.push_back(
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")));
- params.push_back(
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")));
- params.push_back(create<ast::BinaryExpression>(
- ast::BinaryOp::kLogicalAnd,
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("c")),
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("d"))));
+ ty.void_(), utils::Empty, utils::Empty);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
+
+ utils::Vector params{
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")),
+ create<ast::BinaryExpression>(
+ ast::BinaryOp::kLogicalAnd,
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("c")),
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("d"))),
+ };
auto* expr = CallStmt(Call("foo", params));
WrapInFunction(expr);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_test.cc
index 6f2c555909e..b8161e2ea21 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -29,36 +29,40 @@ using BuiltinType = sem::BuiltinType;
using GlslGeneratorImplTest_Builtin = TestHelper;
-enum class ParamType {
+enum class CallParamType {
kF32,
kU32,
kBool,
+ kF16,
};
struct BuiltinData {
BuiltinType builtin;
- ParamType type;
+ CallParamType type;
const char* glsl_name;
};
inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
- out << data.glsl_name;
+ out << data.glsl_name << "<";
switch (data.type) {
- case ParamType::kF32:
+ case CallParamType::kF32:
out << "f32";
break;
- case ParamType::kU32:
+ case CallParamType::kU32:
out << "u32";
break;
- case ParamType::kBool:
+ case CallParamType::kBool:
out << "bool";
break;
+ case CallParamType::kF16:
+ out << "f16";
+ break;
}
out << ">";
return out;
}
const ast::CallExpression* GenerateCall(BuiltinType builtin,
- ParamType type,
+ CallParamType type,
ProgramBuilder* builder) {
std::string name;
std::ostringstream str(name);
@@ -96,30 +100,51 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
case BuiltinType::kTanh:
case BuiltinType::kTrunc:
case BuiltinType::kSign:
- return builder->Call(str.str(), "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2");
+ } else {
+ return builder->Call(str.str(), "f2");
+ }
case BuiltinType::kLdexp:
- return builder->Call(str.str(), "f2", "i2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "i2");
+ } else {
+ return builder->Call(str.str(), "f2", "i2");
+ }
case BuiltinType::kAtan2:
case BuiltinType::kDot:
case BuiltinType::kDistance:
case BuiltinType::kPow:
case BuiltinType::kReflect:
case BuiltinType::kStep:
- return builder->Call(str.str(), "f2", "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2");
+ }
case BuiltinType::kCross:
- return builder->Call(str.str(), "f3", "f3");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h3", "h3");
+ } else {
+ return builder->Call(str.str(), "f3", "f3");
+ }
case BuiltinType::kFma:
case BuiltinType::kMix:
case BuiltinType::kFaceForward:
case BuiltinType::kSmoothstep:
- case BuiltinType::kSmoothStep:
- return builder->Call(str.str(), "f2", "f2", "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "h2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2", "f2");
+ }
case BuiltinType::kAll:
case BuiltinType::kAny:
return builder->Call(str.str(), "b2");
case BuiltinType::kAbs:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2");
} else {
return builder->Call(str.str(), "u2");
}
@@ -128,23 +153,39 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
return builder->Call(str.str(), "u2");
case BuiltinType::kMax:
case BuiltinType::kMin:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2", "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2");
} else {
return builder->Call(str.str(), "u2", "u2");
}
case BuiltinType::kClamp:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2", "f2", "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "h2");
} else {
return builder->Call(str.str(), "u2", "u2", "u2");
}
case BuiltinType::kSelect:
- return builder->Call(str.str(), "f2", "f2", "b2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "b2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2", "b2");
+ }
case BuiltinType::kDeterminant:
- return builder->Call(str.str(), "m2x2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "hm2x2");
+ } else {
+ return builder->Call(str.str(), "m2x2");
+ }
case BuiltinType::kTranspose:
- return builder->Call(str.str(), "m3x2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "hm3x2");
+ } else {
+ return builder->Call(str.str(), "m3x2");
+ }
default:
break;
}
@@ -154,18 +195,30 @@ using GlslBuiltinTest = TestParamHelper<BuiltinData>;
TEST_P(GlslBuiltinTest, Emit) {
auto param = GetParam();
- Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
- Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
- Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
- Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
- Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
- Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
+ if (param.type == CallParamType::kF16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("h2", ty.vec2<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("h3", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("hm2x2", ty.mat2x2<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("hm3x2", ty.mat3x2<f16>(), ast::StorageClass::kPrivate);
+ }
+
+ GlobalVar("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
+ GlobalVar("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
auto* call = GenerateCall(param.builtin, param.type, this);
ASSERT_NE(nullptr, call) << "Unhandled builtin";
- Func("func", {}, ty.void_(), {CallStmt(call)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(call),
+ },
+ utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build();
@@ -181,71 +234,116 @@ TEST_P(GlslBuiltinTest, Emit) {
INSTANTIATE_TEST_SUITE_P(
GlslGeneratorImplTest_Builtin,
GlslBuiltinTest,
- testing::Values(BuiltinData{BuiltinType::kAbs, ParamType::kF32, "abs"},
- BuiltinData{BuiltinType::kAbs, ParamType::kU32, "abs"},
- BuiltinData{BuiltinType::kAcos, ParamType::kF32, "acos"},
- BuiltinData{BuiltinType::kAll, ParamType::kBool, "all"},
- BuiltinData{BuiltinType::kAny, ParamType::kBool, "any"},
- BuiltinData{BuiltinType::kAsin, ParamType::kF32, "asin"},
- BuiltinData{BuiltinType::kAtan, ParamType::kF32, "atan"},
- BuiltinData{BuiltinType::kAtan2, ParamType::kF32, "atan"},
- BuiltinData{BuiltinType::kCeil, ParamType::kF32, "ceil"},
- BuiltinData{BuiltinType::kClamp, ParamType::kF32, "clamp"},
- BuiltinData{BuiltinType::kClamp, ParamType::kU32, "clamp"},
- BuiltinData{BuiltinType::kCos, ParamType::kF32, "cos"},
- BuiltinData{BuiltinType::kCosh, ParamType::kF32, "cosh"},
- BuiltinData{BuiltinType::kCountOneBits, ParamType::kU32, "bitCount"},
- BuiltinData{BuiltinType::kCross, ParamType::kF32, "cross"},
- BuiltinData{BuiltinType::kDeterminant, ParamType::kF32, "determinant"},
- BuiltinData{BuiltinType::kDistance, ParamType::kF32, "distance"},
- BuiltinData{BuiltinType::kDot, ParamType::kF32, "dot"},
- BuiltinData{BuiltinType::kDpdx, ParamType::kF32, "dFdx"},
- BuiltinData{BuiltinType::kDpdxCoarse, ParamType::kF32, "dFdx"},
- BuiltinData{BuiltinType::kDpdxFine, ParamType::kF32, "dFdx"},
- BuiltinData{BuiltinType::kDpdy, ParamType::kF32, "dFdy"},
- BuiltinData{BuiltinType::kDpdyCoarse, ParamType::kF32, "dFdy"},
- BuiltinData{BuiltinType::kDpdyFine, ParamType::kF32, "dFdy"},
- BuiltinData{BuiltinType::kExp, ParamType::kF32, "exp"},
- BuiltinData{BuiltinType::kExp2, ParamType::kF32, "exp2"},
- BuiltinData{BuiltinType::kFaceForward, ParamType::kF32, "faceforward"},
- BuiltinData{BuiltinType::kFloor, ParamType::kF32, "floor"},
- BuiltinData{BuiltinType::kFma, ParamType::kF32, "fma"},
- BuiltinData{BuiltinType::kFract, ParamType::kF32, "fract"},
- BuiltinData{BuiltinType::kFwidth, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "inversesqrt"},
- BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
- BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
- BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
- BuiltinData{BuiltinType::kLog2, ParamType::kF32, "log2"},
- BuiltinData{BuiltinType::kMax, ParamType::kF32, "max"},
- BuiltinData{BuiltinType::kMax, ParamType::kU32, "max"},
- BuiltinData{BuiltinType::kMin, ParamType::kF32, "min"},
- BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
- BuiltinData{BuiltinType::kMix, ParamType::kF32, "mix"},
- BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
- BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
- BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
- BuiltinData{BuiltinType::kReverseBits, ParamType::kU32, "bitfieldReverse"},
- BuiltinData{BuiltinType::kRound, ParamType::kU32, "round"},
- BuiltinData{BuiltinType::kSign, ParamType::kF32, "sign"},
- BuiltinData{BuiltinType::kSin, ParamType::kF32, "sin"},
- BuiltinData{BuiltinType::kSinh, ParamType::kF32, "sinh"},
- BuiltinData{BuiltinType::kSmoothstep, ParamType::kF32, "smoothstep"},
- BuiltinData{BuiltinType::kSmoothStep, ParamType::kF32, "smoothstep"},
- BuiltinData{BuiltinType::kSqrt, ParamType::kF32, "sqrt"},
- BuiltinData{BuiltinType::kStep, ParamType::kF32, "step"},
- BuiltinData{BuiltinType::kTan, ParamType::kF32, "tan"},
- BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
- BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
- BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
+ testing::Values(/* Logical built-in */
+ BuiltinData{BuiltinType::kAll, CallParamType::kBool, "all"},
+ BuiltinData{BuiltinType::kAny, CallParamType::kBool, "any"},
+ /* Float built-in */
+ BuiltinData{BuiltinType::kAbs, CallParamType::kF32, "abs"},
+ BuiltinData{BuiltinType::kAbs, CallParamType::kF16, "abs"},
+ BuiltinData{BuiltinType::kAcos, CallParamType::kF32, "acos"},
+ BuiltinData{BuiltinType::kAcos, CallParamType::kF16, "acos"},
+ BuiltinData{BuiltinType::kAsin, CallParamType::kF32, "asin"},
+ BuiltinData{BuiltinType::kAsin, CallParamType::kF16, "asin"},
+ BuiltinData{BuiltinType::kAtan, CallParamType::kF32, "atan"},
+ BuiltinData{BuiltinType::kAtan, CallParamType::kF16, "atan"},
+ BuiltinData{BuiltinType::kAtan2, CallParamType::kF32, "atan"},
+ BuiltinData{BuiltinType::kAtan2, CallParamType::kF16, "atan"},
+ BuiltinData{BuiltinType::kCeil, CallParamType::kF32, "ceil"},
+ BuiltinData{BuiltinType::kCeil, CallParamType::kF16, "ceil"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kF32, "clamp"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kF16, "clamp"},
+ BuiltinData{BuiltinType::kCos, CallParamType::kF32, "cos"},
+ BuiltinData{BuiltinType::kCos, CallParamType::kF16, "cos"},
+ BuiltinData{BuiltinType::kCosh, CallParamType::kF32, "cosh"},
+ BuiltinData{BuiltinType::kCosh, CallParamType::kF16, "cosh"},
+ BuiltinData{BuiltinType::kCross, CallParamType::kF32, "cross"},
+ BuiltinData{BuiltinType::kCross, CallParamType::kF16, "cross"},
+ BuiltinData{BuiltinType::kDistance, CallParamType::kF32, "distance"},
+ BuiltinData{BuiltinType::kDistance, CallParamType::kF16, "distance"},
+ BuiltinData{BuiltinType::kExp, CallParamType::kF32, "exp"},
+ BuiltinData{BuiltinType::kExp, CallParamType::kF16, "exp"},
+ BuiltinData{BuiltinType::kExp2, CallParamType::kF32, "exp2"},
+ BuiltinData{BuiltinType::kExp2, CallParamType::kF16, "exp2"},
+ BuiltinData{BuiltinType::kFaceForward, CallParamType::kF32, "faceforward"},
+ BuiltinData{BuiltinType::kFaceForward, CallParamType::kF16, "faceforward"},
+ BuiltinData{BuiltinType::kFloor, CallParamType::kF32, "floor"},
+ BuiltinData{BuiltinType::kFloor, CallParamType::kF16, "floor"},
+ BuiltinData{BuiltinType::kFma, CallParamType::kF32, "fma"},
+ BuiltinData{BuiltinType::kFma, CallParamType::kF16, "fma"},
+ BuiltinData{BuiltinType::kFract, CallParamType::kF32, "fract"},
+ BuiltinData{BuiltinType::kFract, CallParamType::kF16, "fract"},
+ BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF32, "inversesqrt"},
+ BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF16, "inversesqrt"},
+ BuiltinData{BuiltinType::kLdexp, CallParamType::kF32, "ldexp"},
+ BuiltinData{BuiltinType::kLdexp, CallParamType::kF16, "ldexp"},
+ BuiltinData{BuiltinType::kLength, CallParamType::kF32, "length"},
+ BuiltinData{BuiltinType::kLength, CallParamType::kF16, "length"},
+ BuiltinData{BuiltinType::kLog, CallParamType::kF32, "log"},
+ BuiltinData{BuiltinType::kLog, CallParamType::kF16, "log"},
+ BuiltinData{BuiltinType::kLog2, CallParamType::kF32, "log2"},
+ BuiltinData{BuiltinType::kLog2, CallParamType::kF16, "log2"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kF32, "max"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kF16, "max"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kF32, "min"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kF16, "min"},
+ BuiltinData{BuiltinType::kMix, CallParamType::kF32, "mix"},
+ BuiltinData{BuiltinType::kMix, CallParamType::kF16, "mix"},
+ BuiltinData{BuiltinType::kNormalize, CallParamType::kF32, "normalize"},
+ BuiltinData{BuiltinType::kNormalize, CallParamType::kF16, "normalize"},
+ BuiltinData{BuiltinType::kPow, CallParamType::kF32, "pow"},
+ BuiltinData{BuiltinType::kPow, CallParamType::kF16, "pow"},
+ BuiltinData{BuiltinType::kReflect, CallParamType::kF32, "reflect"},
+ BuiltinData{BuiltinType::kReflect, CallParamType::kF16, "reflect"},
+ BuiltinData{BuiltinType::kSign, CallParamType::kF32, "sign"},
+ BuiltinData{BuiltinType::kSign, CallParamType::kF16, "sign"},
+ BuiltinData{BuiltinType::kSin, CallParamType::kF32, "sin"},
+ BuiltinData{BuiltinType::kSin, CallParamType::kF16, "sin"},
+ BuiltinData{BuiltinType::kSinh, CallParamType::kF32, "sinh"},
+ BuiltinData{BuiltinType::kSinh, CallParamType::kF16, "sinh"},
+ BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF32, "smoothstep"},
+ BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF16, "smoothstep"},
+ BuiltinData{BuiltinType::kSqrt, CallParamType::kF32, "sqrt"},
+ BuiltinData{BuiltinType::kSqrt, CallParamType::kF16, "sqrt"},
+ BuiltinData{BuiltinType::kStep, CallParamType::kF32, "step"},
+ BuiltinData{BuiltinType::kStep, CallParamType::kF16, "step"},
+ BuiltinData{BuiltinType::kTan, CallParamType::kF32, "tan"},
+ BuiltinData{BuiltinType::kTan, CallParamType::kF16, "tan"},
+ BuiltinData{BuiltinType::kTanh, CallParamType::kF32, "tanh"},
+ BuiltinData{BuiltinType::kTanh, CallParamType::kF16, "tanh"},
+ BuiltinData{BuiltinType::kTrunc, CallParamType::kF32, "trunc"},
+ BuiltinData{BuiltinType::kTrunc, CallParamType::kF16, "trunc"},
+ /* Integer built-in */
+ BuiltinData{BuiltinType::kAbs, CallParamType::kU32, "abs"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kU32, "clamp"},
+ BuiltinData{BuiltinType::kCountOneBits, CallParamType::kU32, "bitCount"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kU32, "max"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kU32, "min"},
+ BuiltinData{BuiltinType::kReverseBits, CallParamType::kU32, "bitfieldReverse"},
+ BuiltinData{BuiltinType::kRound, CallParamType::kU32, "round"},
+ /* Matrix built-in */
+ BuiltinData{BuiltinType::kDeterminant, CallParamType::kF32, "determinant"},
+ BuiltinData{BuiltinType::kDeterminant, CallParamType::kF16, "determinant"},
+ BuiltinData{BuiltinType::kTranspose, CallParamType::kF32, "transpose"},
+ BuiltinData{BuiltinType::kTranspose, CallParamType::kF16, "transpose"},
+ /* Vector built-in */
+ BuiltinData{BuiltinType::kDot, CallParamType::kF32, "dot"},
+ BuiltinData{BuiltinType::kDot, CallParamType::kF16, "dot"},
+ /* Derivate built-in */
+ BuiltinData{BuiltinType::kDpdx, CallParamType::kF32, "dFdx"},
+ BuiltinData{BuiltinType::kDpdxCoarse, CallParamType::kF32, "dFdx"},
+ BuiltinData{BuiltinType::kDpdxFine, CallParamType::kF32, "dFdx"},
+ BuiltinData{BuiltinType::kDpdy, CallParamType::kF32, "dFdy"},
+ BuiltinData{BuiltinType::kDpdyCoarse, CallParamType::kF32, "dFdy"},
+ BuiltinData{BuiltinType::kDpdyFine, CallParamType::kF32, "dFdy"},
+ BuiltinData{BuiltinType::kFwidth, CallParamType::kF32, "fwidth"},
+ BuiltinData{BuiltinType::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+ BuiltinData{BuiltinType::kFwidthFine, CallParamType::kF32, "fwidth"}));
TEST_F(GlslGeneratorImplTest_Builtin, Builtin_Call) {
auto* call = Call("dot", "param1", "param2");
- Global("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
@@ -279,7 +377,42 @@ TEST_F(GlslGeneratorImplTest_Builtin, Select_Vector) {
EXPECT_EQ(out.str(), "mix(ivec2(1, 2), ivec2(3, 4), bvec2(true, false))");
}
-TEST_F(GlslGeneratorImplTest_Builtin, Modf_Scalar) {
+TEST_F(GlslGeneratorImplTest_Builtin, FMA_f32) {
+ auto* call = Call("fma", "a", "b", "c");
+
+ GlobalVar("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+ EXPECT_EQ(out.str(), "((a) * (b) + (c))");
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, FMA_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("a", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* call = Call("fma", "a", "b", "c");
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+ EXPECT_EQ(out.str(), "((a) * (b) + (c))");
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Modf_Scalar_f32) {
auto* call = Call("modf", 1_f);
WrapInFunction(CallStmt(call));
@@ -312,7 +445,43 @@ void main() {
)");
}
-TEST_F(GlslGeneratorImplTest_Builtin, Modf_Vector) {
+TEST_F(GlslGeneratorImplTest_Builtin, Modf_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", 1_h);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct modf_result_f16 {
+ float16_t fract;
+ float16_t whole;
+};
+
+modf_result_f16 tint_modf(float16_t param_0) {
+ modf_result_f16 result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+
+void test_function() {
+ tint_modf(1.0hf);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+}
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Modf_Vector_f32) {
auto* call = Call("modf", vec3<f32>());
WrapInFunction(CallStmt(call));
@@ -345,7 +514,43 @@ void main() {
)");
}
-TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Scalar_i32) {
+TEST_F(GlslGeneratorImplTest_Builtin, Modf_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", vec3<f16>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct modf_result_vec3_f16 {
+ f16vec3 fract;
+ f16vec3 whole;
+};
+
+modf_result_vec3_f16 tint_modf(f16vec3 param_0) {
+ modf_result_vec3_f16 result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+
+void test_function() {
+ tint_modf(f16vec3(0.0hf));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+}
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Scalar_f32) {
auto* call = Call("frexp", 1_f);
WrapInFunction(CallStmt(call));
@@ -372,7 +577,42 @@ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
)"));
}
-TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Vector_i32) {
+TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", 1_h);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr(R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct frexp_result_f16 {
+ float16_t sig;
+ int exp;
+};
+
+frexp_result_f16 tint_frexp(float16_t param_0) {
+ frexp_result_f16 result;
+ result.sig = frexp(param_0, result.exp);
+ return result;
+}
+
+
+void test_function() {
+ tint_frexp(1.0hf);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+)"));
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Vector_f32) {
auto* call = Call("frexp", vec3<f32>());
WrapInFunction(CallStmt(call));
@@ -404,7 +644,43 @@ void main() {
)"));
}
-TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Scalar) {
+TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", vec3<f16>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr(R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct frexp_result_vec3_f16 {
+ f16vec3 sig;
+ ivec3 exp;
+};
+
+frexp_result_vec3_f16 tint_frexp(f16vec3 param_0) {
+ frexp_result_vec3_f16 result;
+ result.sig = frexp(param_0, result.exp);
+ return result;
+}
+
+
+void test_function() {
+ tint_frexp(f16vec3(0.0hf));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+}
+)"));
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Scalar_f32) {
auto* val = Var("val", ty.f32());
auto* call = Call("degrees", val);
WrapInFunction(val, call);
@@ -415,7 +691,7 @@ TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Scalar) {
EXPECT_EQ(gen.result(), R"(#version 310 es
float tint_degrees(float param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082322865f;
}
@@ -432,7 +708,7 @@ void main() {
)");
}
-TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Vector) {
+TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Vector_f32) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("degrees", val);
WrapInFunction(val, call);
@@ -443,7 +719,7 @@ TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Vector) {
EXPECT_EQ(gen.result(), R"(#version 310 es
vec3 tint_degrees(vec3 param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082322865f;
}
@@ -460,7 +736,69 @@ void main() {
)");
}
-TEST_F(GlslGeneratorImplTest_Builtin, Radians_Scalar) {
+TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.f16());
+ auto* call = Call("degrees", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+float16_t tint_degrees(float16_t param_0) {
+ return param_0 * 57.295779513082322865hf;
+}
+
+
+void test_function() {
+ float16_t val = 0.0hf;
+ float16_t tint_symbol = tint_degrees(val);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+}
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.vec3<f16>());
+ auto* call = Call("degrees", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+f16vec3 tint_degrees(f16vec3 param_0) {
+ return param_0 * 57.295779513082322865hf;
+}
+
+
+void test_function() {
+ f16vec3 val = f16vec3(0.0hf, 0.0hf, 0.0hf);
+ f16vec3 tint_symbol = tint_degrees(val);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+}
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Radians_Scalar_f32) {
auto* val = Var("val", ty.f32());
auto* call = Call("radians", val);
WrapInFunction(val, call);
@@ -471,7 +809,7 @@ TEST_F(GlslGeneratorImplTest_Builtin, Radians_Scalar) {
EXPECT_EQ(gen.result(), R"(#version 310 es
float tint_radians(float param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295474f;
}
@@ -488,7 +826,7 @@ void main() {
)");
}
-TEST_F(GlslGeneratorImplTest_Builtin, Radians_Vector) {
+TEST_F(GlslGeneratorImplTest_Builtin, Radians_Vector_f32) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("radians", val);
WrapInFunction(val, call);
@@ -499,7 +837,7 @@ TEST_F(GlslGeneratorImplTest_Builtin, Radians_Vector) {
EXPECT_EQ(gen.result(), R"(#version 310 es
vec3 tint_radians(vec3 param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295474f;
}
@@ -516,6 +854,68 @@ void main() {
)");
}
+TEST_F(GlslGeneratorImplTest_Builtin, Radians_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.f16());
+ auto* call = Call("radians", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+float16_t tint_radians(float16_t param_0) {
+ return param_0 * 0.017453292519943295474hf;
+}
+
+
+void test_function() {
+ float16_t val = 0.0hf;
+ float16_t tint_symbol = tint_radians(val);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+}
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Builtin, Radians_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.vec3<f16>());
+ auto* call = Call("radians", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+f16vec3 tint_radians(f16vec3 param_0) {
+ return param_0 * 0.017453292519943295474hf;
+}
+
+
+void test_function() {
+ f16vec3 val = f16vec3(0.0hf, 0.0hf, 0.0hf);
+ f16vec3 tint_symbol = tint_radians(val);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ test_function();
+ return;
+}
+)");
+}
+
TEST_F(GlslGeneratorImplTest_Builtin, ExtractBits) {
auto* v = Var("v", ty.vec3<u32>());
auto* offset = Var("offset", ty.u32());
@@ -586,7 +986,7 @@ void main() {
TEST_F(GlslGeneratorImplTest_Builtin, Pack4x8Snorm) {
auto* call = Call("pack4x8snorm", "p1");
- Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -604,7 +1004,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Pack4x8Unorm) {
auto* call = Call("pack4x8unorm", "p1");
- Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -622,7 +1022,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Snorm) {
auto* call = Call("pack2x16snorm", "p1");
- Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -640,7 +1040,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Unorm) {
auto* call = Call("pack2x16unorm", "p1");
- Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -658,7 +1058,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Float) {
auto* call = Call("pack2x16float", "p1");
- Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -676,7 +1076,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Unpack4x8Snorm) {
auto* call = Call("unpack4x8snorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -694,7 +1094,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Unpack4x8Unorm) {
auto* call = Call("unpack4x8unorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -712,7 +1112,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Snorm) {
auto* call = Call("unpack2x16snorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -730,7 +1130,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Unorm) {
auto* call = Call("unpack2x16unorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -748,7 +1148,7 @@ void test_function() {
TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Float) {
auto* call = Call("unpack2x16float", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -765,8 +1165,11 @@ void test_function() {
}
TEST_F(GlslGeneratorImplTest_Builtin, StorageBarrier) {
- Func("main", {}, ty.void_(), {CallStmt(Call("storageBarrier"))},
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("storageBarrier")),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -785,8 +1188,11 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Builtin, WorkgroupBarrier) {
- Func("main", {}, ty.void_(), {CallStmt(Call("workgroupBarrier"))},
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("workgroupBarrier")),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -805,7 +1211,7 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Builtin, DotI32) {
- Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(Call("dot", "v", "v")));
GeneratorImpl& gen = SanitizeAndBuild();
@@ -830,25 +1236,8 @@ void main() {
)");
}
-TEST_F(GlslGeneratorImplTest_Builtin, FMA) {
- auto* call = Call("fma", "a", "b", "c");
-
- Global("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("c", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-
- WrapInFunction(CallStmt(call));
-
- GeneratorImpl& gen = Build();
-
- gen.increment_indent();
- std::stringstream out;
- ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
- EXPECT_EQ(out.str(), "((a) * (b) + (c))");
-}
-
TEST_F(GlslGeneratorImplTest_Builtin, DotU32) {
- Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+ GlobalVar("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(Call("dot", "v", "v")));
GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
index 42db16b852b..8a22798202c 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
@@ -278,7 +278,8 @@ TEST_P(GlslGeneratorBuiltinTextureTest, Call) {
auto* call = Call(param.function, param.args(this));
auto* stmt = CallStmt(call);
- Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_call_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_call_test.cc
index c8a1de26e9c..d264896f722 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_call_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_call_test.cc
@@ -23,7 +23,7 @@ namespace {
using GlslGeneratorImplTest_Call = TestHelper;
TEST_F(GlslGeneratorImplTest_Call, EmitExpression_Call_WithoutParams) {
- Func("my_func", {}, ty.f32(), {Return(1.23_f)});
+ Func("my_func", utils::Empty, ty.f32(), utils::Vector{Return(1.23_f)});
auto* call = Call("my_func");
WrapInFunction(call);
@@ -37,13 +37,13 @@ TEST_F(GlslGeneratorImplTest_Call, EmitExpression_Call_WithoutParams) {
TEST_F(GlslGeneratorImplTest_Call, EmitExpression_Call_WithParams) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.f32(), {Return(1.23_f)});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.f32(), utils::Vector{Return(1.23_f)});
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = Call("my_func", "param1", "param2");
WrapInFunction(call);
@@ -57,13 +57,13 @@ TEST_F(GlslGeneratorImplTest_Call, EmitExpression_Call_WithParams) {
TEST_F(GlslGeneratorImplTest_Call, EmitStatement_Call) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.void_(), ast::StatementList{}, ast::AttributeList{});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.void_(), utils::Empty, utils::Empty);
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = CallStmt(Call("my_func", "param1", "param2"));
WrapInFunction(call);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_case_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_case_test.cc
index 02d16654da9..1f607810860 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_case_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_case_test.cc
@@ -69,7 +69,13 @@ TEST_F(GlslGeneratorImplTest_Case, Emit_Case_WithFallthrough) {
}
TEST_F(GlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
- auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+ auto* s = Switch(1_i,
+ Case(
+ utils::Vector{
+ Expr(5_i),
+ Expr(6_i),
+ },
+ Block(create<ast::BreakStatement>())),
DefaultCase());
WrapInFunction(s);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_constructor_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_constructor_test.cc
index e70ecaf6617..5b65c2b5344 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_constructor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_constructor_test.cc
@@ -61,6 +61,18 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Float) {
EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
}
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_F16) {
+ Enable(ast::Extension::kF16);
+
+ // Use a number close to 1<<16 but whose decimal representation ends in 0.
+ WrapInFunction(Expr(f16((1 << 15) - 8)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("32752.0hf"));
+}
+
TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Float) {
WrapInFunction(Construct<f32>(-1.2e-5_f));
@@ -70,6 +82,17 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Float) {
EXPECT_THAT(gen.result(), HasSubstr("-0.000012f"));
}
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(Construct<f16>(-1.2e-3_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("-0.00119972229hf"));
+}
+
TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Bool) {
WrapInFunction(Construct<bool>(true));
@@ -97,7 +120,7 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Uint) {
EXPECT_THAT(gen.result(), HasSubstr("12345u"));
}
-TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec) {
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_F32) {
WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
GeneratorImpl& gen = Build();
@@ -106,7 +129,18 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec) {
EXPECT_THAT(gen.result(), HasSubstr("vec3(1.0f, 2.0f, 3.0f)"));
}
-TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("f16vec3(1.0hf, 2.0hf, 3.0hf)"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty_F32) {
WrapInFunction(vec3<f32>());
GeneratorImpl& gen = Build();
@@ -115,7 +149,18 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
EXPECT_THAT(gen.result(), HasSubstr("vec3(0.0f)"));
}
-TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Float) {
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>());
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("f16vec3(0.0hf)"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F32_Literal) {
WrapInFunction(vec3<f32>(2_f));
GeneratorImpl& gen = Build();
@@ -124,6 +169,43 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_
EXPECT_THAT(gen.result(), HasSubstr("vec3(2.0f)"));
}
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F16_Literal) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(2_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("f16vec3(2.0hf)"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F32_Var) {
+ auto* var = Var("v", nullptr, Expr(2_f));
+ auto* cast = vec3<f32>(var);
+ WrapInFunction(var, cast);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr(R"(float v = 2.0f;
+ vec3 tint_symbol = vec3(v);)"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F16_Var) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("v", nullptr, Expr(2_h));
+ auto* cast = vec3<f16>(var);
+ WrapInFunction(var, cast);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr(R"(float16_t v = 2.0hf;
+ f16vec3 tint_symbol = f16vec3(v);)"));
+}
+
TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Bool) {
WrapInFunction(vec3<bool>(true));
@@ -151,7 +233,7 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_
EXPECT_THAT(gen.result(), HasSubstr("uvec3(2u)"));
}
-TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat) {
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_F32) {
WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
GeneratorImpl& gen = Build();
@@ -161,14 +243,135 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat) {
EXPECT_THAT(gen.result(), HasSubstr("mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(3.0f, 4.0f, 5.0f))"));
}
-TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty) {
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("f16mat2x3(f16vec3(1.0hf, 2.0hf, 3.0hf), f16vec3(3.0hf, 4.0hf, 5.0hf))"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Complex_F32) {
+ // mat4x4<f32>(
+ // vec4<f32>(2.0f, 3.0f, 4.0f, 8.0f),
+ // vec4<f32>(),
+ // vec4<f32>(7.0f),
+ // vec4<f32>(vec4<f32>(42.0f, 21.0f, 6.0f, -5.0f)),
+ // );
+ auto* vector_literal =
+ vec4<f32>(Expr(f32(2.0)), Expr(f32(3.0)), Expr(f32(4.0)), Expr(f32(8.0)));
+ auto* vector_zero_ctor = vec4<f32>();
+ auto* vector_single_scalar_ctor = vec4<f32>(Expr(f32(7.0)));
+ auto* vector_identical_ctor =
+ vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
+
+ auto* constructor = mat4x4<f32>(vector_literal, vector_zero_ctor, vector_single_scalar_ctor,
+ vector_identical_ctor);
+
+ WrapInFunction(constructor);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("mat4(vec4(2.0f, 3.0f, 4.0f, 8.0f), vec4(0.0f), "
+ "vec4(7.0f), vec4(42.0f, 21.0f, 6.0f, -5.0f))"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Complex_F16) {
+ // mat4x4<f16>(
+ // vec4<f16>(2.0h, 3.0h, 4.0h, 8.0h),
+ // vec4<f16>(),
+ // vec4<f16>(7.0h),
+ // vec4<f16>(vec4<f16>(42.0h, 21.0h, 6.0h, -5.0h)),
+ // );
+ Enable(ast::Extension::kF16);
+
+ auto* vector_literal =
+ vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
+ auto* vector_zero_ctor = vec4<f16>();
+ auto* vector_single_scalar_ctor = vec4<f16>(Expr(f16(7.0)));
+ auto* vector_identical_ctor =
+ vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
+
+ auto* constructor = mat4x4<f16>(vector_literal, vector_zero_ctor, vector_single_scalar_ctor,
+ vector_identical_ctor);
+
+ WrapInFunction(constructor);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("f16mat4(f16vec4(2.0hf, 3.0hf, 4.0hf, 8.0hf), f16vec4(0.0hf), "
+ "f16vec4(7.0hf), f16vec4(42.0hf, 21.0hf, 6.0hf, -5.0hf))"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty_F32) {
WrapInFunction(mat2x3<f32>());
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr("mat2x3(vec3(0.0f), vec3(0.0f)"));
+ EXPECT_THAT(gen.result(), HasSubstr("mat2x3 tint_symbol = mat2x3(vec3(0.0f), vec3(0.0f))"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(mat2x3<f16>());
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("f16mat2x3 tint_symbol = f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf))"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Identity_F32) {
+ // fn f() {
+ // var m_1: mat4x4<f32> = mat4x4<f32>();
+ // var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
+ // }
+
+ auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), mat4x4<f32>());
+ auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), mat4x4<f32>(m_1));
+
+ WrapInFunction(m_1, m_2);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("mat4 m_2 = mat4(m_1);"));
+}
+
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Identity_F16) {
+ // fn f() {
+ // var m_1: mat4x4<f16> = mat4x4<f16>();
+ // var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
+ // }
+
+ Enable(ast::Extension::kF16);
+
+ auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
+ auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
+
+ WrapInFunction(m_1, m_2);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("f16mat4 m_2 = f16mat4(m_1);"));
}
TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array) {
@@ -189,12 +392,11 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array_Empty) {
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f),"
- " vec3(0.0f, 0.0f, 0.0f))"));
+ EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(0.0f), vec3(0.0f), vec3(0.0f))"));
}
TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
Member("c", ty.vec3<i32>()),
@@ -209,7 +411,7 @@ TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
}
TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
Member("c", ty.vec3<i32>()),
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_function_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_function_test.cc
index c5bccf263b6..cc01e5d5212 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -28,8 +28,8 @@ namespace {
using GlslGeneratorImplTest_Function = TestHelper;
TEST_F(GlslGeneratorImplTest_Function, Emit_Function) {
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
});
@@ -48,8 +48,8 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Function) {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
- Func("centroid", ast::VariableList{}, ty.void_(),
- {
+ Func("centroid", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
});
@@ -64,8 +64,13 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithParams) {
- Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())}, ty.void_(),
- {
+ Func("my_func",
+ utils::Vector{
+ Param("a", ty.f32()),
+ Param("b", ty.i32()),
+ },
+ ty.void_(),
+ utils::Vector{
Return(),
});
@@ -84,8 +89,8 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithParams) {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_NoReturn_Void) {
- Func("func", ast::VariableList{}, ty.void_(), {/* no explicit return */},
- {
+ Func("func", utils::Empty, ty.void_(), utils::Empty /* no explicit return */,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -105,8 +110,8 @@ TEST_F(GlslGeneratorImplTest_Function, PtrParameter) {
// fn f(foo : ptr<function, f32>) -> f32 {
// return *foo;
// }
- Func("f", {Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))}, ty.f32(),
- {Return(Deref("foo"))});
+ Func("f", utils::Vector{Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))}, ty.f32(),
+ utils::Vector{Return(Deref("foo"))});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -121,9 +126,20 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOutVars)
// fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
// return foo;
// }
- auto* foo_in = Param("foo", ty.f32(), {Location(0)});
- Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
- {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
+ Func("frag_main",
+ utils::Vector{
+ Param("foo", ty.f32(), utils::Vector{Location(0)}),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return("foo"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(1),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -149,9 +165,22 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOut_Built
// fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
// return coord.x;
// }
- auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
- Func("frag_main", ast::VariableList{coord_in}, ty.f32(), {Return(MemberAccessor("coord", "x"))},
- {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
+ auto* coord_in =
+ Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+ Func("frag_main",
+ utils::Vector{
+ coord_in,
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(MemberAccessor("coord", "x")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFragDepth),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -186,24 +215,25 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_SharedStruct_Di
// const p = inputs.pos;
// }
auto* interface_struct = Structure(
- "Interface", {
- Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
- Member("col1", ty.f32(), {Location(1)}),
- Member("col2", ty.f32(), {Location(2)}),
- });
-
- Func("vert_main", {}, ty.Of(interface_struct),
- {Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()), Expr(0.5_f),
- Expr(0.25_f)))},
- {Stage(ast::PipelineStage::kVertex)});
-
- Func("frag_main", {Param("inputs", ty.Of(interface_struct))}, ty.void_(),
- {
+ "Interface",
+ utils::Vector{
+ Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+ Member("col1", ty.f32(), utils::Vector{Location(1)}),
+ Member("col2", ty.f32(), utils::Vector{Location(2)}),
+ });
+
+ Func("vert_main", utils::Empty, ty.Of(interface_struct),
+ utils::Vector{Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()),
+ Expr(0.5_f), Expr(0.25_f)))},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
+
+ Func("frag_main", utils::Vector{Param("inputs", ty.Of(interface_struct))}, ty.void_(),
+ utils::Vector{
Decl(Let("r", ty.f32(), MemberAccessor("inputs", "col1"))),
Decl(Let("g", ty.f32(), MemberAccessor("inputs", "col2"))),
Decl(Let("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
},
- {Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -267,19 +297,19 @@ TEST_F(GlslGeneratorImplTest_Function,
// }
auto* vertex_output_struct = Structure(
"VertexOutput",
- {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+ {Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
- Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
+ Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
{Return(Construct(ty.Of(vertex_output_struct),
Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1_f))))},
{});
- Func("vert_main1", {}, ty.Of(vertex_output_struct),
+ Func("vert_main1", utils::Empty, ty.Of(vertex_output_struct),
{Return(Construct(ty.Of(vertex_output_struct),
Expr(Call("foo", Expr(0.5_f)))))},
{Stage(ast::PipelineStage::kVertex)});
- Func("vert_main2", {}, ty.Of(vertex_output_struct),
+ Func("vert_main2", utils::Empty, ty.Of(vertex_output_struct),
{Return(Construct(ty.Of(vertex_output_struct),
Expr(Call("foo", Expr(0.25_f)))))},
{Stage(ast::PipelineStage::kVertex)});
@@ -320,30 +350,30 @@ tint_symbol_2 vert_main2() {
#endif
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_Uniform) {
- auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
- auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ auto* ubo_ty = Structure("UBO", utils::Vector{Member("coord", ty.vec4<f32>())});
+ auto* ubo = GlobalVar("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
Func("sub_func",
- {
+ utils::Vector{
Param("param", ty.f32()),
},
ty.f32(),
- {
+ utils::Vector{
Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
});
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", {}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -373,23 +403,23 @@ void frag_main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_UniformStruct) {
- auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())});
+ auto* s = Structure("Uniforms", utils::Vector{Member("coord", ty.vec4<f32>())});
- Global("uniforms", ty.Of(s), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("uniforms", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -415,25 +445,25 @@ void frag_main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RW_StorageBuffer_Read) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -465,25 +495,25 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RO_StorageBuffer_Read) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -516,23 +546,23 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_WO_StorageBuffer_Store) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(MemberAccessor("coord", "b"), Expr(2_f)),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -564,23 +594,23 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_StorageBuffer_Store) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(MemberAccessor("coord", "b"), Expr(2_f)),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -612,26 +642,26 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
- auto* s = Structure("S", {Member("x", ty.f32())});
- Global("coord", ty.Of(s), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
-
- Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
- {
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
+
+ Func("sub_func", utils::Vector{Param("param", ty.f32())}, ty.f32(),
+ utils::Vector{
Return(MemberAccessor("coord", "x")),
});
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -661,26 +691,26 @@ void frag_main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
- auto* s = Structure("S", {Member("x", ty.f32())});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
-
- Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
- {
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
+
+ Func("sub_func", utils::Vector{Param("param", ty.f32())}, ty.f32(),
+ utils::Vector{
Return(MemberAccessor("coord", "x")),
});
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -715,8 +745,8 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithNameCollision) {
- Func("centroid", ast::VariableList{}, ty.void_(), {},
- {
+ Func("centroid", utils::Empty, ty.void_(), {},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -737,11 +767,14 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute) {
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
GeneratorImpl& gen = Build();
@@ -756,8 +789,8 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Literal) {
- Func("main", ast::VariableList{}, ty.void_(), {},
- {
+ Func("main", utils::Empty, ty.void_(), {},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(2_i, 4_i, 6_i),
});
@@ -778,8 +811,8 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWor
GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
- Func("main", ast::VariableList{}, ty.void_(), {},
- {
+ Func("main", utils::Empty, ty.void_(), {},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize("width", "height", "depth"),
});
@@ -789,9 +822,6 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWor
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(#version 310 es
-const int width = 2;
-const int height = 3;
-const int depth = 4;
layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) in;
void main() {
return;
@@ -801,11 +831,11 @@ void main() {
TEST_F(GlslGeneratorImplTest_Function,
Emit_Attribute_EntryPoint_Compute_WithWorkgroup_OverridableConst) {
- Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
- Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
- Override("depth", ty.i32(), Construct(ty.i32(), 4_i), {Id(9u)});
- Func("main", ast::VariableList{}, ty.void_(), {},
- {
+ Override("width", ty.i32(), Construct(ty.i32(), 2_i), utils::Vector{Id(7u)});
+ Override("height", ty.i32(), Construct(ty.i32(), 3_i), utils::Vector{Id(8u)});
+ Override("depth", ty.i32(), Construct(ty.i32(), 4_i), utils::Vector{Id(9u)});
+ Func("main", utils::Empty, ty.void_(), {},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize("width", "height", "depth"),
});
@@ -835,8 +865,8 @@ void main() {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
- Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
- {
+ Func("my_func", utils::Vector{Param("a", ty.array<f32, 5>())}, ty.void_(),
+ utils::Vector{
Return(),
});
@@ -853,8 +883,8 @@ void my_func(float a[5]) {
}
TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithArrayReturn) {
- Func("my_func", {}, ty.array<f32, 5>(),
- {
+ Func("my_func", utils::Empty, ty.array<f32, 5>(),
+ utils::Vector{
Return(Construct(ty.array<f32, 5>())),
});
@@ -889,34 +919,40 @@ TEST_F(GlslGeneratorImplTest_Function, Emit_Multiple_EntryPoint_With_Same_Module
// return;
// }
- auto* s = Structure("Data", {Member("d", ty.f32())});
+ auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
- Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("a", ast::VariableList{}, ty.void_(),
- {
+ Func("a", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
}
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("b", ast::VariableList{}, ty.void_(),
- {
+ Func("b", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
}
GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_identifier_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_identifier_test.cc
index 396c261f20b..ff9bc88c720 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_identifier_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_identifier_test.cc
@@ -20,7 +20,7 @@ namespace {
using GlslGeneratorImplTest_Identifier = TestHelper;
TEST_F(GlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
- Global("foo", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("foo", ty.i32(), ast::StorageClass::kPrivate);
auto* i = Expr("foo");
WrapInFunction(i);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_if_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_if_test.cc
index 4b0b7bbe7a9..82dc307abca 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_if_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_if_test.cc
@@ -20,7 +20,7 @@ namespace {
using GlslGeneratorImplTest_If = TestHelper;
TEST_F(GlslGeneratorImplTest_If, Emit_If) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* cond = Expr("cond");
auto* body = Block(Return());
@@ -38,8 +38,8 @@ TEST_F(GlslGeneratorImplTest_If, Emit_If) {
}
TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElseIf) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
- Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_cond = Expr("else_cond");
auto* else_body = Block(Return());
@@ -65,7 +65,7 @@ TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElseIf) {
}
TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElse) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_body = Block(Return());
@@ -88,8 +88,8 @@ TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElse) {
}
TEST_F(GlslGeneratorImplTest_If, Emit_IfWithMultiple) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
- Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_cond = Expr("else_cond");
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_import_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_import_test.cc
index 2843f98b2ef..9e988f13620 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_import_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_import_test.cc
@@ -256,7 +256,7 @@ INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
testing::Values(GlslImportData{"clamp", "clamp"}));
TEST_F(GlslGeneratorImplTest_Import, GlslImportData_Determinant) {
- Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("determinant", "var");
WrapInFunction(expr);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_loop_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_loop_test.cc
index 5187dafdb98..9da50f0a91b 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_loop_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_loop_test.cc
@@ -66,8 +66,8 @@ TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
Func("a_statement", {}, ty.void_(), {});
- Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
- Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("lhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.f32(), ast::StorageClass::kPrivate);
auto* body = Block(create<ast::DiscardStatement>());
auto* continuing = Block(CallStmt(Call("a_statement")));
@@ -112,7 +112,7 @@ TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithVarUsedInContinuing) {
// }
// }
- Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.f32(), ast::StorageClass::kPrivate);
auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4_f))), //
Decl(Var("other", ty.f32())), //
@@ -381,5 +381,71 @@ TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInitCondCont) {
)");
}
+TEST_F(GlslGeneratorImplTest_Loop, Emit_While) {
+ // while(true) {
+ // return;
+ // }
+
+ auto* f = While(Expr(true), Block(Return()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while(true) {
+ return;
+ }
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Loop, Emit_While_WithContinue) {
+ // while(true) {
+ // continue;
+ // }
+
+ auto* f = While(Expr(true), Block(Continue()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while(true) {
+ continue;
+ }
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_Loop, Emit_WhileWithMultiStmtCond) {
+ // while(true && false) {
+ // return;
+ // }
+
+ Func("a_statement", {}, ty.void_(), {});
+
+ auto* multi_stmt =
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+ auto* f = While(multi_stmt, Block(CallStmt(Call("a_statement"))));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while (true) {
+ bool tint_tmp = true;
+ if (tint_tmp) {
+ tint_tmp = false;
+ }
+ if (!((tint_tmp))) { break; }
+ a_statement();
+ }
+)");
+}
+
} // namespace
} // namespace tint::writer::glsl
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_member_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
index 4f7fdb1ee5d..ba6dc43f4d9 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
@@ -86,22 +86,19 @@ inline const ast::Type* ty_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
template <typename BASE>
class GlslGeneratorImplTest_MemberAccessorBase : public BASE {
public:
- void SetupStorageBuffer(ast::StructMemberList members) {
+ void SetupStorageBuffer(utils::VectorRef<const ast::StructMember*> members) {
ProgramBuilder& b = *this;
auto* s = b.Structure("Data", members);
- b.Global("data", b.ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- b.create<ast::BindingAttribute>(0),
- b.create<ast::GroupAttribute>(1),
- });
+ b.GlobalVar("data", b.ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(1u, 0u));
}
- void SetupFunction(ast::StatementList statements) {
+ void SetupFunction(utils::VectorRef<const ast::Statement*> statements) {
ProgramBuilder& b = *this;
- b.Func("main", ast::VariableList{}, b.ty.void_(), statements,
- ast::AttributeList{
+ b.Func("main", utils::Empty, b.ty.void_(), statements,
+ utils::Vector<const ast::Attribute*, 1>{
b.Stage(ast::PipelineStage::kFragment),
});
}
@@ -114,8 +111,8 @@ using GlslGeneratorImplTest_MemberAccessorWithParam =
GlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
TEST_F(GlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
- auto* s = Structure("Data", {Member("mem", ty.f32())});
- Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+ auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
+ GlobalVar("str", ty.Of(s), ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("str", "mem");
WrapInFunction(Var("expr", ty.f32(), ast::StorageClass::kNone, expr));
@@ -165,12 +162,12 @@ TEST_P(GlslGeneratorImplTest_MemberAccessor_StorageBufferLoad, Test) {
auto p = GetParam();
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("a", ty.i32()),
Member("b", p.member_type(ty)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone, MemberAccessor("data", "b"))),
});
@@ -216,12 +213,12 @@ TEST_P(GlslGeneratorImplTest_MemberAccessor_StorageBufferStore, Test) {
auto p = GetParam();
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("a", ty.i32()),
Member("b", p.member_type(ty)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("value", p.member_type(ty), ast::StorageClass::kNone,
Construct(p.member_type(ty)))),
Assign(MemberAccessor("data", "b"), Expr("value")),
@@ -265,13 +262,13 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Matrix_Empty) {
// var<storage> data : Data;
// data.a = mat2x3<f32>();
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("a", ty.i32()),
Member("b", ty.mat2x3<f32>()),
});
- SetupFunction({
- Assign(MemberAccessor("data", "b"), Construct(ty.mat2x3<f32>(), ast::ExpressionList{})),
+ SetupFunction(utils::Vector{
+ Assign(MemberAccessor("data", "b"), Construct(ty.mat2x3<f32>())),
});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -310,12 +307,12 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_Matrix_Single_El
// var<storage> data : Data;
// data.a[2i][1i];
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.mat4x3<f32>()),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
});
@@ -356,12 +353,12 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Data;
// data.a[2];
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.array<i32, 5>(4)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
IndexAccessor(MemberAccessor("data", "a"), 2_i))),
});
@@ -402,14 +399,17 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Data;
// data.a[(2i + 4i) - 3i];
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.array<i32, 5>(4)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
+ Decl(Var("a", nullptr, Expr(2_i))),
+ Decl(Var("b", nullptr, Expr(4_i))),
+ Decl(Var("c", nullptr, Expr(3_i))),
Decl(Var("x", nullptr, ast::StorageClass::kNone,
- IndexAccessor(MemberAccessor("data", "a"), Sub(Add(2_i, 4_i), 3_i)))),
+ IndexAccessor(MemberAccessor("data", "a"), Sub(Add("a", "b"), "c")))),
});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -429,7 +429,10 @@ layout(binding = 0, std430) buffer Data_1 {
int a[5];
} data;
void tint_symbol() {
- int x = data.a[((2 + 4) - 3)];
+ int a = 2;
+ int b = 4;
+ int c = 3;
+ int x = data.a[((a + b) - c)];
}
void main() {
@@ -447,12 +450,12 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
// var<storage> data : Data;
// data.a[2i] = 2i;
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.array<i32, 5>(4)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Assign(IndexAccessor(MemberAccessor("data", "a"), 2_i), 2_i),
});
@@ -496,16 +499,16 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
// var<storage> data : Pre;
// data.c[2i].b
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"))),
});
@@ -553,16 +556,16 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Swizz
// var<storage> data : Pre;
// data.c[2i].b.xy
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
MemberAccessor(
MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "xy"))),
@@ -612,16 +615,16 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Pre;
// data.c[2i].b.g
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
MemberAccessor(
MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "g"))),
@@ -670,16 +673,16 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Index
// var<storage> data : Pre;
// data.c[2i].b[1i]
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
IndexAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
1_i))),
@@ -728,16 +731,16 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
// var<storage> data : Pre;
// data.c[2i].b = vec3<f32>(1.f, 2.f, 3.f);
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
vec3<f32>(1_f, 2_f, 3_f)),
});
@@ -785,16 +788,16 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Swizzle_SingleL
// var<storage> data : Pre;
// data.c[2i].b.y = 1.f;
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<i32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Assign(MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
"y"),
Expr(1_f)),
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_module_constant_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_module_constant_test.cc
index 223122afb83..44cbb53987e 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_module_constant_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_module_constant_test.cc
@@ -22,7 +22,7 @@ namespace {
using GlslGeneratorImplTest_ModuleConstant = TestHelper;
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalLet) {
auto* var = Let("pos", ty.array<f32, 3>(), array<f32, 3>(1_f, 2_f, 3_f));
WrapInFunction(Decl(var));
@@ -32,15 +32,329 @@ TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
EXPECT_EQ(gen.result(), "const float pos[3] = float[3](1.0f, 2.0f, 3.0f);\n");
}
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AInt) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AFloat) {
+ auto* var = GlobalConst("G", nullptr, Expr(1._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_i32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_i));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_u32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_u));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ uint l = 1u;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, Expr(1_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+void f() {
+ float16_t l = 1.0hf;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AInt) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ ivec3 l = ivec3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AFloat) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f32) {
+ auto* var = GlobalConst("G", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+void f() {
+ f16vec3 l = f16vec3(1.0hf, 2.0hf, 3.0hf);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_AFloat) {
+ auto* var = GlobalConst("G", nullptr,
+ Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f32) {
+ auto* var = GlobalConst("G", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+void f() {
+ f16mat2x3 l = f16mat2x3(f16vec3(1.0hf, 2.0hf, 3.0hf), f16vec3(4.0hf, 5.0hf, 6.0hf));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_f32) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ float l[3] = float[3](1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_vec2_bool) {
+ auto* var = GlobalConst("G", nullptr,
+ Construct(ty.array(ty.vec2<bool>(), 3_u), //
+ vec2<bool>(true, false), //
+ vec2<bool>(false, true), //
+ vec2<bool>(true, true)));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Let("l", nullptr, Expr(var))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ bvec2 l[3] = bvec2[3](bvec2(true, false), bvec2(false, true), bvec2(true));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_Override) {
auto* var = Override("pos", ty.f32(), Expr(3_f),
- ast::AttributeList{
+ utils::Vector{
Id(23),
});
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(var)) << gen.error();
EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
#define WGSL_SPEC_CONSTANT_23 3.0f
#endif
@@ -48,15 +362,15 @@ const float pos = WGSL_SPEC_CONSTANT_23;
)");
}
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_Override_NoConstructor) {
auto* var = Override("pos", ty.f32(), nullptr,
- ast::AttributeList{
+ utils::Vector{
Id(23),
});
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(var)) << gen.error();
EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
#error spec constant required for constant id 23
#endif
@@ -64,17 +378,17 @@ const float pos = WGSL_SPEC_CONSTANT_23;
)");
}
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoId) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_Override_NoId) {
auto* a = Override("a", ty.f32(), Expr(3_f),
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
auto* b = Override("b", ty.f32(), Expr(2_f));
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(a)) << gen.error();
- ASSERT_TRUE(gen.EmitProgramConstVariable(b)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(a)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(b)) << gen.error();
EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_0
#define WGSL_SPEC_CONSTANT_0 3.0f
#endif
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_return_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_return_test.cc
index 59df38514ba..28bbf51b687 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_return_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_return_test.cc
@@ -35,7 +35,7 @@ TEST_F(GlslGeneratorImplTest_Return, Emit_Return) {
TEST_F(GlslGeneratorImplTest_Return, Emit_ReturnWithValue) {
auto* r = Return(123_i);
- Func("f", {}, ty.i32(), {r});
+ Func("f", utils::Empty, ty.i32(), utils::Vector{r});
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_sanitizer_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
index 6575c56c158..c2a4ff28d5b 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
@@ -25,19 +25,19 @@ namespace {
using GlslSanitizerTest = TestHelper;
TEST_F(GlslSanitizerTest, Call_ArrayLength) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -65,22 +65,22 @@ void main() {
}
TEST_F(GlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member(0, "z", ty.f32()),
Member(4, "a", ty.array<f32>(4)),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -110,23 +110,23 @@ void main() {
}
TEST_F(GlslSanitizerTest, Call_ArrayLength_ViaLets) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
auto* p = Let("p", nullptr, AddressOf("b"));
auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(p),
Decl(p2),
Decl(Var("len", ty.u32(), ast::StorageClass::kNone, Call("arrayLength", p2))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -156,14 +156,13 @@ void main() {
TEST_F(GlslSanitizerTest, PromoteArrayInitializerToConstVar) {
auto* array_init = array<i32, 4>(1_i, 2_i, 3_i, 4_i);
- auto* array_index = IndexAccessor(array_init, 3_i);
- auto* pos = Var("pos", ty.i32(), ast::StorageClass::kNone, array_index);
- Func("main", ast::VariableList{}, ty.void_(),
- {
- Decl(pos),
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Var("idx", nullptr, Expr(3_i))),
+ Decl(Var("pos", ty.i32(), IndexAccessor(array_init, "idx"))),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -176,8 +175,9 @@ TEST_F(GlslSanitizerTest, PromoteArrayInitializerToConstVar) {
precision mediump float;
void tint_symbol() {
+ int idx = 3;
int tint_symbol_1[4] = int[4](1, 2, 3, 4);
- int pos = tint_symbol_1[3];
+ int pos = tint_symbol_1[idx];
}
void main() {
@@ -189,7 +189,7 @@ void main() {
}
TEST_F(GlslSanitizerTest, PromoteStructInitializerToConstVar) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.vec3<f32>()),
Member("c", ty.i32()),
@@ -198,11 +198,11 @@ TEST_F(GlslSanitizerTest, PromoteStructInitializerToConstVar) {
auto* struct_access = MemberAccessor(struct_init, "b");
auto* pos = Var("pos", ty.vec3<f32>(), ast::StorageClass::kNone, struct_access);
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(pos),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -241,13 +241,13 @@ TEST_F(GlslSanitizerTest, InlinePtrLetsBasic) {
auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(v));
auto* x = Var("x", ty.i32(), ast::StorageClass::kNone, Deref(p));
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(v),
Decl(p),
Decl(x),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -287,15 +287,15 @@ TEST_F(GlslSanitizerTest, InlinePtrLetsComplexChain) {
AddressOf(IndexAccessor(Deref(mp), 2_i)));
auto* v = Var("v", ty.vec4<f32>(), ast::StorageClass::kNone, Deref(vp));
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(a),
Decl(ap),
Decl(mp),
Decl(vp),
Decl(v),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
index a12fbbcd9d6..0323d749b78 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
@@ -29,17 +29,17 @@ void TestAlign(ProgramBuilder* ctx) {
// @align(256) louie : f32;
// };
// @group(0) @binding(0) var<storage, read_write> nephews : Nephews;
- auto* nephews =
- ctx->Structure("Nephews", {
- ctx->Member("huey", ctx->ty.f32(), {ctx->MemberAlign(256)}),
- ctx->Member("dewey", ctx->ty.f32(), {ctx->MemberAlign(256)}),
- ctx->Member("louie", ctx->ty.f32(), {ctx->MemberAlign(256)}),
- });
- ctx->Global("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage,
- ast::AttributeList{
- ctx->create<ast::BindingAttribute>(0),
- ctx->create<ast::GroupAttribute>(0),
- });
+ auto* nephews = ctx->Structure(
+ "Nephews", utils::Vector{
+ ctx->Member("huey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256)}),
+ ctx->Member("dewey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256)}),
+ ctx->Member("louie", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256)}),
+ });
+ ctx->GlobalVar("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage,
+ utils::Vector{
+ ctx->create<ast::BindingAttribute>(0u),
+ ctx->create<ast::GroupAttribute>(0u),
+ });
}
TEST_F(GlslGeneratorImplTest_StorageBuffer, Align) {
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_switch_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_switch_test.cc
index 1cc42fb639f..c2db3b5ad7f 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_switch_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_switch_test.cc
@@ -22,21 +22,21 @@ namespace {
using GlslGeneratorImplTest_Switch = TestHelper;
TEST_F(GlslGeneratorImplTest_Switch, Emit_Switch) {
- Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.i32(), ast::StorageClass::kPrivate);
auto* def_body = Block(create<ast::BreakStatement>());
- auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
+ auto* def = create<ast::CaseStatement>(utils::Empty, def_body);
- ast::CaseSelectorList case_val;
- case_val.push_back(Expr(5_i));
+ utils::Vector case_val{Expr(5_i)};
auto* case_body = Block(create<ast::BreakStatement>());
auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
- ast::CaseStatementList body;
- body.push_back(case_stmt);
- body.push_back(def);
+ utils::Vector body{
+ case_stmt,
+ def,
+ };
auto* cond = Expr("cond");
auto* s = create<ast::SwitchStatement>(cond, body);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_test.cc
index af2e205d317..919d684b58f 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_test.cc
@@ -29,7 +29,7 @@ TEST_F(GlslGeneratorImplTest, InvalidProgram) {
}
TEST_F(GlslGeneratorImplTest, Generate) {
- Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+ Func("my_func", utils::Empty, ty.void_(), utils::Empty);
GeneratorImpl& gen = Build();
@@ -43,7 +43,7 @@ void my_func() {
}
TEST_F(GlslGeneratorImplTest, GenerateDesktop) {
- Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+ Func("my_func", utils::Empty, ty.void_(), utils::Empty);
GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
@@ -57,11 +57,16 @@ void my_func() {
}
TEST_F(GlslGeneratorImplTest, GenerateSampleIndexES) {
- Global("gl_SampleID", ty.i32(),
- ast::AttributeList{Builtin(ast::Builtin::kSampleIndex),
- Disable(ast::DisabledValidation::kIgnoreStorageClass)},
- ast::StorageClass::kInput);
- Func("my_func", {}, ty.i32(), ast::StatementList{Return(Expr("gl_SampleID"))});
+ GlobalVar("gl_SampleID", ty.i32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleIndex),
+ Disable(ast::DisabledValidation::kIgnoreStorageClass),
+ },
+ ast::StorageClass::kIn);
+ Func("my_func", utils::Empty, ty.i32(),
+ utils::Vector{
+ Return(Expr("gl_SampleID")),
+ });
GeneratorImpl& gen = Build(Version(Version::Standard::kES, 3, 1));
@@ -77,11 +82,16 @@ int my_func() {
}
TEST_F(GlslGeneratorImplTest, GenerateSampleIndexDesktop) {
- Global("gl_SampleID", ty.i32(),
- ast::AttributeList{Builtin(ast::Builtin::kSampleIndex),
- Disable(ast::DisabledValidation::kIgnoreStorageClass)},
- ast::StorageClass::kInput);
- Func("my_func", {}, ty.i32(), ast::StatementList{Return(Expr("gl_SampleID"))});
+ GlobalVar("gl_SampleID", ty.i32(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kSampleIndex),
+ Disable(ast::DisabledValidation::kIgnoreStorageClass),
+ },
+ ast::StorageClass::kIn);
+ Func("my_func", utils::Empty, ty.i32(),
+ utils::Vector{
+ Return(Expr("gl_SampleID")),
+ });
GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_type_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_type_test.cc
index b7daee263a6..aa2afabc130 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_type_test.cc
@@ -33,7 +33,7 @@ using GlslGeneratorImplTest_Type = TestHelper;
TEST_F(GlslGeneratorImplTest_Type, EmitType_Array) {
auto* arr = ty.array<bool, 4>();
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -46,7 +46,7 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_Array) {
TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
auto* arr = ty.array(ty.array<bool, 4>(), 5_u);
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -59,7 +59,7 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5_u), 6_u);
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -72,7 +72,7 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
TEST_F(GlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
auto* arr = ty.array<bool, 4>();
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -105,6 +105,19 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_F32) {
EXPECT_EQ(out.str(), "float");
}
+TEST_F(GlslGeneratorImplTest_Type, EmitType_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* f16 = create<sem::F16>();
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, f16, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+ << gen.error();
+ EXPECT_EQ(out.str(), "float16_t");
+}
+
TEST_F(GlslGeneratorImplTest_Type, EmitType_I32) {
auto* i32 = create<sem::I32>();
@@ -116,7 +129,7 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_I32) {
EXPECT_EQ(out.str(), "int");
}
-TEST_F(GlslGeneratorImplTest_Type, EmitType_Matrix) {
+TEST_F(GlslGeneratorImplTest_Type, EmitType_Matrix_F32) {
auto* f32 = create<sem::F32>();
auto* vec3 = create<sem::Vector>(f32, 3u);
auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
@@ -129,12 +142,27 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_Matrix) {
EXPECT_EQ(out.str(), "mat2x3");
}
+TEST_F(GlslGeneratorImplTest_Type, EmitType_Matrix_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* f16 = create<sem::F16>();
+ auto* vec3 = create<sem::Vector>(f16, 3u);
+ auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+ << gen.error();
+ EXPECT_EQ(out.str(), "f16mat2x3");
+}
+
TEST_F(GlslGeneratorImplTest_Type, EmitType_StructDecl) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -150,11 +178,11 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_StructDecl) {
}
TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -166,11 +194,11 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct) {
}
TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("double", ty.i32()),
Member("float", ty.f32()),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = SanitizeAndBuild();
@@ -183,11 +211,11 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
}
TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct_WithOffsetAttributes) {
- auto* s = Structure("S", {
- Member("a", ty.i32(), {MemberOffset(0)}),
- Member("b", ty.f32(), {MemberOffset(8)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberOffset(0)}),
+ Member("b", ty.f32(), utils::Vector{MemberOffset(8)}),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -213,7 +241,7 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_U32) {
EXPECT_EQ(out.str(), "uint");
}
-TEST_F(GlslGeneratorImplTest_Type, EmitType_Vector) {
+TEST_F(GlslGeneratorImplTest_Type, EmitType_Vector_F32) {
auto* f32 = create<sem::F32>();
auto* vec3 = create<sem::Vector>(f32, 3u);
@@ -225,6 +253,20 @@ TEST_F(GlslGeneratorImplTest_Type, EmitType_Vector) {
EXPECT_EQ(out.str(), "vec3");
}
+TEST_F(GlslGeneratorImplTest_Type, EmitType_Vector_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* f16 = create<sem::F16>();
+ auto* vec3 = create<sem::Vector>(f16, 3u);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+ << gen.error();
+ EXPECT_EQ(out.str(), "f16vec3");
+}
+
TEST_F(GlslGeneratorImplTest_Type, EmitType_Void) {
auto* void_ = create<sem::Void>();
@@ -270,14 +312,19 @@ TEST_P(GlslDepthTexturesTest, Emit) {
auto* t = ty.depth_texture(params.dim);
- Global("tex", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar("tex", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
@@ -297,14 +344,19 @@ using GlslDepthMultisampledTexturesTest = TestHelper;
TEST_F(GlslDepthMultisampledTexturesTest, Emit) {
auto* t = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
- Global("tex", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar("tex", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
@@ -340,14 +392,19 @@ TEST_P(GlslSampledTexturesTest, Emit) {
}
auto* t = ty.sampled_texture(params.dim, datatype);
- Global("tex", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar("tex", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
@@ -474,14 +531,19 @@ TEST_P(GlslStorageTexturesTest, Emit) {
auto* t = ty.storage_texture(params.dim, params.imgfmt, ast::Access::kWrite);
- Global("tex", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ GlobalVar("tex", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_unary_op_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_unary_op_test.cc
index 0e318fcf8c3..22012c800c0 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_unary_op_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@ namespace {
using GlslUnaryOpTest = TestHelper;
TEST_F(GlslUnaryOpTest, AddressOf) {
- Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.f32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
WrapInFunction(op);
@@ -32,7 +32,7 @@ TEST_F(GlslUnaryOpTest, AddressOf) {
}
TEST_F(GlslUnaryOpTest, Complement) {
- Global("expr", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.u32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
WrapInFunction(op);
@@ -44,7 +44,7 @@ TEST_F(GlslUnaryOpTest, Complement) {
}
TEST_F(GlslUnaryOpTest, Indirection) {
- Global("G", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("G", ty.f32(), ast::StorageClass::kPrivate);
auto* p =
Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
@@ -58,7 +58,7 @@ TEST_F(GlslUnaryOpTest, Indirection) {
}
TEST_F(GlslUnaryOpTest, Not) {
- Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.bool_(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
WrapInFunction(op);
@@ -70,7 +70,7 @@ TEST_F(GlslUnaryOpTest, Not) {
}
TEST_F(GlslUnaryOpTest, Negation) {
- Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.i32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
WrapInFunction(op);
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
index 8709b3dadc6..4ea57794761 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
@@ -23,8 +23,8 @@ namespace {
using GlslGeneratorImplTest_UniformBuffer = TestHelper;
TEST_F(GlslGeneratorImplTest_UniformBuffer, Simple) {
- auto* simple = Structure("Simple", {Member("member", ty.f32())});
- Global("simple", ty.Of(simple), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+ auto* simple = Structure("Simple", utils::Vector{Member("member", ty.f32())});
+ GlobalVar("simple", ty.Of(simple), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
GeneratorImpl& gen = Build();
@@ -43,8 +43,8 @@ layout(binding = 0) uniform Simple_1 {
}
TEST_F(GlslGeneratorImplTest_UniformBuffer, Simple_Desktop) {
- auto* simple = Structure("Simple", {Member("member", ty.f32())});
- Global("simple", ty.Of(simple), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+ auto* simple = Structure("Simple", utils::Vector{Member("member", ty.f32())});
+ GlobalVar("simple", ty.Of(simple), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
index 5d95bc66cd1..1ad1c552d4b 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
@@ -16,6 +16,8 @@
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/writer/glsl/test_helper.h"
+using namespace tint::number_suffixes; // NOLINT
+
namespace tint::writer::glsl {
namespace {
@@ -36,7 +38,7 @@ TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement) {
EXPECT_EQ(gen.result(), " float a = 0.0f;\n");
}
-TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Let) {
auto* var = Let("a", ty.f32(), Construct(ty.f32()));
auto* stmt = Decl(var);
WrapInFunction(stmt);
@@ -49,6 +51,348 @@ TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
EXPECT_EQ(gen.result(), " float a = 0.0f;\n");
}
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+ auto* var = Const("a", ty.f32(), Construct(ty.f32()));
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), ""); // Not a mistake - 'const' is inlined
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AInt) {
+ auto* C = Const("C", nullptr, Expr(1_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AFloat) {
+ auto* C = Const("C", nullptr, Expr(1._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_i32) {
+ auto* C = Const("C", nullptr, Expr(1_i));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_u32) {
+ auto* C = Const("C", nullptr, Expr(1_u));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ uint l = 1u;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f32) {
+ auto* C = Const("C", nullptr, Expr(1_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, Expr(1_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+void f() {
+ float16_t l = 1.0hf;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AInt) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ ivec3 l = ivec3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f32) {
+ auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+void f() {
+ f16vec3 l = f16vec3(1.0hf, 2.0hf, 3.0hf);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+ auto* C =
+ Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+ auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+void f() {
+ f16mat2x3 l = f16mat2x3(f16vec3(1.0hf, 2.0hf, 3.0hf), f16vec3(4.0hf, 5.0hf, 6.0hf));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_f32) {
+ auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ float l[3] = float[3](1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+ auto* C = Const("C", nullptr,
+ Construct(ty.array(ty.vec2<bool>(), 3_u), //
+ vec2<bool>(true, false), //
+ vec2<bool>(false, true), //
+ vec2<bool>(true, true)));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+ bvec2 l[3] = bvec2[3](bvec2(true, false), bvec2(false, true), bvec2(true));
+}
+
+)");
+}
+
TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
auto* var = Var("a", ty.array<f32, 5>());
@@ -64,7 +408,7 @@ TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
}
TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
WrapInFunction(Expr("a"));
@@ -76,21 +420,23 @@ TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
EXPECT_THAT(gen.result(), HasSubstr(" float a = 0.0f;\n"));
}
-TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_Private) {
- Global("initializer", ty.f32(), ast::StorageClass::kPrivate);
- Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_f32) {
+ auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
- WrapInFunction(Expr("a"));
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr(R"(float a = initializer;
-)"));
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), R"(vec3 a = vec3(0.0f);
+)");
}
-TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec) {
- auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("a", ty.vec3<f16>(), ast::StorageClass::kNone, vec3<f16>());
auto* stmt = Decl(var);
WrapInFunction(stmt);
@@ -98,11 +444,11 @@ TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initialize
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
- EXPECT_EQ(gen.result(), R"(vec3 a = vec3(0.0f);
+ EXPECT_EQ(gen.result(), R"(f16vec3 a = f16vec3(0.0hf);
)");
}
-TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat) {
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_f32) {
auto* var = Var("a", ty.mat2x3<f32>(), ast::StorageClass::kNone, mat2x3<f32>());
auto* stmt = Decl(var);
@@ -116,5 +462,21 @@ TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initialize
)");
}
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("a", ty.mat2x3<f16>(), ast::StorageClass::kNone, mat2x3<f16>());
+
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(),
+ R"(f16mat2x3 a = f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf));
+)");
+}
+
} // namespace
} // namespace tint::writer::glsl
diff --git a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
index faa675dcded..9b39fda9ae5 100644
--- a/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
@@ -27,10 +27,10 @@ namespace {
using GlslGeneratorImplTest_WorkgroupVar = TestHelper;
TEST_F(GlslGeneratorImplTest_WorkgroupVar, Basic) {
- Global("wg", ty.f32(), ast::StorageClass::kWorkgroup);
+ GlobalVar("wg", ty.f32(), ast::StorageClass::kWorkgroup);
- Func("main", {}, ty.void_(), {Assign("wg", 1.2_f)},
- {
+ Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -43,10 +43,10 @@ TEST_F(GlslGeneratorImplTest_WorkgroupVar, Basic) {
TEST_F(GlslGeneratorImplTest_WorkgroupVar, Aliased) {
auto* alias = Alias("F32", ty.f32());
- Global("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
+ GlobalVar("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
- Func("main", {}, ty.void_(), {Assign("wg", 1.2_f)},
- {
+ Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator.h b/chromium/third_party/dawn/src/tint/writer/hlsl/generator.h
index a18687a709f..233416ea998 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator.h
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator.h
@@ -16,7 +16,7 @@
#define SRC_TINT_WRITER_HLSL_GENERATOR_H_
#include <memory>
-#include <optional> // NOLINT(build/include_order)
+#include <optional>
#include <string>
#include <unordered_set>
#include <utility>
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.cc
index 19af4fad521..444746cc0d2 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.cc
@@ -60,7 +60,7 @@
#include "src/tint/transform/loop_to_for_loop.h"
#include "src/tint/transform/manager.h"
#include "src/tint/transform/num_workgroups_from_uniform.h"
-#include "src/tint/transform/promote_initializers_to_const_var.h"
+#include "src/tint/transform/promote_initializers_to_let.h"
#include "src/tint/transform/promote_side_effects_to_decl.h"
#include "src/tint/transform/remove_continue_in_switch.h"
#include "src/tint/transform/remove_phonies.h"
@@ -72,6 +72,7 @@
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/string.h"
#include "src/tint/writer/append_vector.h"
#include "src/tint/writer/float_to_string.h"
#include "src/tint/writer/generate_external_texture_bindings.h"
@@ -122,6 +123,16 @@ void PrintF32(std::ostream& out, float value) {
}
}
+bool PrintF16(std::ostream& out, float value) {
+ // Note: Currently inf and nan should not be constructable, don't emit them.
+ if (std::isinf(value) || std::isnan(value)) {
+ return false;
+ } else {
+ out << FloatToString(value) << "h";
+ return true;
+ }
+}
+
// Helper for writing " : register(RX, spaceY)", where R is the register, X is
// the binding point binding value, and Y is the binding point group value.
struct RegisterAndSpace {
@@ -158,6 +169,9 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
{ // Builtin polyfills
transform::BuiltinPolyfill::Builtins polyfills;
+ polyfills.acosh = transform::BuiltinPolyfill::Level::kFull;
+ polyfills.asinh = true;
+ polyfills.atanh = transform::BuiltinPolyfill::Level::kFull;
// TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
// and `firstbithigh`.
polyfills.count_leading_zeros = true;
@@ -231,7 +245,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
// DecomposeMemoryAccess special-cases the arrayLength() intrinsic, which
// will be transformed by CalculateArrayLength
manager.Add<transform::CalculateArrayLength>();
- manager.Add<transform::PromoteInitializersToConstVar>();
+ manager.Add<transform::PromoteInitializersToLet>();
manager.Add<transform::RemoveContinueInSwitch>();
@@ -261,12 +275,8 @@ bool GeneratorImpl::Generate() {
auto* mod = builder_.Sem().Module();
for (auto* decl : mod->DependencyOrderedDeclarations()) {
- if (decl->Is<ast::Alias>()) {
- continue; // Ignore aliases.
- }
- if (decl->Is<ast::Enable>()) {
- // Currently we don't have to do anything for using a extension in HLSL.
- continue;
+ if (decl->IsAnyOf<ast::Alias, ast::Enable, ast::StaticAssert>()) {
+ continue; // These are not emitted.
}
// Emit a new line between declarations if the type of declaration has
@@ -365,7 +375,7 @@ bool GeneratorImpl::EmitDynamicVectorAssignment(const ast::AssignmentStatement*
out << "vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;";
break;
default:
- TINT_UNREACHABLE(Writer, builder_.Diagnostics())
+ TINT_UNREACHABLE(Writer, diagnostics_)
<< "invalid vector size " << vec->Width();
break;
}
@@ -524,7 +534,7 @@ bool GeneratorImpl::EmitDynamicMatrixScalarAssignment(const ast::AssignmentState
<< vec_name << ";";
break;
default:
- TINT_UNREACHABLE(Writer, builder_.Diagnostics())
+ TINT_UNREACHABLE(Writer, diagnostics_)
<< "invalid vector size " << vec->Width();
break;
}
@@ -612,8 +622,7 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
if (auto* mat = TypeOf(lhs_sub_access->object)->UnwrapRef()->As<sem::Matrix>()) {
auto* rhs_col_idx_sem = builder_.Sem().Get(lhs_access->index);
auto* rhs_row_idx_sem = builder_.Sem().Get(lhs_sub_access->index);
- if (!rhs_col_idx_sem->ConstantValue().IsValid() ||
- !rhs_row_idx_sem->ConstantValue().IsValid()) {
+ if (!rhs_col_idx_sem->ConstantValue() || !rhs_row_idx_sem->ConstantValue()) {
return EmitDynamicMatrixScalarAssignment(stmt, mat);
}
}
@@ -623,7 +632,7 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
const auto* lhs_access_type = TypeOf(lhs_access->object)->UnwrapRef();
if (auto* mat = lhs_access_type->As<sem::Matrix>()) {
auto* lhs_index_sem = builder_.Sem().Get(lhs_access->index);
- if (!lhs_index_sem->ConstantValue().IsValid()) {
+ if (!lhs_index_sem->ConstantValue()) {
return EmitDynamicMatrixVectorAssignment(stmt, mat);
}
}
@@ -631,7 +640,7 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
// indices
if (auto* vec = lhs_access_type->As<sem::Vector>()) {
auto* rhs_sem = builder_.Sem().Get(lhs_access->index);
- if (!rhs_sem->ConstantValue().IsValid()) {
+ if (!rhs_sem->ConstantValue()) {
return EmitDynamicVectorAssignment(stmt, vec);
}
}
@@ -651,28 +660,30 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr) {
// For constants, replace literal 0 with 1.
- if (const auto& val = builder_.Sem().Get(expr)->ConstantValue()) {
- if (!val.AnyZero()) {
+ if (const auto* val = builder_.Sem().Get(expr)->ConstantValue()) {
+ if (!val->AnyZero()) {
return EmitExpression(out, expr);
}
- if (val.Type()->IsAnyOf<sem::I32, sem::U32>()) {
- return EmitValue(out, val.Type(), 1);
+ auto* ty = val->Type();
+
+ if (ty->IsAnyOf<sem::I32, sem::U32>()) {
+ return EmitValue(out, ty, 1);
}
- if (auto* vec = val.Type()->As<sem::Vector>()) {
+ if (auto* vec = ty->As<sem::Vector>()) {
auto* elem_ty = vec->type();
- if (!EmitType(out, val.Type(), ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+ if (!EmitType(out, ty, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return false;
}
out << "(";
- for (size_t i = 0; i < val.ElementCount(); ++i) {
+ for (size_t i = 0; i < vec->Width(); ++i) {
if (i != 0) {
out << ", ";
}
- auto s = val.Element<AInt>(i).value;
+ auto s = val->Index(i)->As<AInt>();
if (!EmitValue(out, elem_ty, (s == 0) ? 1 : static_cast<int>(s))) {
return false;
}
@@ -906,7 +917,7 @@ bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* e
return true;
}
-bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatements(utils::VectorRef<const ast::Statement*> stmts) {
for (auto* s : stmts) {
if (!EmitStatement(s)) {
return false;
@@ -915,7 +926,7 @@ bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
return true;
}
-bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts) {
ScopedIndent si(this);
return EmitStatements(stmts);
}
@@ -1106,56 +1117,17 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
// If the type constructor is empty then we need to construct with the zero
// value for all components.
- if (call->Arguments().empty()) {
+ if (call->Arguments().IsEmpty()) {
return EmitZeroValue(out, type);
}
- if (auto* mat = call->Type()->As<sem::Matrix>()) {
- if (ctor->Parameters().size() == 1) {
- // Matrix constructor with single scalar.
- auto fn = utils::GetOrCreate(matrix_scalar_ctors_, mat, [&]() -> std::string {
- TextBuffer b;
- TINT_DEFER(helpers_.Append(b));
-
- auto name = UniqueIdentifier("build_mat" + std::to_string(mat->columns()) + "x" +
- std::to_string(mat->rows()));
- {
- auto l = line(&b);
- if (!EmitType(l, mat, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
- return "";
- }
- l << " " << name << "(";
- if (!EmitType(l, mat->type(), ast::StorageClass::kNone, ast::Access::kUndefined,
- "")) {
- return "";
- }
- l << " value) {";
- }
- {
- ScopedIndent si(&b);
- auto l = line(&b);
- l << "return ";
- if (!EmitType(l, mat, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
- return "";
- }
- l << "(";
- for (uint32_t i = 0; i < mat->columns() * mat->rows(); i++) {
- l << ((i > 0) ? ", value" : "value");
- }
- l << ");";
- }
- line(&b) << "}";
- return name;
- });
- if (fn.empty()) {
- return false;
- }
- out << fn << "(";
- if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
- return false;
- }
- out << ")";
- return true;
+ // Single parameter matrix initializers must be identity constructor.
+ // It could also be conversions between f16 and f32 matrix when f16 is properly supported.
+ if (type->Is<sem::Matrix>() && call->Arguments().Length() == 1) {
+ if (!ctor->Parameters()[0]->Type()->UnwrapRef()->is_float_matrix()) {
+ TINT_UNREACHABLE(Writer, diagnostics_)
+ << "found a single-parameter matrix constructor that is not identity constructor";
+ return false;
}
}
@@ -1164,14 +1136,10 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
// For single-value vector initializers, swizzle the scalar to the right
// vector dimension using .x
const bool is_single_value_vector_init = type->is_scalar_vector() &&
- call->Arguments().size() == 1 &&
+ call->Arguments().Length() == 1 &&
ctor->Parameters()[0]->Type()->is_scalar();
- auto it = structure_builders_.find(As<sem::Struct>(type));
- if (it != structure_builders_.end()) {
- out << it->second << "(";
- brackets = false;
- } else if (brackets) {
+ if (brackets) {
out << "{";
} else {
if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
@@ -1217,9 +1185,9 @@ bool GeneratorImpl::EmitUniformBufferAccess(
// If true, use scalar_offset_value, otherwise use scalar_offset_expr
bool scalar_offset_constant = false;
- if (auto val = offset_arg->ConstantValue()) {
- TINT_ASSERT(Writer, val.Type()->Is<sem::U32>());
- scalar_offset_value = static_cast<uint32_t>(val.Element<AInt>(0).value);
+ if (auto* val = offset_arg->ConstantValue()) {
+ TINT_ASSERT(Writer, val->Type()->Is<sem::U32>());
+ scalar_offset_value = static_cast<uint32_t>(std::get<AInt>(val->Value()));
scalar_offset_value /= 4; // bytes -> scalar index
scalar_offset_constant = true;
}
@@ -1692,7 +1660,7 @@ bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
{
ScopedParen sp(pre);
- for (size_t i = 0; i < expr->args.size(); i++) {
+ for (size_t i = 0; i < expr->args.Length(); i++) {
auto* arg = expr->args[i];
if (i > 0) {
pre << ", ";
@@ -1779,8 +1747,8 @@ bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
{ // T compare_value = <compare_value>;
auto pre = line();
- if (!EmitTypeAndName(pre, TypeOf(compare_value), ast::StorageClass::kNone,
- ast::Access::kUndefined, compare)) {
+ if (!EmitTypeAndName(pre, TypeOf(compare_value)->UnwrapRef(),
+ ast::StorageClass::kNone, ast::Access::kUndefined, compare)) {
return false;
}
pre << " = ";
@@ -1887,16 +1855,15 @@ bool GeneratorImpl::EmitModfCall(std::ostream& out,
return false;
}
- line(b) << "float" << width << " whole;";
- line(b) << "float" << width << " fract = modf(" << in << ", whole);";
{
auto l = line(b);
if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
ast::Access::kUndefined, "")) {
return false;
}
- l << " result = {fract, whole};";
+ l << " result;";
}
+ line(b) << "result.fract = modf(" << params[0] << ", result.whole);";
line(b) << "return result;";
return true;
});
@@ -1921,8 +1888,15 @@ bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
return false;
}
- line(b) << "float" << width << " exp;";
- line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
+ std::string member_type;
+ if (Is<sem::F16>(sem::Type::DeepestElementOf(ty))) {
+ member_type = width.empty() ? "float16_t" : ("vector<float16_t, " + width + ">");
+ } else {
+ member_type = "float" + width;
+ }
+
+ line(b) << member_type << " exp;";
+ line(b) << member_type << " sig = frexp(" << in << ", exp);";
{
auto l = line(b);
if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
@@ -2143,7 +2117,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
// Returns the argument with the given usage
auto arg = [&](Usage usage) {
int idx = signature.IndexOf(usage);
- return (idx >= 0) ? arguments[idx] : nullptr;
+ return (idx >= 0) ? arguments[static_cast<size_t>(idx)] : nullptr;
};
auto* texture = arg(Usage::kTexture);
@@ -2373,7 +2347,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
case sem::BuiltinType::kTextureGather:
out << ".Gather";
if (builtin->Parameters()[0]->Usage() == sem::ParameterUsage::kComponent) {
- switch (call->Arguments()[0]->ConstantValue().Element<AInt>(0).value) {
+ switch (call->Arguments()[0]->ConstantValue()->As<AInt>()) {
case 0:
out << "Red";
break;
@@ -2420,8 +2394,10 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
auto* i32 = builder_.create<sem::I32>();
auto* zero = builder_.Expr(0_i);
auto* stmt = builder_.Sem().Get(vector)->Stmt();
- builder_.Sem().Add(zero, builder_.create<sem::Expression>(zero, i32, stmt, sem::Constant{},
- /* has_side_effects */ false));
+ builder_.Sem().Add(
+ zero, builder_.create<sem::Expression>(zero, i32, sem::EvaluationStage::kRuntime, stmt,
+ /* constant_value */ nullptr,
+ /* has_side_effects */ false));
auto* packed = AppendVector(&builder_, vector, zero);
return EmitExpression(out, packed->Declaration());
};
@@ -2577,7 +2553,6 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
case sem::BuiltinType::kReverseBits: // uint
return "reversebits";
case sem::BuiltinType::kSmoothstep:
- case sem::BuiltinType::kSmoothStep:
return "smoothstep";
default:
diagnostics_.add_error(diag::System::Writer,
@@ -2599,7 +2574,7 @@ bool GeneratorImpl::EmitCase(const ast::SwitchStatement* s, size_t case_idx) {
return false;
}
out << ":";
- if (selector == stmt->selectors.back()) {
+ if (selector == stmt->selectors.Back()) {
out << " {";
}
}
@@ -2635,7 +2610,7 @@ bool GeneratorImpl::EmitCase(const ast::SwitchStatement* s, size_t case_idx) {
}
bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
- if (!emit_continuing_()) {
+ if (!emit_continuing_ || !emit_continuing_()) {
return false;
}
line() << "continue;";
@@ -2651,7 +2626,7 @@ bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().Get(expr)) {
- if (auto constant = sem->ConstantValue()) {
+ if (auto* constant = sem->ConstantValue()) {
return EmitConstant(out, constant);
}
}
@@ -2714,7 +2689,7 @@ bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
return false;
}
} else {
- if (!EmitStatementsWithIndent({stmt->else_statement})) {
+ if (!EmitStatementsWithIndent(utils::Vector{stmt->else_statement})) {
return false;
}
}
@@ -2776,14 +2751,25 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
first = false;
auto const* type = v->Type();
+ auto storage_class = ast::StorageClass::kNone;
+ auto access = ast::Access::kUndefined;
if (auto* ptr = type->As<sem::Pointer>()) {
- // Transform pointer parameters in to `inout` parameters.
- // The WGSL spec is highly restrictive in what can be passed in pointer
- // parameters, which allows for this transformation. See:
- // https://gpuweb.github.io/gpuweb/wgsl/#function-restriction
- out << "inout ";
type = ptr->StoreType();
+ switch (ptr->StorageClass()) {
+ case ast::StorageClass::kStorage:
+ case ast::StorageClass::kUniform:
+ // Not allowed by WGSL, but is used by certain transforms (e.g. DMA) to pass
+ // storage buffers and uniform buffers down into transform-generated
+ // functions. In this situation we want to generate the parameter without an
+ // 'inout', using the storage class and access from the pointer.
+ storage_class = ptr->StorageClass();
+ access = ptr->Access();
+ break;
+ default:
+ // Transform regular WGSL pointer parameters in to `inout` parameters.
+ out << "inout ";
+ }
}
// Note: WGSL only allows for StorageClass::kNone on parameters, however
@@ -2792,7 +2778,7 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
// StorageClass::kStorage or StorageClass::kUniform. This is required to
// correctly translate the parameter to a [RW]ByteAddressBuffer for
// storage buffers and a uint4[N] for uniform buffers.
- if (!EmitTypeAndName(out, type, v->StorageClass(), v->Access(),
+ if (!EmitTypeAndName(out, type, storage_class, access,
builder_.Symbols().NameFor(v->Declaration()->symbol))) {
return false;
}
@@ -2851,41 +2837,55 @@ bool GeneratorImpl::EmitFunctionBodyWithDiscard(const ast::Function* func) {
}
bool GeneratorImpl::EmitGlobalVariable(const ast::Variable* global) {
- if (global->is_const) {
- return EmitProgramConstVariable(global);
- }
-
- auto* sem = builder_.Sem().Get(global);
- switch (sem->StorageClass()) {
- case ast::StorageClass::kUniform:
- return EmitUniformVariable(sem);
- case ast::StorageClass::kStorage:
- return EmitStorageVariable(sem);
- case ast::StorageClass::kHandle:
- return EmitHandleVariable(sem);
- case ast::StorageClass::kPrivate:
- return EmitPrivateVariable(sem);
- case ast::StorageClass::kWorkgroup:
- return EmitWorkgroupVariable(sem);
- default:
- break;
- }
+ return Switch(
+ global, //
+ [&](const ast::Var* var) {
+ auto* sem = builder_.Sem().Get(global);
+ switch (sem->StorageClass()) {
+ case ast::StorageClass::kUniform:
+ return EmitUniformVariable(var, sem);
+ case ast::StorageClass::kStorage:
+ return EmitStorageVariable(var, sem);
+ case ast::StorageClass::kHandle:
+ return EmitHandleVariable(var, sem);
+ case ast::StorageClass::kPrivate:
+ return EmitPrivateVariable(sem);
+ case ast::StorageClass::kWorkgroup:
+ return EmitWorkgroupVariable(sem);
+ case ast::StorageClass::kPushConstant:
+ diagnostics_.add_error(
+ diag::System::Writer,
+ "unhandled storage class " + utils::ToString(sem->StorageClass()));
+ return false;
+ default: {
+ TINT_ICE(Writer, diagnostics_)
+ << "unhandled storage class " << sem->StorageClass();
+ return false;
+ }
+ }
+ },
+ [&](const ast::Override* override) { return EmitOverride(override); },
+ [&](const ast::Const*) {
+ return true; // Constants are embedded at their use
+ },
+ [&](Default) {
+ TINT_ICE(Writer, diagnostics_)
+ << "unhandled global variable type " << global->TypeInfo().name;
- TINT_ICE(Writer, diagnostics_) << "unhandled storage class " << sem->StorageClass();
- return false;
+ return false;
+ });
}
-bool GeneratorImpl::EmitUniformVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
- auto binding_point = decl->BindingPoint();
- auto* type = var->Type()->UnwrapRef();
- auto name = builder_.Symbols().NameFor(decl->symbol);
+bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) {
+ auto binding_point = var->BindingPoint();
+ auto* type = sem->Type()->UnwrapRef();
+ auto name = builder_.Symbols().NameFor(var->symbol);
line() << "cbuffer cbuffer_" << name << RegisterAndSpace('b', binding_point) << " {";
{
ScopedIndent si(this);
auto out = line();
- if (!EmitTypeAndName(out, type, ast::StorageClass::kUniform, var->Access(), name)) {
+ if (!EmitTypeAndName(out, type, ast::StorageClass::kUniform, sem->Access(), name)) {
return false;
}
out << ";";
@@ -2896,29 +2896,27 @@ bool GeneratorImpl::EmitUniformVariable(const sem::Variable* var) {
return true;
}
-bool GeneratorImpl::EmitStorageVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
- auto* type = var->Type()->UnwrapRef();
+bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable* sem) {
+ auto* type = sem->Type()->UnwrapRef();
auto out = line();
- if (!EmitTypeAndName(out, type, ast::StorageClass::kStorage, var->Access(),
- builder_.Symbols().NameFor(decl->symbol))) {
+ if (!EmitTypeAndName(out, type, ast::StorageClass::kStorage, sem->Access(),
+ builder_.Symbols().NameFor(var->symbol))) {
return false;
}
- out << RegisterAndSpace(var->Access() == ast::Access::kRead ? 't' : 'u', decl->BindingPoint())
+ out << RegisterAndSpace(sem->Access() == ast::Access::kRead ? 't' : 'u', var->BindingPoint())
<< ";";
return true;
}
-bool GeneratorImpl::EmitHandleVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
- auto* unwrapped_type = var->Type()->UnwrapRef();
+bool GeneratorImpl::EmitHandleVariable(const ast::Var* var, const sem::Variable* sem) {
+ auto* unwrapped_type = sem->Type()->UnwrapRef();
auto out = line();
- auto name = builder_.Symbols().NameFor(decl->symbol);
- auto* type = var->Type()->UnwrapRef();
- if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+ auto name = builder_.Symbols().NameFor(var->symbol);
+ auto* type = sem->Type()->UnwrapRef();
+ if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(), name)) {
return false;
}
@@ -2934,7 +2932,7 @@ bool GeneratorImpl::EmitHandleVariable(const sem::Variable* var) {
}
if (register_space) {
- auto bp = decl->BindingPoint();
+ auto bp = var->BindingPoint();
out << " : register(" << register_space << bp.binding->value << ", space" << bp.group->value
<< ")";
}
@@ -2993,29 +2991,29 @@ bool GeneratorImpl::EmitWorkgroupVariable(const sem::Variable* var) {
return true;
}
-std::string GeneratorImpl::builtin_to_attribute(ast::Builtin builtin) const {
+std::string GeneratorImpl::builtin_to_attribute(ast::BuiltinValue builtin) const {
switch (builtin) {
- case ast::Builtin::kPosition:
+ case ast::BuiltinValue::kPosition:
return "SV_Position";
- case ast::Builtin::kVertexIndex:
+ case ast::BuiltinValue::kVertexIndex:
return "SV_VertexID";
- case ast::Builtin::kInstanceIndex:
+ case ast::BuiltinValue::kInstanceIndex:
return "SV_InstanceID";
- case ast::Builtin::kFrontFacing:
+ case ast::BuiltinValue::kFrontFacing:
return "SV_IsFrontFace";
- case ast::Builtin::kFragDepth:
+ case ast::BuiltinValue::kFragDepth:
return "SV_Depth";
- case ast::Builtin::kLocalInvocationId:
+ case ast::BuiltinValue::kLocalInvocationId:
return "SV_GroupThreadID";
- case ast::Builtin::kLocalInvocationIndex:
+ case ast::BuiltinValue::kLocalInvocationIndex:
return "SV_GroupIndex";
- case ast::Builtin::kGlobalInvocationId:
+ case ast::BuiltinValue::kGlobalInvocationId:
return "SV_DispatchThreadID";
- case ast::Builtin::kWorkgroupId:
+ case ast::BuiltinValue::kWorkgroupId:
return "SV_GroupID";
- case ast::Builtin::kSampleIndex:
+ case ast::BuiltinValue::kSampleIndex:
return "SV_SampleIndex";
- case ast::Builtin::kSampleMask:
+ case ast::BuiltinValue::kSampleMask:
return "SV_Coverage";
default:
break;
@@ -3060,7 +3058,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
// Emit the workgroup_size attribute.
auto wgsize = func_sem->WorkgroupSize();
out << "[numthreads(";
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (i > 0) {
out << ", ";
}
@@ -3068,11 +3066,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
if (wgsize[i].overridable_const) {
auto* global =
builder_.Sem().Get<sem::GlobalVariable>(wgsize[i].overridable_const);
- if (!global->IsOverridable()) {
- TINT_ICE(Writer, builder_.Diagnostics())
+ if (!global->Declaration()->Is<ast::Override>()) {
+ TINT_ICE(Writer, diagnostics_)
<< "expected a pipeline-overridable constant";
}
- out << kSpecConstantPrefix << global->ConstantId();
+ out << kSpecConstantPrefix << global->OverrideId().value;
} else {
out << std::to_string(wgsize[i].value);
}
@@ -3118,7 +3116,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
}
if (!Is<ast::ReturnStatement>(func->body->Last())) {
- ast::ReturnStatement ret(ProgramID(), Source{});
+ ast::ReturnStatement ret(ProgramID(), ast::NodeID{}, Source{});
if (!EmitStatement(&ret)) {
return false;
}
@@ -3130,107 +3128,132 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
return true;
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant& constant) {
- auto emit_bool = [&](size_t element_idx) {
- out << (constant.Element<AInt>(element_idx) ? "true" : "false");
- return true;
- };
- auto emit_f32 = [&](size_t element_idx) {
- PrintF32(out, static_cast<float>(constant.Element<AFloat>(element_idx)));
- return true;
- };
- auto emit_i32 = [&](size_t element_idx) {
- out << constant.Element<AInt>(element_idx).value;
- return true;
- };
- auto emit_u32 = [&](size_t element_idx) {
- out << constant.Element<AInt>(element_idx).value << "u";
- return true;
- };
- auto emit_vector = [&](const sem::Vector* vec_ty, size_t start, size_t end) {
- if (constant.AllEqual(start, end)) {
- {
- ScopedParen sp(out);
- bool ok = Switch(
- vec_ty->type(), //
- [&](const sem::Bool*) { return emit_bool(0); }, //
- [&](const sem::F32*) { return emit_f32(0); }, //
- [&](const sem::I32*) { return emit_i32(0); }, //
- [&](const sem::U32*) { return emit_u32(0); } //
- );
- if (!ok) {
- return false;
+bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constant) {
+ return Switch(
+ constant->Type(), //
+ [&](const sem::Bool*) {
+ out << (constant->As<AInt>() ? "true" : "false");
+ return true;
+ },
+ [&](const sem::F32*) {
+ PrintF32(out, constant->As<float>());
+ return true;
+ },
+ [&](const sem::F16*) {
+ // emit a f16 scalar with explicit float16_t type declaration.
+ out << "float16_t(";
+ bool valid = PrintF16(out, constant->As<float>());
+ out << ")";
+ return valid;
+ },
+ [&](const sem::I32*) {
+ out << constant->As<AInt>();
+ return true;
+ },
+ [&](const sem::U32*) {
+ out << constant->As<AInt>() << "u";
+ return true;
+ },
+ [&](const sem::Vector* v) {
+ if (constant->AllEqual()) {
+ {
+ ScopedParen sp(out);
+ if (!EmitConstant(out, constant->Index(0))) {
+ return false;
+ }
}
+ out << ".";
+ for (size_t i = 0; i < v->Width(); i++) {
+ out << "x";
+ }
+ return true;
}
- out << ".";
- for (size_t i = start; i < end; i++) {
- out << "x";
- }
- return true;
- }
- if (!EmitType(out, vec_ty, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
- return false;
- }
+ if (!EmitType(out, v, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+ return false;
+ }
- ScopedParen sp(out);
+ ScopedParen sp(out);
- auto emit_els = [&](auto emit_el) {
- for (size_t i = start; i < end; i++) {
- if (i > start) {
+ for (size_t i = 0; i < v->Width(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!emit_el(i)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
return true;
- };
- return Switch(
- vec_ty->type(), //
- [&](const sem::Bool*) { return emit_els(emit_bool); }, //
- [&](const sem::F32*) { return emit_els(emit_f32); }, //
- [&](const sem::I32*) { return emit_els(emit_i32); }, //
- [&](const sem::U32*) { return emit_els(emit_u32); }, //
- [&](Default) {
- diagnostics_.add_error(diag::System::Writer,
- "unhandled constant vector element type: " +
- builder_.FriendlyName(vec_ty->type()));
+ },
+ [&](const sem::Matrix* m) {
+ if (!EmitType(out, m, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return false;
- });
- };
- auto emit_matrix = [&](const sem::Matrix* m) {
- if (!EmitType(out, constant.Type(), ast::StorageClass::kNone, ast::Access::kUndefined,
- "")) {
- return false;
- }
+ }
- ScopedParen sp(out);
+ ScopedParen sp(out);
- for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
- if (column_idx > 0) {
- out << ", ";
+ for (size_t i = 0; i < m->columns(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
}
- size_t start = m->rows() * column_idx;
- size_t end = m->rows() * (column_idx + 1);
- if (!emit_vector(m->ColumnType(), start, end)) {
- return false;
+ return true;
+ },
+ [&](const sem::Array* a) {
+ if (constant->AllZero()) {
+ out << "(";
+ if (!EmitType(out, a, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+ return false;
+ }
+ out << ")0";
+ return true;
}
- }
- return true;
- };
- return Switch(
- constant.Type(), //
- [&](const sem::Bool*) { return emit_bool(0); }, //
- [&](const sem::F32*) { return emit_f32(0); }, //
- [&](const sem::I32*) { return emit_i32(0); }, //
- [&](const sem::U32*) { return emit_u32(0); }, //
- [&](const sem::Vector* v) { return emit_vector(v, 0, constant.ElementCount()); }, //
- [&](const sem::Matrix* m) { return emit_matrix(m); },
+
+ out << "{";
+ TINT_DEFER(out << "}");
+
+ for (size_t i = 0; i < a->Count(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+ [&](const sem::Struct* s) {
+ if (constant->AllZero()) {
+ out << "(";
+ if (!EmitType(out, s, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+ return false;
+ }
+ out << ")0";
+ return true;
+ }
+
+ out << "{";
+ TINT_DEFER(out << "}");
+
+ for (size_t i = 0; i < s->Members().size(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ },
[&](Default) {
diagnostics_.add_error(
diag::System::Writer,
- "unhandled constant type: " + builder_.FriendlyName(constant.Type()));
+ "unhandled constant type: " + builder_.FriendlyName(constant->Type()));
return false;
});
}
@@ -3243,6 +3266,13 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
return true;
},
[&](const ast::FloatLiteralExpression* l) {
+ if (l->suffix == ast::FloatLiteralExpression::Suffix::kH) {
+ // Emit f16 literal with explicit float16_t type declaration.
+ out << "float16_t(";
+ bool valid = PrintF16(out, static_cast<float>(l->value));
+ out << ")";
+ return valid;
+ }
PrintF32(out, static_cast<float>(l->value));
return true;
},
@@ -3276,6 +3306,10 @@ bool GeneratorImpl::EmitValue(std::ostream& out, const sem::Type* type, int valu
out << value << ".0f";
return true;
},
+ [&](const sem::F16*) {
+ out << "float16_t(" << value << ".0h)";
+ return true;
+ },
[&](const sem::I32*) {
out << value;
return true;
@@ -3471,6 +3505,56 @@ bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
return true;
}
+bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
+ TextBuffer cond_pre;
+ std::stringstream cond_buf;
+ {
+ auto* cond = stmt->condition;
+ TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
+ if (!EmitExpression(cond_buf, cond)) {
+ return false;
+ }
+ }
+
+ auto emit_continuing = [&]() { return true; };
+ TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+
+ // If the while has a multi-statement conditional, then we cannot emit this
+ // as a regular while in HLSL. Instead we need to generate a `while(true)` loop.
+ bool emit_as_loop = cond_pre.lines.size() > 0;
+ if (emit_as_loop) {
+ line() << LoopAttribute() << "while (true) {";
+ increment_indent();
+ TINT_DEFER({
+ decrement_indent();
+ line() << "}";
+ });
+
+ current_buffer_->Append(cond_pre);
+ line() << "if (!(" << cond_buf.str() << ")) { break; }";
+ if (!EmitStatements(stmt->body->statements)) {
+ return false;
+ }
+ } else {
+ // While can be generated.
+ {
+ auto out = line();
+ out << LoopAttribute() << "while";
+ {
+ ScopedParen sp(out);
+ out << cond_buf.str();
+ }
+ out << " {";
+ }
+ if (!EmitStatementsWithIndent(stmt->body->statements)) {
+ return false;
+ }
+ line() << "}";
+ }
+
+ return true;
+}
+
bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
const ast::MemberAccessorExpression* expr) {
if (!EmitExpression(out, expr->structure)) {
@@ -3541,6 +3625,9 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
[&](const ast::ForLoopStatement* l) { //
return EmitForLoop(l);
},
+ [&](const ast::WhileStatement* l) { //
+ return EmitWhile(l);
+ },
[&](const ast::ReturnStatement* r) { //
return EmitReturn(r);
},
@@ -3548,7 +3635,21 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
return EmitSwitch(s);
},
[&](const ast::VariableDeclStatement* v) { //
- return EmitVariable(v->variable);
+ return Switch(
+ v->variable, //
+ [&](const ast::Var* var) { return EmitVar(var); },
+ [&](const ast::Let* let) { return EmitLet(let); },
+ [&](const ast::Const*) {
+ return true; // Constants are embedded at their use
+ },
+ [&](Default) { //
+ TINT_ICE(Writer, diagnostics_)
+ << "unknown variable type: " << v->variable->TypeInfo().name;
+ return false;
+ });
+ },
+ [&](const ast::StaticAssert*) {
+ return true; // Not emitted
},
[&](Default) { //
diagnostics_.add_error(diag::System::Writer,
@@ -3558,7 +3659,7 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
}
bool GeneratorImpl::EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt) {
- TINT_ASSERT(Writer, stmt->body.size() == 1 && stmt->body[0]->IsDefault());
+ TINT_ASSERT(Writer, stmt->body.Length() == 1 && stmt->body[0]->IsDefault());
// FXC fails to compile a switch with just a default case, ignoring the
// default case body. We work around this here by emitting the default case
@@ -3591,7 +3692,7 @@ bool GeneratorImpl::EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt) {
bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
// BUG(crbug.com/tint/1188): work around default-only switches
- if (stmt->body.size() == 1 && stmt->body[0]->IsDefault()) {
+ if (stmt->body.Length() == 1 && stmt->body[0]->IsDefault()) {
return EmitDefaultOnlySwitch(stmt);
}
@@ -3606,7 +3707,7 @@ bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
{
ScopedIndent si(this);
- for (size_t i = 0; i < stmt->body.size(); i++) {
+ for (size_t i = 0; i < stmt->body.Length(); i++) {
if (!EmitCase(stmt, i)) {
return false;
}
@@ -3654,9 +3755,8 @@ bool GeneratorImpl::EmitType(std::ostream& out,
while (auto* arr = base_type->As<sem::Array>()) {
if (arr->IsRuntimeSized()) {
TINT_ICE(Writer, diagnostics_)
- << "Runtime arrays may only exist in storage buffers, which "
- "should "
- "have been transformed into a ByteAddressBuffer";
+ << "Runtime arrays may only exist in storage buffers, which should have "
+ "been transformed into a ByteAddressBuffer";
return false;
}
sizes.push_back(arr->Count());
@@ -3685,15 +3785,23 @@ bool GeneratorImpl::EmitType(std::ostream& out,
return true;
},
[&](const sem::F16*) {
- diagnostics_.add_error(diag::System::Writer,
- "Type f16 is not completely implemented yet.");
- return false;
+ out << "float16_t";
+ return true;
},
[&](const sem::I32*) {
out << "int";
return true;
},
[&](const sem::Matrix* mat) {
+ if (mat->type()->Is<sem::F16>()) {
+ // Use matrix<type, N, M> for f16 matrix
+ out << "matrix<";
+ if (!EmitType(out, mat->type(), storage_class, access, "")) {
+ return false;
+ }
+ out << ", " << mat->columns() << ", " << mat->rows() << ">";
+ return true;
+ }
if (!EmitType(out, mat->type(), storage_class, access, "")) {
return false;
}
@@ -3809,6 +3917,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
} else if (vec->type()->Is<sem::Bool>() && width >= 1 && width <= 4) {
out << "bool" << width;
} else {
+ // For example, use "vector<float16_t, N>" for f16 vector.
out << "vector<";
if (!EmitType(out, vec->type(), storage_class, access, "")) {
return false;
@@ -3955,20 +4064,11 @@ bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression*
return true;
}
-bool GeneratorImpl::EmitVariable(const ast::Variable* var) {
+bool GeneratorImpl::EmitVar(const ast::Var* var) {
auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type()->UnwrapRef();
- // TODO(dsinclair): Handle variable attributes
- if (!var->attributes.empty()) {
- diagnostics_.add_error(diag::System::Writer, "Variable attributes are not handled yet");
- return false;
- }
-
auto out = line();
- if (var->is_const) {
- out << "const ";
- }
if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
builder_.Symbols().NameFor(var->symbol))) {
return false;
@@ -3990,60 +4090,52 @@ bool GeneratorImpl::EmitVariable(const ast::Variable* var) {
return true;
}
-bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
- for (auto* d : var->attributes) {
- if (!d->Is<ast::IdAttribute>()) {
- diagnostics_.add_error(diag::System::Writer, "Decorated const values not valid");
- return false;
- }
+bool GeneratorImpl::EmitLet(const ast::Let* let) {
+ auto* sem = builder_.Sem().Get(let);
+ auto* type = sem->Type()->UnwrapRef();
+
+ auto out = line();
+ out << "const ";
+ if (!EmitTypeAndName(out, type, ast::StorageClass::kNone, ast::Access::kUndefined,
+ builder_.Symbols().NameFor(let->symbol))) {
+ return false;
}
- if (!var->is_const) {
- diagnostics_.add_error(diag::System::Writer, "Expected a const value");
+ out << " = ";
+ if (!EmitExpression(out, let->constructor)) {
return false;
}
+ out << ";";
- auto* sem = builder_.Sem().Get(var);
+ return true;
+}
+
+bool GeneratorImpl::EmitOverride(const ast::Override* override) {
+ auto* sem = builder_.Sem().Get(override);
auto* type = sem->Type();
- auto* global = sem->As<sem::GlobalVariable>();
- if (global && global->IsOverridable()) {
- auto const_id = global->ConstantId();
+ auto override_id = sem->OverrideId();
- line() << "#ifndef " << kSpecConstantPrefix << const_id;
+ line() << "#ifndef " << kSpecConstantPrefix << override_id.value;
- if (var->constructor != nullptr) {
- auto out = line();
- out << "#define " << kSpecConstantPrefix << const_id << " ";
- if (!EmitExpression(out, var->constructor)) {
- return false;
- }
- } else {
- line() << "#error spec constant required for constant id " << const_id;
- }
- line() << "#endif";
- {
- auto out = line();
- out << "static const ";
- if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
- builder_.Symbols().NameFor(var->symbol))) {
- return false;
- }
- out << " = " << kSpecConstantPrefix << const_id << ";";
+ if (override->constructor != nullptr) {
+ auto out = line();
+ out << "#define " << kSpecConstantPrefix << override_id.value << " ";
+ if (!EmitExpression(out, override->constructor)) {
+ return false;
}
} else {
+ line() << "#error spec constant required for constant id " << override_id.value;
+ }
+ line() << "#endif";
+ {
auto out = line();
out << "static const ";
if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
- builder_.Symbols().NameFor(var->symbol))) {
+ builder_.Symbols().NameFor(override->symbol))) {
return false;
}
- out << " = ";
- if (!EmitExpression(out, var->constructor)) {
- return false;
- }
- out << ";";
+ out << " = " << kSpecConstantPrefix << override_id.value << ";";
}
-
return true;
}
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.h b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.h
index af7e4c98208..78680c8f9f8 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.h
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl.h
@@ -93,7 +93,8 @@ class GeneratorImpl : public TextGenerator {
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitAssign(const ast::AssignmentStatement* stmt);
- /// Emits code such that if `expr` is zero, it emits one, else `expr`
+ /// Emits code such that if `expr` is zero, it emits one, else `expr`.
+ /// Used to avoid divide-by-zeros by substituting constant zeros with ones.
/// @param out the output of the expression stream
/// @param expr the expression
/// @returns true if the expression was emitted, false otherwise
@@ -111,11 +112,11 @@ class GeneratorImpl : public TextGenerator {
/// Emits a list of statements
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
- bool EmitStatements(const ast::StatementList& stmts);
+ bool EmitStatements(utils::VectorRef<const ast::Statement*> stmts);
/// Emits a list of statements with an indentation
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
- bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+ bool EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts);
/// Handles a block statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -303,19 +304,22 @@ class GeneratorImpl : public TextGenerator {
bool EmitGlobalVariable(const ast::Variable* global);
/// Handles emitting a global variable with the uniform storage class
- /// @param var the global variable
+ /// @param var the AST node for the 'var'
+ /// @param sem the semantic node for the 'var'
/// @returns true on success
- bool EmitUniformVariable(const sem::Variable* var);
+ bool EmitUniformVariable(const ast::Var* var, const sem::Variable* sem);
/// Handles emitting a global variable with the storage storage class
- /// @param var the global variable
+ /// @param var the AST node for the 'var'
+ /// @param sem the semantic node for the 'var'
/// @returns true on success
- bool EmitStorageVariable(const sem::Variable* var);
+ bool EmitStorageVariable(const ast::Var* var, const sem::Variable* sem);
/// Handles emitting a global variable with the handle storage class
- /// @param var the global variable
+ /// @param var the AST node for the 'var'
+ /// @param sem the semantic node for the 'var'
/// @returns true on success
- bool EmitHandleVariable(const sem::Variable* var);
+ bool EmitHandleVariable(const ast::Var* var, const sem::Variable* sem);
/// Handles emitting a global variable with the private storage class
/// @param var the global variable
@@ -339,7 +343,7 @@ class GeneratorImpl : public TextGenerator {
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const sem::Constant& constant);
+ bool EmitConstant(std::ostream& out, const sem::Constant* constant);
/// Handles a literal
/// @param out the output stream
/// @param lit the literal to emit
@@ -353,6 +357,10 @@ class GeneratorImpl : public TextGenerator {
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
bool EmitForLoop(const ast::ForLoopStatement* stmt);
+ /// Handles a while statement
+ /// @param stmt the statement to emit
+ /// @returns true if the statement was emitted
+ bool EmitWhile(const ast::WhileStatement* stmt);
/// Handles generating an identifier expression
/// @param out the output of the expression stream
/// @param expr the identifier expression
@@ -433,14 +441,18 @@ class GeneratorImpl : public TextGenerator {
/// @param type the type to emit the value for
/// @returns true if the zero value was successfully emitted.
bool EmitZeroValue(std::ostream& out, const sem::Type* type);
- /// Handles generating a variable
+ /// Handles generating a 'var' declaration
/// @param var the variable to generate
/// @returns true if the variable was emitted
- bool EmitVariable(const ast::Variable* var);
- /// Handles generating a program scope constant variable
- /// @param var the variable to emit
+ bool EmitVar(const ast::Var* var);
+ /// Handles generating a function-scope 'let' declaration
+ /// @param let the variable to generate
+ /// @returns true if the variable was emitted
+ bool EmitLet(const ast::Let* let);
+ /// Handles generating a module-scope 'override' declaration
+ /// @param override the 'override' to emit
/// @returns true if the variable was emitted
- bool EmitProgramConstVariable(const ast::Variable* var);
+ bool EmitOverride(const ast::Override* override);
/// Emits call to a helper vector assignment function for the input assignment
/// statement and vector type. This is used to work around FXC issues where
/// assignments to vectors with dynamic indices cause compilation failures.
@@ -477,7 +489,7 @@ class GeneratorImpl : public TextGenerator {
/// Converts a builtin to an attribute name
/// @param builtin the builtin to convert
/// @returns the string name of the builtin or blank on error
- std::string builtin_to_attribute(ast::Builtin builtin) const;
+ std::string builtin_to_attribute(ast::BuiltinValue builtin) const;
/// Converts interpolation attributes to a HLSL modifiers
/// @param type the interpolation type
@@ -531,7 +543,6 @@ class GeneratorImpl : public TextGenerator {
std::function<bool()> emit_continuing_;
std::unordered_map<const sem::Matrix*, std::string> matrix_scalar_ctors_;
std::unordered_map<const sem::Builtin*, std::string> builtins_;
- std::unordered_map<const sem::Struct*, std::string> structure_builders_;
std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_;
std::unordered_map<const sem::Matrix*, std::string> dynamic_matrix_vector_write_;
std::unordered_map<const sem::Matrix*, std::string> dynamic_matrix_scalar_write_;
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
index bbdeb10fd15..dfa3d67087c 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
@@ -22,7 +22,7 @@ namespace {
using HlslGeneratorImplTest_Expression = TestHelper;
TEST_F(HlslGeneratorImplTest_Expression, IndexAccessor) {
- Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+ GlobalVar("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
auto* expr = IndexAccessor("ary", 5_i);
WrapInFunction(expr);
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_assign_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_assign_test.cc
index c69cbdf9190..a01903efdec 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_assign_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_assign_test.cc
@@ -22,8 +22,8 @@ namespace {
using HlslGeneratorImplTest_Assign = TestHelper;
TEST_F(HlslGeneratorImplTest_Assign, Emit_Assign) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("lhs", ty.i32())),
Decl(Var("rhs", ty.i32())),
Assign("lhs", "rhs"),
@@ -41,9 +41,9 @@ TEST_F(HlslGeneratorImplTest_Assign, Emit_Assign) {
)");
}
-TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_ConstantIndex) {
- Func("fn", {}, ty.void_(),
- {
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_LetIndex) {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("lhs", ty.vec3<f32>())),
Decl(Var("rhs", ty.f32())),
Decl(Let("index", ty.u32(), Expr(0_u))),
@@ -54,18 +54,43 @@ TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_ConstantIndex) {
ASSERT_TRUE(gen.Generate());
EXPECT_EQ(gen.result(),
- R"(void fn() {
+ R"(void set_float3(inout float3 vec, int idx, float val) {
+ vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;
+}
+
+void fn() {
float3 lhs = float3(0.0f, 0.0f, 0.0f);
float rhs = 0.0f;
const uint index = 0u;
+ set_float3(lhs, index, rhs);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_ConstIndex) {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Var("lhs", ty.vec3<f32>())),
+ Decl(Var("rhs", ty.f32())),
+ Decl(Const("index", ty.u32(), Expr(0_u))),
+ Assign(IndexAccessor("lhs", "index"), "rhs"),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate());
+ EXPECT_EQ(gen.result(),
+ R"(void fn() {
+ float3 lhs = float3(0.0f, 0.0f, 0.0f);
+ float rhs = 0.0f;
lhs[0u] = rhs;
}
)");
}
TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_DynamicIndex) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("lhs", ty.vec3<f32>())),
Decl(Var("rhs", ty.f32())),
Decl(Var("index", ty.u32())),
@@ -89,9 +114,9 @@ void fn() {
)");
}
-TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_ConstantIndex) {
- Func("fn", {}, ty.void_(),
- {
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_LetIndex) {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("lhs", ty.mat4x2<f32>())),
Decl(Var("rhs", ty.vec2<f32>())),
Decl(Let("index", ty.u32(), Expr(0_u))),
@@ -102,18 +127,48 @@ TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_ConstantIndex) {
ASSERT_TRUE(gen.Generate());
EXPECT_EQ(gen.result(),
- R"(void fn() {
+ R"(void set_vector_float4x2(inout float4x2 mat, int col, float2 val) {
+ switch (col) {
+ case 0: mat[0] = val; break;
+ case 1: mat[1] = val; break;
+ case 2: mat[2] = val; break;
+ case 3: mat[3] = val; break;
+ }
+}
+
+void fn() {
float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
float2 rhs = float2(0.0f, 0.0f);
const uint index = 0u;
+ set_vector_float4x2(lhs, index, rhs);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_ConstIndex) {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Var("lhs", ty.mat4x2<f32>())),
+ Decl(Var("rhs", ty.vec2<f32>())),
+ Decl(Const("index", ty.u32(), Expr(0_u))),
+ Assign(IndexAccessor("lhs", "index"), "rhs"),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate());
+ EXPECT_EQ(gen.result(),
+ R"(void fn() {
+ float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ float2 rhs = float2(0.0f, 0.0f);
lhs[0u] = rhs;
}
)");
}
TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_DynamicIndex) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("lhs", ty.mat4x2<f32>())),
Decl(Var("rhs", ty.vec2<f32>())),
Decl(Var("index", ty.u32())),
@@ -142,9 +197,9 @@ void fn() {
)");
}
-TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_ConstantIndex) {
- Func("fn", {}, ty.void_(),
- {
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_LetIndex) {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("lhs", ty.mat4x2<f32>())),
Decl(Var("rhs", ty.f32())),
Decl(Let("index", ty.u32(), Expr(0_u))),
@@ -155,18 +210,56 @@ TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_ConstantIndex) {
ASSERT_TRUE(gen.Generate());
EXPECT_EQ(gen.result(),
- R"(void fn() {
+ R"(void set_scalar_float4x2(inout float4x2 mat, int col, int row, float val) {
+ switch (col) {
+ case 0:
+ mat[0] = (row.xx == int2(0, 1)) ? val.xx : mat[0];
+ break;
+ case 1:
+ mat[1] = (row.xx == int2(0, 1)) ? val.xx : mat[1];
+ break;
+ case 2:
+ mat[2] = (row.xx == int2(0, 1)) ? val.xx : mat[2];
+ break;
+ case 3:
+ mat[3] = (row.xx == int2(0, 1)) ? val.xx : mat[3];
+ break;
+ }
+}
+
+void fn() {
float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
float rhs = 0.0f;
const uint index = 0u;
+ set_scalar_float4x2(lhs, index, index, rhs);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_ConstIndex) {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Var("lhs", ty.mat4x2<f32>())),
+ Decl(Var("rhs", ty.f32())),
+ Decl(Const("index", ty.u32(), Expr(0_u))),
+ Assign(IndexAccessor(IndexAccessor("lhs", "index"), "index"), "rhs"),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate());
+ EXPECT_EQ(gen.result(),
+ R"(void fn() {
+ float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ float rhs = 0.0f;
lhs[0u][0u] = rhs;
}
)");
}
TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_DynamicIndex) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("lhs", ty.mat4x2<f32>())),
Decl(Var("rhs", ty.f32())),
Decl(Var("index", ty.u32())),
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_binary_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_binary_test.cc
index 58255368bb7..d5f70fb0949 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_binary_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_binary_test.cc
@@ -50,8 +50,40 @@ TEST_P(HlslBinaryTest, Emit_f32) {
return;
}
- Global("left", ty.f32(), ast::StorageClass::kPrivate);
- Global("right", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("left", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.f32(), ast::StorageClass::kPrivate);
+
+ auto* left = Expr("left");
+ auto* right = Expr("right");
+
+ auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), params.result);
+}
+TEST_P(HlslBinaryTest, Emit_f16) {
+ auto params = GetParam();
+
+ if ((params.valid_for & BinaryData::Types::Float) == 0) {
+ return;
+ }
+
+ // Skip ops that are illegal for this type
+ if (params.op == ast::BinaryOp::kAnd || params.op == ast::BinaryOp::kOr ||
+ params.op == ast::BinaryOp::kXor || params.op == ast::BinaryOp::kShiftLeft ||
+ params.op == ast::BinaryOp::kShiftRight) {
+ return;
+ }
+
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("left", ty.f16(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.f16(), ast::StorageClass::kPrivate);
auto* left = Expr("left");
auto* right = Expr("right");
@@ -73,8 +105,8 @@ TEST_P(HlslBinaryTest, Emit_u32) {
return;
}
- Global("left", ty.u32(), ast::StorageClass::kPrivate);
- Global("right", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("left", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.u32(), ast::StorageClass::kPrivate);
auto* left = Expr("left");
auto* right = Expr("right");
@@ -101,8 +133,8 @@ TEST_P(HlslBinaryTest, Emit_i32) {
return;
}
- Global("left", ty.i32(), ast::StorageClass::kPrivate);
- Global("right", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("left", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("right", ty.i32(), ast::StorageClass::kPrivate);
auto* left = Expr("left");
auto* right = Expr("right");
@@ -140,7 +172,7 @@ INSTANTIATE_TEST_SUITE_P(
BinaryData{"(left % right)", ast::BinaryOp::kModulo,
BinaryData::Types::Float}));
-TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar) {
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar_f32) {
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
auto* rhs = Expr(1_f);
@@ -155,7 +187,24 @@ TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar) {
EXPECT_EQ(out.str(), "((1.0f).xxx * 1.0f)");
}
-TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarVector) {
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+ auto* rhs = Expr(1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "((float16_t(1.0h)).xxx * float16_t(1.0h))");
+}
+
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarVector_f32) {
auto* lhs = Expr(1_f);
auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -170,8 +219,25 @@ TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarVector) {
EXPECT_EQ(out.str(), "(1.0f * (1.0f).xxx)");
}
-TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarVector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* lhs = Expr(1_h);
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(float16_t(1.0h) * (float16_t(1.0h)).xxx)");
+}
+
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = Expr("mat");
auto* rhs = Expr(1_f);
@@ -185,8 +251,25 @@ TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar) {
EXPECT_EQ(out.str(), "(mat * 1.0f)");
}
-TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = Expr("mat");
+ auto* rhs = Expr(1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(mat * float16_t(1.0h))");
+}
+
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = Expr(1_f);
auto* rhs = Expr("mat");
@@ -200,8 +283,25 @@ TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix) {
EXPECT_EQ(out.str(), "(1.0f * mat)");
}
-TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = Expr(1_h);
+ auto* rhs = Expr("mat");
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "(float16_t(1.0h) * mat)");
+}
+
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = Expr("mat");
auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -215,8 +315,25 @@ TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector) {
EXPECT_EQ(out.str(), "mul((1.0f).xxx, mat)");
}
-TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix) {
- Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = Expr("mat");
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "mul((float16_t(1.0h)).xxx, mat)");
+}
+
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f32) {
+ GlobalVar("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
auto* rhs = Expr("mat");
@@ -230,9 +347,42 @@ TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix) {
EXPECT_EQ(out.str(), "mul(mat, (1.0f).xxx)");
}
-TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix) {
- Global("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
- Global("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("mat", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+ auto* rhs = Expr("mat");
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "mul(mat, (float16_t(1.0h)).xxx)");
+}
+
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f32) {
+ GlobalVar("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
+ WrapInFunction(expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "mul(rhs, lhs)");
+}
+
+TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("lhs", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr);
@@ -245,8 +395,8 @@ TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix) {
}
TEST_F(HlslGeneratorImplTest_Binary, Logical_And) {
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
WrapInFunction(expr);
@@ -265,10 +415,10 @@ if (tint_tmp) {
TEST_F(HlslGeneratorImplTest_Binary, Logical_Multi) {
// (a && b) || (c || d)
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(
ast::BinaryOp::kLogicalOr,
@@ -297,8 +447,8 @@ if (!tint_tmp) {
}
TEST_F(HlslGeneratorImplTest_Binary, Logical_Or) {
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
WrapInFunction(expr);
@@ -324,16 +474,16 @@ TEST_F(HlslGeneratorImplTest_Binary, If_WithLogical) {
// return 3i;
// }
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr =
If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
Block(Return(1_i)),
Else(If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
Block(Return(2_i)), Else(Block(Return(3_i))))));
- Func("func", {}, ty.i32(), {WrapInStatement(expr)});
+ Func("func", utils::Empty, ty.i32(), utils::Vector{WrapInStatement(expr)});
GeneratorImpl& gen = Build();
@@ -361,15 +511,15 @@ if ((tint_tmp)) {
TEST_F(HlslGeneratorImplTest_Binary, Return_WithLogical) {
// return (a && b) || c;
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = Return(create<ast::BinaryExpression>(
ast::BinaryOp::kLogicalOr,
create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
Expr("c")));
- Func("func", {}, ty.bool_(), {WrapInStatement(expr)});
+ Func("func", utils::Empty, ty.bool_(), utils::Vector{WrapInStatement(expr)});
GeneratorImpl& gen = Build();
@@ -389,10 +539,10 @@ return (tint_tmp);
TEST_F(HlslGeneratorImplTest_Binary, Assign_WithLogical) {
// a = (b || c) && d;
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr =
Assign(Expr("a"),
@@ -420,9 +570,9 @@ a = (tint_tmp);
TEST_F(HlslGeneratorImplTest_Binary, Decl_WithLogical) {
// var a : bool = (b && c) || d;
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
auto* var =
Var("a", ty.bool_(), ast::StorageClass::kNone,
@@ -453,26 +603,25 @@ TEST_F(HlslGeneratorImplTest_Binary, Call_WithLogical) {
// foo(a && b, c || d, (a || c) && (b || d))
Func("foo",
- {
+ utils::Vector{
Param(Sym(), ty.bool_()),
Param(Sym(), ty.bool_()),
Param(Sym(), ty.bool_()),
},
- ty.void_(), ast::StatementList{}, ast::AttributeList{});
- Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- Global("b", ty.bool_(), ast::StorageClass::kPrivate);
- Global("c", ty.bool_(), ast::StorageClass::kPrivate);
- Global("d", ty.bool_(), ast::StorageClass::kPrivate);
-
- ast::ExpressionList params;
- params.push_back(
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")));
- params.push_back(
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")));
- params.push_back(create<ast::BinaryExpression>(
- ast::BinaryOp::kLogicalAnd,
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("c")),
- create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("d"))));
+ ty.void_(), utils::Empty, utils::Empty);
+ GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("d", ty.bool_(), ast::StorageClass::kPrivate);
+
+ utils::Vector params{
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")),
+ create<ast::BinaryExpression>(
+ ast::BinaryOp::kLogicalAnd,
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("c")),
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("d"))),
+ };
auto* expr = CallStmt(Call("foo", params));
WrapInFunction(expr);
@@ -526,8 +675,8 @@ INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest,
testing::Values(Params{Params::Type::Div}, Params{Params::Type::Mod}));
TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_i32) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.i32())),
Decl(Let("r", nullptr, Op("a", 0_i))),
});
@@ -544,8 +693,8 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_i32) {
}
TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_u32) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.u32())),
Decl(Let("r", nullptr, Op("a", 0_u))),
});
@@ -559,11 +708,11 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_u32) {
R"( 1u);
}
)");
-} // namespace HlslGeneratorDivMod
+}
TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_vec_i32) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", nullptr, vec4<i32>(100_i, 100_i, 100_i, 100_i))),
Decl(Let("r", nullptr, Op("a", vec4<i32>(50_i, 0_i, 25_i, 0_i)))),
});
@@ -577,11 +726,11 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_vec_i32) {
R"( int4(50, 1, 25, 1));
}
)");
-} // namespace
+}
TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_scalar_i32) {
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", nullptr, vec4<i32>(100_i, 100_i, 100_i, 100_i))),
Decl(Let("r", nullptr, Op("a", 0_i))),
});
@@ -595,11 +744,11 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_scalar_i32) {
R"( 1);
}
)");
-} // namespace hlsl
+}
TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_i32) {
- Func("fn", {Param("b", ty.i32())}, ty.void_(),
- {
+ Func("fn", utils::Vector{Param("b", ty.i32())}, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.i32())),
Decl(Let("r", nullptr, Op("a", "b"))),
});
@@ -613,11 +762,11 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_i32) {
R"( (b == 0 ? 1 : b));
}
)");
-} // namespace writer
+}
TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_u32) {
- Func("fn", {Param("b", ty.u32())}, ty.void_(),
- {
+ Func("fn", utils::Vector{Param("b", ty.u32())}, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.u32())),
Decl(Let("r", nullptr, Op("a", "b"))),
});
@@ -631,11 +780,11 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_u32) {
R"( (b == 0u ? 1u : b));
}
)");
-} // namespace tint
+}
TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_vec_i32) {
- Func("fn", {Param("b", ty.vec3<i32>())}, ty.void_(),
- {
+ Func("fn", utils::Vector{Param("b", ty.vec3<i32>())}, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.vec3<i32>())),
Decl(Let("r", nullptr, Op("a", "b"))),
});
@@ -652,8 +801,8 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_vec_i32) {
}
TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_scalar_i32) {
- Func("fn", {Param("b", ty.i32())}, ty.void_(),
- {
+ Func("fn", utils::Vector{Param("b", ty.i32())}, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.vec3<i32>())),
Decl(Let("r", nullptr, Op("a", "b"))),
});
@@ -670,13 +819,13 @@ TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_scalar_i32) {
}
TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_i32) {
- Func("zero", {}, ty.i32(),
- {
+ Func("zero", utils::Empty, ty.i32(),
+ utils::Vector{
Return(Expr(0_i)),
});
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.i32())),
Decl(Let("r", nullptr, Op("a", Call("zero")))),
});
@@ -701,13 +850,13 @@ void fn() {
}
TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_u32) {
- Func("zero", {}, ty.u32(),
- {
+ Func("zero", utils::Empty, ty.u32(),
+ utils::Vector{
Return(Expr(0_u)),
});
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.u32())),
Decl(Let("r", nullptr, Op("a", Call("zero")))),
});
@@ -732,13 +881,13 @@ void fn() {
}
TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_vec_by_vec_i32) {
- Func("zero", {}, ty.vec3<i32>(),
- {
+ Func("zero", utils::Empty, ty.vec3<i32>(),
+ utils::Vector{
Return(vec3<i32>(0_i, 0_i, 0_i)),
});
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.vec3<i32>())),
Decl(Let("r", nullptr, Op("a", Call("zero")))),
});
@@ -763,13 +912,13 @@ void fn() {
}
TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_vec_by_scalar_i32) {
- Func("zero", {}, ty.i32(),
- {
+ Func("zero", utils::Empty, ty.i32(),
+ utils::Vector{
Return(0_i),
});
- Func("fn", {}, ty.void_(),
- {
+ Func("fn", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("a", ty.vec3<i32>())),
Decl(Let("r", nullptr, Op("a", Call("zero")))),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index b356ccd21e7..3f9cfa79a88 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -28,36 +28,40 @@ namespace {
using BuiltinType = sem::BuiltinType;
using HlslGeneratorImplTest_Builtin = TestHelper;
-enum class ParamType {
+enum class CallParamType {
kF32,
kU32,
kBool,
+ kF16,
};
struct BuiltinData {
BuiltinType builtin;
- ParamType type;
+ CallParamType type;
const char* hlsl_name;
};
inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
- out << data.hlsl_name;
+ out << data.hlsl_name << "<";
switch (data.type) {
- case ParamType::kF32:
+ case CallParamType::kF32:
out << "f32";
break;
- case ParamType::kU32:
+ case CallParamType::kU32:
out << "u32";
break;
- case ParamType::kBool:
+ case CallParamType::kBool:
out << "bool";
break;
+ case CallParamType::kF16:
+ out << "f16";
+ break;
}
out << ">";
return out;
}
const ast::CallExpression* GenerateCall(BuiltinType builtin,
- ParamType type,
+ CallParamType type,
ProgramBuilder* builder) {
std::string name;
std::ostringstream str(name);
@@ -95,30 +99,51 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
case BuiltinType::kTanh:
case BuiltinType::kTrunc:
case BuiltinType::kSign:
- return builder->Call(str.str(), "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2");
+ } else {
+ return builder->Call(str.str(), "f2");
+ }
case BuiltinType::kLdexp:
- return builder->Call(str.str(), "f2", "i2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "i2");
+ } else {
+ return builder->Call(str.str(), "f2", "i2");
+ }
case BuiltinType::kAtan2:
case BuiltinType::kDot:
case BuiltinType::kDistance:
case BuiltinType::kPow:
case BuiltinType::kReflect:
case BuiltinType::kStep:
- return builder->Call(str.str(), "f2", "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2");
+ }
case BuiltinType::kCross:
- return builder->Call(str.str(), "f3", "f3");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h3", "h3");
+ } else {
+ return builder->Call(str.str(), "f3", "f3");
+ }
case BuiltinType::kFma:
case BuiltinType::kMix:
case BuiltinType::kFaceForward:
case BuiltinType::kSmoothstep:
- case BuiltinType::kSmoothStep:
- return builder->Call(str.str(), "f2", "f2", "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "h2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2", "f2");
+ }
case BuiltinType::kAll:
case BuiltinType::kAny:
return builder->Call(str.str(), "b2");
case BuiltinType::kAbs:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2");
} else {
return builder->Call(str.str(), "u2");
}
@@ -127,44 +152,73 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
return builder->Call(str.str(), "u2");
case BuiltinType::kMax:
case BuiltinType::kMin:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2", "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2");
} else {
return builder->Call(str.str(), "u2", "u2");
}
case BuiltinType::kClamp:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2", "f2", "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "h2");
} else {
return builder->Call(str.str(), "u2", "u2", "u2");
}
case BuiltinType::kSelect:
- return builder->Call(str.str(), "f2", "f2", "b2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "b2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2", "b2");
+ }
case BuiltinType::kDeterminant:
- return builder->Call(str.str(), "m2x2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "hm2x2");
+ } else {
+ return builder->Call(str.str(), "m2x2");
+ }
case BuiltinType::kTranspose:
- return builder->Call(str.str(), "m3x2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "hm3x2");
+ } else {
+ return builder->Call(str.str(), "m3x2");
+ }
default:
break;
}
return nullptr;
}
+
using HlslBuiltinTest = TestParamHelper<BuiltinData>;
TEST_P(HlslBuiltinTest, Emit) {
auto param = GetParam();
- Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
- Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
- Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
- Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
- Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
- Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
+ if (param.type == CallParamType::kF16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("h2", ty.vec2<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("h3", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("hm2x2", ty.mat2x2<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("hm3x2", ty.mat3x2<f16>(), ast::StorageClass::kPrivate);
+ }
+
+ GlobalVar("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
+ GlobalVar("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
auto* call = GenerateCall(param.builtin, param.type, this);
ASSERT_NE(nullptr, call) << "Unhandled builtin";
- Func("func", {}, ty.void_(), {CallStmt(call)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(call),
+ },
+ utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build();
@@ -180,71 +234,116 @@ TEST_P(HlslBuiltinTest, Emit) {
INSTANTIATE_TEST_SUITE_P(
HlslGeneratorImplTest_Builtin,
HlslBuiltinTest,
- testing::Values(BuiltinData{BuiltinType::kAbs, ParamType::kF32, "abs"},
- BuiltinData{BuiltinType::kAbs, ParamType::kU32, "abs"},
- BuiltinData{BuiltinType::kAcos, ParamType::kF32, "acos"},
- BuiltinData{BuiltinType::kAll, ParamType::kBool, "all"},
- BuiltinData{BuiltinType::kAny, ParamType::kBool, "any"},
- BuiltinData{BuiltinType::kAsin, ParamType::kF32, "asin"},
- BuiltinData{BuiltinType::kAtan, ParamType::kF32, "atan"},
- BuiltinData{BuiltinType::kAtan2, ParamType::kF32, "atan2"},
- BuiltinData{BuiltinType::kCeil, ParamType::kF32, "ceil"},
- BuiltinData{BuiltinType::kClamp, ParamType::kF32, "clamp"},
- BuiltinData{BuiltinType::kClamp, ParamType::kU32, "clamp"},
- BuiltinData{BuiltinType::kCos, ParamType::kF32, "cos"},
- BuiltinData{BuiltinType::kCosh, ParamType::kF32, "cosh"},
- BuiltinData{BuiltinType::kCountOneBits, ParamType::kU32, "countbits"},
- BuiltinData{BuiltinType::kCross, ParamType::kF32, "cross"},
- BuiltinData{BuiltinType::kDeterminant, ParamType::kF32, "determinant"},
- BuiltinData{BuiltinType::kDistance, ParamType::kF32, "distance"},
- BuiltinData{BuiltinType::kDot, ParamType::kF32, "dot"},
- BuiltinData{BuiltinType::kDpdx, ParamType::kF32, "ddx"},
- BuiltinData{BuiltinType::kDpdxCoarse, ParamType::kF32, "ddx_coarse"},
- BuiltinData{BuiltinType::kDpdxFine, ParamType::kF32, "ddx_fine"},
- BuiltinData{BuiltinType::kDpdy, ParamType::kF32, "ddy"},
- BuiltinData{BuiltinType::kDpdyCoarse, ParamType::kF32, "ddy_coarse"},
- BuiltinData{BuiltinType::kDpdyFine, ParamType::kF32, "ddy_fine"},
- BuiltinData{BuiltinType::kExp, ParamType::kF32, "exp"},
- BuiltinData{BuiltinType::kExp2, ParamType::kF32, "exp2"},
- BuiltinData{BuiltinType::kFaceForward, ParamType::kF32, "faceforward"},
- BuiltinData{BuiltinType::kFloor, ParamType::kF32, "floor"},
- BuiltinData{BuiltinType::kFma, ParamType::kF32, "mad"},
- BuiltinData{BuiltinType::kFract, ParamType::kF32, "frac"},
- BuiltinData{BuiltinType::kFwidth, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "rsqrt"},
- BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
- BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
- BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
- BuiltinData{BuiltinType::kLog2, ParamType::kF32, "log2"},
- BuiltinData{BuiltinType::kMax, ParamType::kF32, "max"},
- BuiltinData{BuiltinType::kMax, ParamType::kU32, "max"},
- BuiltinData{BuiltinType::kMin, ParamType::kF32, "min"},
- BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
- BuiltinData{BuiltinType::kMix, ParamType::kF32, "lerp"},
- BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
- BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
- BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
- BuiltinData{BuiltinType::kReverseBits, ParamType::kU32, "reversebits"},
- BuiltinData{BuiltinType::kRound, ParamType::kU32, "round"},
- BuiltinData{BuiltinType::kSign, ParamType::kF32, "sign"},
- BuiltinData{BuiltinType::kSin, ParamType::kF32, "sin"},
- BuiltinData{BuiltinType::kSinh, ParamType::kF32, "sinh"},
- BuiltinData{BuiltinType::kSmoothstep, ParamType::kF32, "smoothstep"},
- BuiltinData{BuiltinType::kSmoothStep, ParamType::kF32, "smoothstep"},
- BuiltinData{BuiltinType::kSqrt, ParamType::kF32, "sqrt"},
- BuiltinData{BuiltinType::kStep, ParamType::kF32, "step"},
- BuiltinData{BuiltinType::kTan, ParamType::kF32, "tan"},
- BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
- BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
- BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
+ testing::Values(/* Logical built-in */
+ BuiltinData{BuiltinType::kAll, CallParamType::kBool, "all"},
+ BuiltinData{BuiltinType::kAny, CallParamType::kBool, "any"},
+ /* Float built-in */
+ BuiltinData{BuiltinType::kAbs, CallParamType::kF32, "abs"},
+ BuiltinData{BuiltinType::kAbs, CallParamType::kF16, "abs"},
+ BuiltinData{BuiltinType::kAcos, CallParamType::kF32, "acos"},
+ BuiltinData{BuiltinType::kAcos, CallParamType::kF16, "acos"},
+ BuiltinData{BuiltinType::kAsin, CallParamType::kF32, "asin"},
+ BuiltinData{BuiltinType::kAsin, CallParamType::kF16, "asin"},
+ BuiltinData{BuiltinType::kAtan, CallParamType::kF32, "atan"},
+ BuiltinData{BuiltinType::kAtan, CallParamType::kF16, "atan"},
+ BuiltinData{BuiltinType::kAtan2, CallParamType::kF32, "atan2"},
+ BuiltinData{BuiltinType::kAtan2, CallParamType::kF16, "atan2"},
+ BuiltinData{BuiltinType::kCeil, CallParamType::kF32, "ceil"},
+ BuiltinData{BuiltinType::kCeil, CallParamType::kF16, "ceil"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kF32, "clamp"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kF16, "clamp"},
+ BuiltinData{BuiltinType::kCos, CallParamType::kF32, "cos"},
+ BuiltinData{BuiltinType::kCos, CallParamType::kF16, "cos"},
+ BuiltinData{BuiltinType::kCosh, CallParamType::kF32, "cosh"},
+ BuiltinData{BuiltinType::kCosh, CallParamType::kF16, "cosh"},
+ BuiltinData{BuiltinType::kCross, CallParamType::kF32, "cross"},
+ BuiltinData{BuiltinType::kCross, CallParamType::kF16, "cross"},
+ BuiltinData{BuiltinType::kDistance, CallParamType::kF32, "distance"},
+ BuiltinData{BuiltinType::kDistance, CallParamType::kF16, "distance"},
+ BuiltinData{BuiltinType::kExp, CallParamType::kF32, "exp"},
+ BuiltinData{BuiltinType::kExp, CallParamType::kF16, "exp"},
+ BuiltinData{BuiltinType::kExp2, CallParamType::kF32, "exp2"},
+ BuiltinData{BuiltinType::kExp2, CallParamType::kF16, "exp2"},
+ BuiltinData{BuiltinType::kFaceForward, CallParamType::kF32, "faceforward"},
+ BuiltinData{BuiltinType::kFaceForward, CallParamType::kF16, "faceforward"},
+ BuiltinData{BuiltinType::kFloor, CallParamType::kF32, "floor"},
+ BuiltinData{BuiltinType::kFloor, CallParamType::kF16, "floor"},
+ BuiltinData{BuiltinType::kFma, CallParamType::kF32, "mad"},
+ BuiltinData{BuiltinType::kFma, CallParamType::kF16, "mad"},
+ BuiltinData{BuiltinType::kFract, CallParamType::kF32, "frac"},
+ BuiltinData{BuiltinType::kFract, CallParamType::kF16, "frac"},
+ BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+ BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+ BuiltinData{BuiltinType::kLdexp, CallParamType::kF32, "ldexp"},
+ BuiltinData{BuiltinType::kLdexp, CallParamType::kF16, "ldexp"},
+ BuiltinData{BuiltinType::kLength, CallParamType::kF32, "length"},
+ BuiltinData{BuiltinType::kLength, CallParamType::kF16, "length"},
+ BuiltinData{BuiltinType::kLog, CallParamType::kF32, "log"},
+ BuiltinData{BuiltinType::kLog, CallParamType::kF16, "log"},
+ BuiltinData{BuiltinType::kLog2, CallParamType::kF32, "log2"},
+ BuiltinData{BuiltinType::kLog2, CallParamType::kF16, "log2"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kF32, "max"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kF16, "max"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kF32, "min"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kF16, "min"},
+ BuiltinData{BuiltinType::kMix, CallParamType::kF32, "lerp"},
+ BuiltinData{BuiltinType::kMix, CallParamType::kF16, "lerp"},
+ BuiltinData{BuiltinType::kNormalize, CallParamType::kF32, "normalize"},
+ BuiltinData{BuiltinType::kNormalize, CallParamType::kF16, "normalize"},
+ BuiltinData{BuiltinType::kPow, CallParamType::kF32, "pow"},
+ BuiltinData{BuiltinType::kPow, CallParamType::kF16, "pow"},
+ BuiltinData{BuiltinType::kReflect, CallParamType::kF32, "reflect"},
+ BuiltinData{BuiltinType::kReflect, CallParamType::kF16, "reflect"},
+ BuiltinData{BuiltinType::kSign, CallParamType::kF32, "sign"},
+ BuiltinData{BuiltinType::kSign, CallParamType::kF16, "sign"},
+ BuiltinData{BuiltinType::kSin, CallParamType::kF32, "sin"},
+ BuiltinData{BuiltinType::kSin, CallParamType::kF16, "sin"},
+ BuiltinData{BuiltinType::kSinh, CallParamType::kF32, "sinh"},
+ BuiltinData{BuiltinType::kSinh, CallParamType::kF16, "sinh"},
+ BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF32, "smoothstep"},
+ BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF16, "smoothstep"},
+ BuiltinData{BuiltinType::kSqrt, CallParamType::kF32, "sqrt"},
+ BuiltinData{BuiltinType::kSqrt, CallParamType::kF16, "sqrt"},
+ BuiltinData{BuiltinType::kStep, CallParamType::kF32, "step"},
+ BuiltinData{BuiltinType::kStep, CallParamType::kF16, "step"},
+ BuiltinData{BuiltinType::kTan, CallParamType::kF32, "tan"},
+ BuiltinData{BuiltinType::kTan, CallParamType::kF16, "tan"},
+ BuiltinData{BuiltinType::kTanh, CallParamType::kF32, "tanh"},
+ BuiltinData{BuiltinType::kTanh, CallParamType::kF16, "tanh"},
+ BuiltinData{BuiltinType::kTrunc, CallParamType::kF32, "trunc"},
+ BuiltinData{BuiltinType::kTrunc, CallParamType::kF16, "trunc"},
+ /* Integer built-in */
+ BuiltinData{BuiltinType::kAbs, CallParamType::kU32, "abs"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kU32, "clamp"},
+ BuiltinData{BuiltinType::kCountOneBits, CallParamType::kU32, "countbits"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kU32, "max"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kU32, "min"},
+ BuiltinData{BuiltinType::kReverseBits, CallParamType::kU32, "reversebits"},
+ BuiltinData{BuiltinType::kRound, CallParamType::kU32, "round"},
+ /* Matrix built-in */
+ BuiltinData{BuiltinType::kDeterminant, CallParamType::kF32, "determinant"},
+ BuiltinData{BuiltinType::kDeterminant, CallParamType::kF16, "determinant"},
+ BuiltinData{BuiltinType::kTranspose, CallParamType::kF32, "transpose"},
+ BuiltinData{BuiltinType::kTranspose, CallParamType::kF16, "transpose"},
+ /* Vector built-in */
+ BuiltinData{BuiltinType::kDot, CallParamType::kF32, "dot"},
+ BuiltinData{BuiltinType::kDot, CallParamType::kF16, "dot"},
+ /* Derivate built-in */
+ BuiltinData{BuiltinType::kDpdx, CallParamType::kF32, "ddx"},
+ BuiltinData{BuiltinType::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
+ BuiltinData{BuiltinType::kDpdxFine, CallParamType::kF32, "ddx_fine"},
+ BuiltinData{BuiltinType::kDpdy, CallParamType::kF32, "ddy"},
+ BuiltinData{BuiltinType::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
+ BuiltinData{BuiltinType::kDpdyFine, CallParamType::kF32, "ddy_fine"},
+ BuiltinData{BuiltinType::kFwidth, CallParamType::kF32, "fwidth"},
+ BuiltinData{BuiltinType::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+ BuiltinData{BuiltinType::kFwidthFine, CallParamType::kF32, "fwidth"}));
TEST_F(HlslGeneratorImplTest_Builtin, Builtin_Call) {
auto* call = Call("dot", "param1", "param2");
- Global("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
@@ -278,7 +377,7 @@ TEST_F(HlslGeneratorImplTest_Builtin, Select_Vector) {
EXPECT_EQ(out.str(), "(bool2(true, false) ? int2(3, 4) : int2(1, 2))");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Modf_Scalar) {
+TEST_F(HlslGeneratorImplTest_Builtin, Modf_Scalar_f32) {
auto* call = Call("modf", 1_f);
WrapInFunction(CallStmt(call));
@@ -290,9 +389,8 @@ TEST_F(HlslGeneratorImplTest_Builtin, Modf_Scalar) {
float whole;
};
modf_result tint_modf(float param_0) {
- float whole;
- float fract = modf(param_0, whole);
- modf_result result = {fract, whole};
+ modf_result result;
+ result.fract = modf(param_0, result.whole);
return result;
}
@@ -304,7 +402,34 @@ void test_function() {
)");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Modf_Vector) {
+TEST_F(HlslGeneratorImplTest_Builtin, Modf_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", 1_h);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(struct modf_result_f16 {
+ float16_t fract;
+ float16_t whole;
+};
+modf_result_f16 tint_modf(float16_t param_0) {
+ modf_result_f16 result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ tint_modf(float16_t(1.0h));
+ return;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Builtin, Modf_Vector_f32) {
auto* call = Call("modf", vec3<f32>());
WrapInFunction(CallStmt(call));
@@ -316,9 +441,8 @@ TEST_F(HlslGeneratorImplTest_Builtin, Modf_Vector) {
float3 whole;
};
modf_result_vec3 tint_modf(float3 param_0) {
- float3 whole;
- float3 fract = modf(param_0, whole);
- modf_result_vec3 result = {fract, whole};
+ modf_result_vec3 result;
+ result.fract = modf(param_0, result.whole);
return result;
}
@@ -330,7 +454,34 @@ void test_function() {
)");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Scalar_i32) {
+TEST_F(HlslGeneratorImplTest_Builtin, Modf_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", vec3<f16>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(struct modf_result_vec3_f16 {
+ vector<float16_t, 3> fract;
+ vector<float16_t, 3> whole;
+};
+modf_result_vec3_f16 tint_modf(vector<float16_t, 3> param_0) {
+ modf_result_vec3_f16 result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ tint_modf((float16_t(0.0h)).xxx);
+ return;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Scalar_f32) {
auto* call = Call("frexp", 1_f);
WrapInFunction(CallStmt(call));
@@ -356,7 +507,35 @@ void test_function() {
)");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Vector_i32) {
+TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", 1_h);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(struct frexp_result_f16 {
+ float16_t sig;
+ int exp;
+};
+frexp_result_f16 tint_frexp(float16_t param_0) {
+ float16_t exp;
+ float16_t sig = frexp(param_0, exp);
+ frexp_result_f16 result = {sig, int(exp)};
+ return result;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ tint_frexp(float16_t(1.0h));
+ return;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Vector_f32) {
auto* call = Call("frexp", vec3<f32>());
WrapInFunction(CallStmt(call));
@@ -382,7 +561,35 @@ void test_function() {
)");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Scalar) {
+TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", vec3<f16>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(struct frexp_result_vec3_f16 {
+ vector<float16_t, 3> sig;
+ int3 exp;
+};
+frexp_result_vec3_f16 tint_frexp(vector<float16_t, 3> param_0) {
+ vector<float16_t, 3> exp;
+ vector<float16_t, 3> sig = frexp(param_0, exp);
+ frexp_result_vec3_f16 result = {sig, int3(exp)};
+ return result;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ tint_frexp((float16_t(0.0h)).xxx);
+ return;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Scalar_f32) {
auto* val = Var("val", ty.f32());
auto* call = Call("degrees", val);
WrapInFunction(val, call);
@@ -403,7 +610,7 @@ void test_function() {
)");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Vector) {
+TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Vector_f32) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("degrees", val);
WrapInFunction(val, call);
@@ -424,7 +631,53 @@ void test_function() {
)");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Radians_Scalar) {
+TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.f16());
+ auto* call = Call("degrees", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(float16_t tint_degrees(float16_t param_0) {
+ return param_0 * 57.295779513082322865;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ float16_t val = float16_t(0.0h);
+ const float16_t tint_symbol = tint_degrees(val);
+ return;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.vec3<f16>());
+ auto* call = Call("degrees", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(vector<float16_t, 3> tint_degrees(vector<float16_t, 3> param_0) {
+ return param_0 * 57.295779513082322865;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ vector<float16_t, 3> val = vector<float16_t, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+ const vector<float16_t, 3> tint_symbol = tint_degrees(val);
+ return;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Builtin, Radians_Scalar_f32) {
auto* val = Var("val", ty.f32());
auto* call = Call("radians", val);
WrapInFunction(val, call);
@@ -445,7 +698,7 @@ void test_function() {
)");
}
-TEST_F(HlslGeneratorImplTest_Builtin, Radians_Vector) {
+TEST_F(HlslGeneratorImplTest_Builtin, Radians_Vector_f32) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("radians", val);
WrapInFunction(val, call);
@@ -466,9 +719,55 @@ void test_function() {
)");
}
+TEST_F(HlslGeneratorImplTest_Builtin, Radians_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.f16());
+ auto* call = Call("radians", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(float16_t tint_radians(float16_t param_0) {
+ return param_0 * 0.017453292519943295474;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ float16_t val = float16_t(0.0h);
+ const float16_t tint_symbol = tint_radians(val);
+ return;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Builtin, Radians_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.vec3<f16>());
+ auto* call = Call("radians", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(vector<float16_t, 3> tint_radians(vector<float16_t, 3> param_0) {
+ return param_0 * 0.017453292519943295474;
+}
+
+[numthreads(1, 1, 1)]
+void test_function() {
+ vector<float16_t, 3> val = vector<float16_t, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+ const vector<float16_t, 3> tint_symbol = tint_radians(val);
+ return;
+}
+)");
+}
+
TEST_F(HlslGeneratorImplTest_Builtin, Pack4x8Snorm) {
auto* call = Call("pack4x8snorm", "p1");
- Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -490,7 +789,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Pack4x8Unorm) {
auto* call = Call("pack4x8unorm", "p1");
- Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -512,7 +811,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Snorm) {
auto* call = Call("pack2x16snorm", "p1");
- Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -534,7 +833,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Unorm) {
auto* call = Call("pack2x16unorm", "p1");
- Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -556,7 +855,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Float) {
auto* call = Call("pack2x16float", "p1");
- Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -578,7 +877,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Unpack4x8Snorm) {
auto* call = Call("unpack4x8snorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -601,7 +900,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Unpack4x8Unorm) {
auto* call = Call("unpack4x8unorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -624,7 +923,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Snorm) {
auto* call = Call("unpack2x16snorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -647,7 +946,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Unorm) {
auto* call = Call("unpack2x16unorm", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -670,7 +969,7 @@ void test_function() {
TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Float) {
auto* call = Call("unpack2x16float", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -691,8 +990,11 @@ void test_function() {
}
TEST_F(HlslGeneratorImplTest_Builtin, StorageBarrier) {
- Func("main", {}, ty.void_(), {CallStmt(Call("storageBarrier"))},
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("storageBarrier")),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -709,8 +1011,11 @@ void main() {
}
TEST_F(HlslGeneratorImplTest_Builtin, WorkgroupBarrier) {
- Func("main", {}, ty.void_(), {CallStmt(Call("workgroupBarrier"))},
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("workgroupBarrier")),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -727,7 +1032,7 @@ void main() {
}
TEST_F(HlslGeneratorImplTest_Builtin, Dot4I8Packed) {
- Enable(ast::Extension::kChromiumExperimentalDP4a);
+ Enable(ast::Extension::kChromiumExperimentalDp4A);
auto* val1 = Var("val1", ty.u32());
auto* val2 = Var("val2", ty.u32());
@@ -753,7 +1058,7 @@ void test_function() {
}
TEST_F(HlslGeneratorImplTest_Builtin, Dot4U8Packed) {
- Enable(ast::Extension::kChromiumExperimentalDP4a);
+ Enable(ast::Extension::kChromiumExperimentalDp4A);
auto* val1 = Var("val1", ty.u32());
auto* val2 = Var("val2", ty.u32());
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
index 371cc1df611..b996b70e7da 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
@@ -370,7 +370,8 @@ TEST_P(HlslGeneratorBuiltinTextureTest, Call) {
auto* call = Call(param.function, param.args(this));
auto* stmt = CallStmt(call);
- Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_call_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_call_test.cc
index b72b0eb740f..82fb9264cfe 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_call_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_call_test.cc
@@ -23,7 +23,7 @@ namespace {
using HlslGeneratorImplTest_Call = TestHelper;
TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithoutParams) {
- Func("my_func", {}, ty.f32(), {Return(1.23_f)});
+ Func("my_func", utils::Empty, ty.f32(), utils::Vector{Return(1.23_f)});
auto* call = Call("my_func");
WrapInFunction(call);
@@ -37,13 +37,13 @@ TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithoutParams) {
TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithParams) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.f32(), {Return(1.23_f)});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.f32(), utils::Vector{Return(1.23_f)});
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = Call("my_func", "param1", "param2");
WrapInFunction(call);
@@ -57,13 +57,13 @@ TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithParams) {
TEST_F(HlslGeneratorImplTest_Call, EmitStatement_Call) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.void_(), ast::StatementList{}, ast::AttributeList{});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.void_(), utils::Empty, utils::Empty);
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = CallStmt(Call("my_func", "param1", "param2"));
WrapInFunction(call);
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_case_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_case_test.cc
index ee3acfcc06f..c55f14b6a18 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_case_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_case_test.cc
@@ -75,8 +75,9 @@ TEST_F(HlslGeneratorImplTest_Case, Emit_Case_WithFallthrough) {
}
TEST_F(HlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
- auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
- DefaultCase());
+ auto* s =
+ Switch(1_i, Case(utils::Vector{Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+ DefaultCase());
WrapInFunction(s);
GeneratorImpl& gen = Build();
@@ -99,7 +100,7 @@ TEST_F(HlslGeneratorImplTest_Case, Emit_Case_Default) {
gen.increment_indent();
- ASSERT_TRUE(gen.EmitCase(s, 0_i)) << gen.error();
+ ASSERT_TRUE(gen.EmitCase(s, 0u)) << gen.error();
EXPECT_EQ(gen.result(), R"( default: {
break;
}
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_constructor_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_constructor_test.cc
index fbcc79b6936..bb708db1fe9 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_constructor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_constructor_test.cc
@@ -61,6 +61,18 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Float) {
EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
}
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_F16) {
+ Enable(ast::Extension::kF16);
+
+ // Use a number close to 1<<16 but whose decimal representation ends in 0.
+ WrapInFunction(Expr(f16((1 << 15) - 8)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("float16_t(32752.0h)"));
+}
+
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Float) {
WrapInFunction(Construct<f32>(-1.2e-5_f));
@@ -70,6 +82,17 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Float) {
EXPECT_THAT(gen.result(), HasSubstr("-0.000012f"));
}
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(Construct<f16>(-1.2e-3_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("float16_t(-0.00119972229h)"));
+}
+
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Bool) {
WrapInFunction(Construct<bool>(true));
@@ -97,7 +120,7 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Uint) {
EXPECT_THAT(gen.result(), HasSubstr("12345u"));
}
-TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec) {
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_F32) {
WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
GeneratorImpl& gen = Build();
@@ -106,7 +129,20 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec) {
EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
}
-TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(
+ gen.result(),
+ HasSubstr("vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h))"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty_F32) {
WrapInFunction(vec3<f32>());
GeneratorImpl& gen = Build();
@@ -115,7 +151,18 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
EXPECT_THAT(gen.result(), HasSubstr("0.0f).xxx"));
}
-TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Float_Literal) {
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>());
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("(float16_t(0.0h)).xxx"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F32_Literal) {
WrapInFunction(vec3<f32>(2_f));
GeneratorImpl& gen = Build();
@@ -124,7 +171,18 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_
EXPECT_THAT(gen.result(), HasSubstr("2.0f).xxx"));
}
-TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Float_Var) {
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F16_Literal) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(2_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("(float16_t(2.0h)).xxx"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F32_Var) {
auto* var = Var("v", nullptr, Expr(2_f));
auto* cast = vec3<f32>(var);
WrapInFunction(var, cast);
@@ -136,6 +194,20 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_
const float3 tint_symbol = float3((v).xxx);)"));
}
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_F16_Var) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("v", nullptr, Expr(2_h));
+ auto* cast = vec3<f16>(var);
+ WrapInFunction(var, cast);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr(R"(float16_t v = float16_t(2.0h);
+ const vector<float16_t, 3> tint_symbol = vector<float16_t, 3>((v).xxx);)"));
+}
+
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Bool_Literal) {
WrapInFunction(vec3<bool>(true));
@@ -175,7 +247,7 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_
EXPECT_THAT(gen.result(), HasSubstr("2u).xxx"));
}
-TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat) {
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_F32) {
WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
GeneratorImpl& gen = Build();
@@ -186,7 +258,82 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat) {
HasSubstr("float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
}
-TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty) {
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("matrix<float16_t, 2, 3>(vector<float16_t, 3>(float16_t(1.0h), "
+ "float16_t(2.0h), float16_t(3.0h)), vector<float16_t, "
+ "3>(float16_t(3.0h), float16_t(4.0h), float16_t(5.0h)))"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Complex_F32) {
+ // mat4x4<f32>(
+ // vec4<f32>(2.0f, 3.0f, 4.0f, 8.0f),
+ // vec4<f32>(),
+ // vec4<f32>(7.0f),
+ // vec4<f32>(vec4<f32>(42.0f, 21.0f, 6.0f, -5.0f)),
+ // );
+ auto* vector_literal =
+ vec4<f32>(Expr(f32(2.0)), Expr(f32(3.0)), Expr(f32(4.0)), Expr(f32(8.0)));
+ auto* vector_zero_ctor = vec4<f32>();
+ auto* vector_single_scalar_ctor = vec4<f32>(Expr(f32(7.0)));
+ auto* vector_identical_ctor =
+ vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
+
+ auto* constructor = mat4x4<f32>(vector_literal, vector_zero_ctor, vector_single_scalar_ctor,
+ vector_identical_ctor);
+
+ WrapInFunction(constructor);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("float4x4(float4(2.0f, 3.0f, 4.0f, 8.0f), (0.0f).xxxx, "
+ "(7.0f).xxxx, float4(42.0f, 21.0f, 6.0f, -5.0f))"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Complex_F16) {
+ // mat4x4<f16>(
+ // vec4<f16>(2.0h, 3.0h, 4.0h, 8.0h),
+ // vec4<f16>(),
+ // vec4<f16>(7.0h),
+ // vec4<f16>(vec4<f16>(42.0h, 21.0h, 6.0h, -5.0h)),
+ // );
+ Enable(ast::Extension::kF16);
+
+ auto* vector_literal =
+ vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
+ auto* vector_zero_ctor = vec4<f16>();
+ auto* vector_single_scalar_ctor = vec4<f16>(Expr(f16(7.0)));
+ auto* vector_identical_ctor =
+ vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
+
+ auto* constructor = mat4x4<f16>(vector_literal, vector_zero_ctor, vector_single_scalar_ctor,
+ vector_identical_ctor);
+
+ WrapInFunction(constructor);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("matrix<float16_t, 4, 4>("
+ "vector<float16_t, 4>(float16_t(2.0h), float16_t(3.0h), "
+ "float16_t(4.0h), float16_t(8.0h)), "
+ "(float16_t(0.0h)).xxxx, (float16_t(7.0h)).xxxx, "
+ "vector<float16_t, 4>(float16_t(42.0h), float16_t(21.0h), "
+ "float16_t(6.0h), float16_t(-5.0h)))"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty_F32) {
WrapInFunction(mat2x3<f32>());
GeneratorImpl& gen = Build();
@@ -196,6 +343,58 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty) {
EXPECT_THAT(gen.result(), HasSubstr("float2x3 tint_symbol = float2x3((0.0f).xxx, (0.0f).xxx)"));
}
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(mat2x3<f16>());
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx)"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Identity_F32) {
+ // fn f() {
+ // var m_1: mat4x4<f32> = mat4x4<f32>();
+ // var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
+ // }
+
+ auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), mat4x4<f32>());
+ auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), mat4x4<f32>(m_1));
+
+ WrapInFunction(m_1, m_2);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("float4x4 m_2 = float4x4(m_1);"));
+}
+
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Identity_F16) {
+ // fn f() {
+ // var m_1: mat4x4<f16> = mat4x4<f16>();
+ // var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
+ // }
+
+ Enable(ast::Extension::kF16);
+
+ auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
+ auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
+
+ WrapInFunction(m_1, m_2);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("matrix<float16_t, 4, 4> m_2 = matrix<float16_t, 4, 4>(m_1);"));
+}
+
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array) {
WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
@@ -217,7 +416,7 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array_Empty) {
}
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
Member("c", ty.vec3<i32>()),
@@ -232,7 +431,7 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
}
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
Member("c", ty.vec3<i32>()),
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_function_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_function_test.cc
index c994b35b5de..7e1ce60ef86 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -28,8 +28,8 @@ namespace {
using HlslGeneratorImplTest_Function = TestHelper;
TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
- Func("my_func", ast::VariableList{}, ty.void_(),
- {
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
});
@@ -45,8 +45,8 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
- Func("GeometryShader", ast::VariableList{}, ty.void_(),
- {
+ Func("GeometryShader", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
});
@@ -61,8 +61,13 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) {
- Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())}, ty.void_(),
- {
+ Func("my_func",
+ utils::Vector{
+ Param("a", ty.f32()),
+ Param("b", ty.i32()),
+ },
+ ty.void_(),
+ utils::Vector{
Return(),
});
@@ -78,8 +83,8 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_NoReturn_Void) {
- Func("main", ast::VariableList{}, ty.void_(), {/* no explicit return */},
- {
+ Func("main", utils::Empty, ty.void_(), utils::Empty /* no explicit return */,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -96,8 +101,8 @@ TEST_F(HlslGeneratorImplTest_Function, PtrParameter) {
// fn f(foo : ptr<function, f32>) -> f32 {
// return *foo;
// }
- Func("f", {Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))}, ty.f32(),
- {Return(Deref("foo"))});
+ Func("f", utils::Vector{Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))}, ty.f32(),
+ utils::Vector{Return(Deref("foo"))});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -112,9 +117,17 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOutVars)
// fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
// return foo;
// }
- auto* foo_in = Param("foo", ty.f32(), {Location(0)});
- Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
- {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
+ auto* foo_in = Param("foo", ty.f32(), utils::Vector{Location(0)});
+ Func("frag_main", utils::Vector{foo_in}, ty.f32(),
+ utils::Vector{
+ Return("foo"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(1),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -143,9 +156,18 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOut_Built
// fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
// return coord.x;
// }
- auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
- Func("frag_main", ast::VariableList{coord_in}, ty.f32(), {Return(MemberAccessor("coord", "x"))},
- {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
+ auto* coord_in =
+ Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+ Func("frag_main", utils::Vector{coord_in}, ty.f32(),
+ utils::Vector{
+ Return(MemberAccessor("coord", "x")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFragDepth),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -185,24 +207,27 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_SharedStruct_Di
// const p = inputs.pos;
// }
auto* interface_struct = Structure(
- "Interface", {
- Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
- Member("col1", ty.f32(), {Location(1)}),
- Member("col2", ty.f32(), {Location(2)}),
- });
-
- Func("vert_main", {}, ty.Of(interface_struct),
- {Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()), Expr(0.5_f),
- Expr(0.25_f)))},
- {Stage(ast::PipelineStage::kVertex)});
-
- Func("frag_main", {Param("inputs", ty.Of(interface_struct))}, ty.void_(),
- {
+ "Interface",
+ utils::Vector{
+ Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+ Member("col1", ty.f32(), utils::Vector{Location(1)}),
+ Member("col2", ty.f32(), utils::Vector{Location(2)}),
+ });
+
+ Func("vert_main", utils::Empty, ty.Of(interface_struct),
+ utils::Vector{
+ Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()), Expr(0.5_f),
+ Expr(0.25_f))),
+ },
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
+
+ Func("frag_main", utils::Vector{Param("inputs", ty.Of(interface_struct))}, ty.void_(),
+ utils::Vector{
Decl(Let("r", ty.f32(), MemberAccessor("inputs", "col1"))),
Decl(Let("g", ty.f32(), MemberAccessor("inputs", "col2"))),
Decl(Let("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
},
- {Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -265,19 +290,29 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_SharedStruct_He
// fn vert_main2() -> VertexOutput {
// return foo(0.25);
// }
- auto* vertex_output_struct = Structure(
- "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
-
- Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
- {Return(Construct(ty.Of(vertex_output_struct),
- Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1_f))))},
- {});
+ auto* vertex_output_struct =
+ Structure("VertexOutput",
+ utils::Vector{Member("pos", ty.vec4<f32>(),
+ utils::Vector{Builtin(ast::BuiltinValue::kPosition)})});
+
+ Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
+ utils::Vector{
+ Return(Construct(ty.Of(vertex_output_struct),
+ Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1_f)))),
+ },
+ utils::Empty);
- Func("vert_main1", {}, ty.Of(vertex_output_struct), {Return(Call("foo", Expr(0.5_f)))},
- {Stage(ast::PipelineStage::kVertex)});
+ Func("vert_main1", utils::Empty, ty.Of(vertex_output_struct),
+ utils::Vector{
+ Return(Call("foo", Expr(0.5_f))),
+ },
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
- Func("vert_main2", {}, ty.Of(vertex_output_struct), {Return(Call("foo", Expr(0.25_f)))},
- {Stage(ast::PipelineStage::kVertex)});
+ Func("vert_main2", utils::Empty, ty.Of(vertex_output_struct),
+ utils::Vector{
+ Return(Call("foo", Expr(0.25_f))),
+ },
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -324,30 +359,30 @@ tint_symbol_1 vert_main2() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_Uniform) {
- auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
- auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ auto* ubo_ty = Structure("UBO", utils::Vector{Member("coord", ty.vec4<f32>())});
+ auto* ubo = GlobalVar("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
Func("sub_func",
- {
+ utils::Vector{
Param("param", ty.f32()),
},
ty.f32(),
- {
+ utils::Vector{
Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
});
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", {}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -370,23 +405,23 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_UniformStruct) {
- auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())});
+ auto* s = Structure("Uniforms", utils::Vector{Member("coord", ty.vec4<f32>())});
- Global("uniforms", ty.Of(s), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("uniforms", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -405,25 +440,25 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RW_StorageBuffer_Read) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -441,25 +476,25 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RO_StorageBuffer_Read) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -477,23 +512,23 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_WO_StorageBuffer_Store) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(MemberAccessor("coord", "b"), Expr(2_f)),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -511,23 +546,23 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_StorageBuffer_Store) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(MemberAccessor("coord", "b"), Expr(2_f)),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -545,26 +580,30 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
- auto* s = Structure("S", {Member("x", ty.f32())});
- Global("coord", ty.Of(s), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
-
- Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
- {
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kUniform,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
+
+ Func("sub_func",
+ utils::Vector{
+ Param("param", ty.f32()),
+ },
+ ty.f32(),
+ utils::Vector{
Return(MemberAccessor("coord", "x")),
});
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -587,26 +626,30 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
- auto* s = Structure("S", {Member("x", ty.f32())});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(1),
- });
-
- Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
- {
+ auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(1u),
+ });
+
+ Func("sub_func",
+ utils::Vector{
+ Param("param", ty.f32()),
+ },
+ ty.f32(),
+ utils::Vector{
Return(MemberAccessor("coord", "x")),
});
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -628,8 +671,8 @@ void frag_main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithNameCollision) {
- Func("GeometryShader", ast::VariableList{}, ty.void_(), {},
- {
+ Func("GeometryShader", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -643,11 +686,11 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithNameCollisi
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute) {
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
GeneratorImpl& gen = Build();
@@ -660,8 +703,8 @@ void main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Literal) {
- Func("main", ast::VariableList{}, ty.void_(), {},
- {
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(2_i, 4_i, 6_i),
});
@@ -680,8 +723,8 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWor
GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
- Func("main", ast::VariableList{}, ty.void_(), {},
- {
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize("width", "height", "depth"),
});
@@ -689,11 +732,7 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWor
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_EQ(gen.result(), R"(static const int width = 2;
-static const int height = 3;
-static const int depth = 4;
-
-[numthreads(2, 3, 4)]
+ EXPECT_EQ(gen.result(), R"([numthreads(2, 3, 4)]
void main() {
return;
}
@@ -702,11 +741,11 @@ void main() {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Attribute_EntryPoint_Compute_WithWorkgroup_OverridableConst) {
- Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
- Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
- Override("depth", ty.i32(), Construct(ty.i32(), 4_i), {Id(9u)});
- Func("main", ast::VariableList{}, ty.void_(), {},
- {
+ Override("width", ty.i32(), Construct(ty.i32(), 2_i), utils::Vector{Id(7u)});
+ Override("height", ty.i32(), Construct(ty.i32(), 3_i), utils::Vector{Id(8u)});
+ Override("depth", ty.i32(), Construct(ty.i32(), 4_i), utils::Vector{Id(9u)});
+ Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize("width", "height", "depth"),
});
@@ -735,8 +774,12 @@ void main() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
- Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
- {
+ Func("my_func",
+ utils::Vector{
+ Param("a", ty.array<f32, 5>()),
+ },
+ ty.void_(),
+ utils::Vector{
Return(),
});
@@ -750,8 +793,8 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayReturn) {
- Func("my_func", {}, ty.array<f32, 5>(),
- {
+ Func("my_func", utils::Empty, ty.array<f32, 5>(),
+ utils::Vector{
Return(Construct(ty.array<f32, 5>())),
});
@@ -766,8 +809,8 @@ my_func_ret my_func() {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithDiscardAndVoidReturn) {
- Func("my_func", {Param("a", ty.i32())}, ty.void_(),
- {
+ Func("my_func", utils::Vector{Param("a", ty.i32())}, ty.void_(),
+ utils::Vector{
If(Equal("a", 0_i), //
Block(create<ast::DiscardStatement>())),
Return(),
@@ -786,8 +829,8 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithDiscardAndVoidReturn) {
}
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithDiscardAndNonVoidReturn) {
- Func("my_func", {Param("a", ty.i32())}, ty.i32(),
- {
+ Func("my_func", utils::Vector{Param("a", ty.i32())}, ty.i32(),
+ utils::Vector{
If(Equal("a", 0_i), //
Block(create<ast::DiscardStatement>())),
Return(42_i),
@@ -828,34 +871,40 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Multiple_EntryPoint_With_Same_Module
// return;
// }
- auto* s = Structure("Data", {Member("d", ty.f32())});
+ auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
- Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("a", ast::VariableList{}, ty.void_(),
- {
+ Func("a", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
}
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("b", ast::VariableList{}, ty.void_(),
- {
+ Func("b", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
}
GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_identifier_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_identifier_test.cc
index d982e1e7dfd..d4b645f6bd7 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_identifier_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_identifier_test.cc
@@ -20,7 +20,7 @@ namespace {
using HlslGeneratorImplTest_Identifier = TestHelper;
TEST_F(HlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
- Global("foo", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("foo", ty.i32(), ast::StorageClass::kPrivate);
auto* i = Expr("foo");
WrapInFunction(i);
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_if_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_if_test.cc
index 1668d71cb8a..3195a06ca73 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_if_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_if_test.cc
@@ -20,7 +20,7 @@ namespace {
using HlslGeneratorImplTest_If = TestHelper;
TEST_F(HlslGeneratorImplTest_If, Emit_If) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* cond = Expr("cond");
auto* body = Block(Return());
@@ -38,8 +38,8 @@ TEST_F(HlslGeneratorImplTest_If, Emit_If) {
}
TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElseIf) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
- Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_cond = Expr("else_cond");
auto* else_body = Block(Return());
@@ -65,7 +65,7 @@ TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElseIf) {
}
TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElse) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_body = Block(Return());
@@ -88,8 +88,8 @@ TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElse) {
}
TEST_F(HlslGeneratorImplTest_If, Emit_IfWithMultiple) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
- Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_cond = Expr("else_cond");
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_import_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_import_test.cc
index f7d544e49cd..d6fdeac1d08 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_import_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_import_test.cc
@@ -259,7 +259,7 @@ INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
testing::Values(HlslImportData{"clamp", "clamp"}));
TEST_F(HlslGeneratorImplTest_Import, HlslImportData_Determinant) {
- Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("determinant", "var");
WrapInFunction(expr);
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_loop_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_loop_test.cc
index 0bf4090c96d..9f288f6334b 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_loop_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_loop_test.cc
@@ -66,8 +66,8 @@ TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
Func("a_statement", {}, ty.void_(), {});
- Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
- Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("lhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.f32(), ast::StorageClass::kPrivate);
auto* body = Block(create<ast::DiscardStatement>());
auto* continuing = Block(CallStmt(Call("a_statement")));
@@ -112,7 +112,7 @@ TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopWithVarUsedInContinuing) {
// }
// }
- Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.f32(), ast::StorageClass::kPrivate);
auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4_f))), //
Decl(Var("other", ty.f32())), //
@@ -373,5 +373,69 @@ TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInitCondCont) {
)");
}
+TEST_F(HlslGeneratorImplTest_Loop, Emit_While) {
+ // while(true) {
+ // return;
+ // }
+
+ auto* f = While(Expr(true), Block(Return()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( [loop] while(true) {
+ return;
+ }
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Loop, Emit_While_WithContinue) {
+ // while(true) {
+ // continue;
+ // }
+
+ auto* f = While(Expr(true), Block(Continue()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( [loop] while(true) {
+ continue;
+ }
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_Loop, Emit_WhileWithMultiStmtCond) {
+ // while(true && false) {
+ // return;
+ // }
+
+ auto* multi_stmt =
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+ auto* f = While(multi_stmt, Block(Return()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( [loop] while (true) {
+ bool tint_tmp = true;
+ if (tint_tmp) {
+ tint_tmp = false;
+ }
+ if (!((tint_tmp))) { break; }
+ return;
+ }
+)");
+}
+
} // namespace
} // namespace tint::writer::hlsl
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
index 10e9f1096f6..a0068b969a0 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -86,24 +86,20 @@ inline const ast::Type* ty_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
template <typename BASE>
class HlslGeneratorImplTest_MemberAccessorBase : public BASE {
public:
- void SetupStorageBuffer(ast::StructMemberList members) {
+ void SetupStorageBuffer(utils::VectorRef<const ast::StructMember*> members) {
ProgramBuilder& b = *this;
-
auto* s = b.Structure("Data", members);
- b.Global("data", b.ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- b.create<ast::BindingAttribute>(0),
- b.create<ast::GroupAttribute>(1),
- });
+ b.GlobalVar("data", b.ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ b.GroupAndBinding(1, 0));
}
- void SetupFunction(ast::StatementList statements) {
+ void SetupFunction(utils::VectorRef<const ast::Statement*> statements) {
ProgramBuilder& b = *this;
- b.Func("main", ast::VariableList{}, b.ty.void_(), statements,
- ast::AttributeList{
- b.Stage(ast::PipelineStage::kFragment),
- });
+ utils::Vector attrs{
+ b.Stage(ast::PipelineStage::kFragment),
+ };
+ b.Func("main", utils::Empty, b.ty.void_(), std::move(statements), std::move(attrs));
}
};
@@ -114,8 +110,8 @@ using HlslGeneratorImplTest_MemberAccessorWithParam =
HlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
- auto* s = Structure("Data", {Member("mem", ty.f32())});
- Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+ auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
+ GlobalVar("str", ty.Of(s), ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("str", "mem");
WrapInFunction(Var("expr", ty.f32(), ast::StorageClass::kNone, expr));
@@ -160,12 +156,12 @@ TEST_P(HlslGeneratorImplTest_MemberAccessor_StorageBufferLoad, Test) {
auto p = GetParam();
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("a", ty.i32()),
Member("b", p.member_type(ty)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone, MemberAccessor("data", "b"))),
});
@@ -231,12 +227,12 @@ TEST_P(HlslGeneratorImplTest_MemberAccessor_StorageBufferStore, Test) {
auto p = GetParam();
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("a", ty.i32()),
Member("b", p.member_type(ty)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("value", p.member_type(ty), ast::StorageClass::kNone,
Construct(p.member_type(ty)))),
Assign(MemberAccessor("data", "b"), Expr("value")),
@@ -316,13 +312,13 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Matrix_Empty) {
// var<storage> data : Data;
// data.a = mat2x3<f32>();
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("a", ty.i32()),
Member("b", ty.mat2x3<f32>()),
});
- SetupFunction({
- Assign(MemberAccessor("data", "b"), Construct(ty.mat2x3<f32>(), ast::ExpressionList{})),
+ SetupFunction(utils::Vector{
+ Assign(MemberAccessor("data", "b"), Construct(ty.mat2x3<f32>())),
});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -352,12 +348,12 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_Matrix_Single_El
// var<storage> data : Data;
// data.a[2i][1i];
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.mat4x3<f32>()),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
});
@@ -384,12 +380,12 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Data;
// data.a[2];
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.array<i32, 5>(4)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
IndexAccessor(MemberAccessor("data", "a"), 2_i))),
});
@@ -416,14 +412,17 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Data;
// data.a[(2i + 4i) - 3i];
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.array<i32, 5>(4)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
+ Decl(Var("a", nullptr, Expr(2_i))),
+ Decl(Var("b", nullptr, Expr(4_i))),
+ Decl(Var("c", nullptr, Expr(3_i))),
Decl(Var("x", nullptr, ast::StorageClass::kNone,
- IndexAccessor(MemberAccessor("data", "a"), Sub(Add(2_i, Expr(4_i)), Expr(3_i))))),
+ IndexAccessor(MemberAccessor("data", "a"), Sub(Add("a", "b"), "c")))),
});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -433,7 +432,10 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
R"(RWByteAddressBuffer data : register(u0, space1);
void main() {
- int x = asint(data.Load((4u + (4u * uint(((2 + 4) - 3))))));
+ int a = 2;
+ int b = 4;
+ int c = 3;
+ int x = asint(data.Load((4u + (4u * uint(((a + b) - c))))));
return;
}
)";
@@ -447,12 +449,12 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
// var<storage> data : Data;
// data.a[2] = 2;
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("z", ty.f32()),
Member("a", ty.array<i32, 5>(4)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Assign(IndexAccessor(MemberAccessor("data", "a"), 2_i), 2_i),
});
@@ -482,16 +484,16 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
// var<storage> data : Pre;
// data.c[2].b
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"))),
});
@@ -522,16 +524,16 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Swizz
// var<storage> data : Pre;
// data.c[2].b.xy
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
MemberAccessor(
MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "xy"))),
@@ -564,16 +566,16 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Pre;
// data.c[2].b.g
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
MemberAccessor(
MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "g"))),
@@ -605,16 +607,16 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Index
// var<storage> data : Pre;
// data.c[2].b[1]
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Decl(Var("x", nullptr, ast::StorageClass::kNone,
IndexAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
1_i))),
@@ -646,16 +648,16 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
// var<storage> data : Pre;
// data.c[2].b = vec3<f32>(1_f, 2_f, 3_f);
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
vec3<f32>(1_f, 2_f, 3_f)),
});
@@ -686,16 +688,16 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Swizzle_SingleL
// var<storage> data : Pre;
// data.c[2].b.y = 1.f;
- auto* inner = Structure("Inner", {
+ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.vec3<i32>()),
Member("b", ty.vec3<f32>()),
});
- SetupStorageBuffer({
+ SetupStorageBuffer(utils::Vector{
Member("c", ty.array(ty.Of(inner), 4_u, 32)),
});
- SetupFunction({
+ SetupFunction(utils::Vector{
Assign(MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
"y"),
Expr(1_f)),
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_module_constant_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
index 2c967446239..7296d137aa3 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
@@ -22,25 +22,233 @@ namespace {
using HlslGeneratorImplTest_ModuleConstant = TestHelper;
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
- auto* var = Let("pos", ty.array<f32, 3>(), array<f32, 3>(1_f, 2_f, 3_f));
- WrapInFunction(Decl(var));
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AInt) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
- EXPECT_EQ(gen.result(), "static const float pos[3] = {1.0f, 2.0f, 3.0f};\n");
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AFloat) {
+ auto* var = GlobalConst("G", nullptr, Expr(1._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_i32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_i));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_u32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_u));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const uint l = 1u;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, Expr(1_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float16_t l = float16_t(1.0h);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AInt) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const int3 l = int3(1, 2, 3);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AFloat) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f32) {
+ auto* var = GlobalConst("G", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const vector<float16_t, 3> l = vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_AFloat) {
+ auto* var = GlobalConst("G", nullptr,
+ Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f32) {
+ auto* var = GlobalConst("G", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const matrix<float16_t, 2, 3> l = matrix<float16_t, 2, 3>(vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)), vector<float16_t, 3>(float16_t(4.0h), float16_t(5.0h), float16_t(6.0h)));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_f32) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float l[3] = {1.0f, 2.0f, 3.0f};
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_vec2_bool) {
+ auto* var = GlobalConst("G", nullptr,
+ Construct(ty.array(ty.vec2<bool>(), 3_u), //
+ vec2<bool>(true, false), //
+ vec2<bool>(false, true), //
+ vec2<bool>(true, true)));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const bool2 l[3] = {bool2(true, false), bool2(false, true), (true).xx};
+}
+)");
}
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
- auto* var = Override("pos", ty.f32(), Expr(3_f),
- ast::AttributeList{
- Id(23),
- });
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override) {
+ auto* var = Override("pos", ty.f32(), Expr(3_f), utils::Vector{Id(23)});
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(var)) << gen.error();
EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
#define WGSL_SPEC_CONSTANT_23 3.0f
#endif
@@ -48,15 +256,12 @@ static const float pos = WGSL_SPEC_CONSTANT_23;
)");
}
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
- auto* var = Override("pos", ty.f32(), nullptr,
- ast::AttributeList{
- Id(23),
- });
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override_NoConstructor) {
+ auto* var = Override("pos", ty.f32(), nullptr, utils::Vector{Id(23)});
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(var)) << gen.error();
EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
#error spec constant required for constant id 23
#endif
@@ -64,17 +269,14 @@ static const float pos = WGSL_SPEC_CONSTANT_23;
)");
}
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoId) {
- auto* a = Override("a", ty.f32(), Expr(3_f),
- ast::AttributeList{
- Id(0),
- });
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override_NoId) {
+ auto* a = Override("a", ty.f32(), Expr(3_f), utils::Vector{Id(0)});
auto* b = Override("b", ty.f32(), Expr(2_f));
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(a)) << gen.error();
- ASSERT_TRUE(gen.EmitProgramConstVariable(b)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(a)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(b)) << gen.error();
EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_0
#define WGSL_SPEC_CONSTANT_0 3.0f
#endif
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_return_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_return_test.cc
index 1813645206b..91b4159b12f 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_return_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_return_test.cc
@@ -35,7 +35,7 @@ TEST_F(HlslGeneratorImplTest_Return, Emit_Return) {
TEST_F(HlslGeneratorImplTest_Return, Emit_ReturnWithValue) {
auto* r = Return(123_i);
- Func("f", {}, ty.i32(), {r});
+ Func("f", utils::Empty, ty.i32(), utils::Vector{r});
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
index 66df5352483..3d0785a88c0 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -25,19 +25,19 @@ namespace {
using HlslSanitizerTest = TestHelper;
TEST_F(HlslSanitizerTest, Call_ArrayLength) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -60,22 +60,22 @@ void a_func() {
}
TEST_F(HlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member(0, "z", ty.f32()),
Member(4, "a", ty.array<f32>(4)),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -99,23 +99,23 @@ void a_func() {
}
TEST_F(HlslSanitizerTest, Call_ArrayLength_ViaLets) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
auto* p = Let("p", nullptr, AddressOf("b"));
auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(p),
Decl(p2),
Decl(Var("len", ty.u32(), ast::StorageClass::kNone, Call("arrayLength", p2))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -139,25 +139,25 @@ void a_func() {
}
TEST_F(HlslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
- Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(2),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+ GlobalVar("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(2u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -188,14 +188,13 @@ void a_func() {
TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
auto* array_init = array<i32, 4>(1_i, 2_i, 3_i, 4_i);
- auto* array_index = IndexAccessor(array_init, 3_i);
- auto* pos = Var("pos", ty.i32(), ast::StorageClass::kNone, array_index);
- Func("main", ast::VariableList{}, ty.void_(),
- {
- Decl(pos),
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(Var("idx", nullptr, Expr(3_i))),
+ Decl(Var("pos", ty.i32(), IndexAccessor(array_init, "idx"))),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -205,8 +204,9 @@ TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
auto got = gen.result();
auto* expect = R"(void main() {
+ int idx = 3;
const int tint_symbol[4] = {1, 2, 3, 4};
- int pos = tint_symbol[3];
+ int pos = tint_symbol[idx];
return;
}
)";
@@ -214,7 +214,7 @@ TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
}
TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.vec3<f32>()),
Member("c", ty.i32()),
@@ -223,11 +223,11 @@ TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
auto* struct_access = MemberAccessor(struct_init, "b");
auto* pos = Var("pos", ty.vec3<f32>(), ast::StorageClass::kNone, struct_access);
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(pos),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -259,13 +259,13 @@ TEST_F(HlslSanitizerTest, InlinePtrLetsBasic) {
auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(v));
auto* x = Var("x", ty.i32(), ast::StorageClass::kNone, Deref(p));
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(v),
Decl(p),
Decl(x),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -298,15 +298,15 @@ TEST_F(HlslSanitizerTest, InlinePtrLetsComplexChain) {
AddressOf(IndexAccessor(Deref(mp), 2_i)));
auto* v = Var("v", ty.vec4<f32>(), ast::StorageClass::kNone, Deref(vp));
- Func("main", ast::VariableList{}, ty.void_(),
- {
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(a),
Decl(ap),
Decl(mp),
Decl(vp),
Decl(v),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_static_assert_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_static_assert_test.cc
new file mode 100644
index 00000000000..8ae5dd8b00a
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_static_assert_test.cc
@@ -0,0 +1,47 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/writer/hlsl/test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::writer::hlsl {
+namespace {
+
+using HlslGeneratorImplTest = TestHelper;
+
+TEST_F(HlslGeneratorImplTest, Emit_GlobalStaticAssert) {
+ GlobalStaticAssert(true);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ // static asserts are not emitted
+ EXPECT_EQ(gen.result(), "");
+}
+
+TEST_F(HlslGeneratorImplTest, Emit_FunctionStaticAssert) {
+ Func("f", utils::Empty, ty.void_(), utils::Vector{StaticAssert(true)});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ // static asserts are not emitted
+ EXPECT_EQ(gen.result(), R"(void f() {
+}
+)");
+}
+
+} // namespace
+} // namespace tint::writer::hlsl
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_switch_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_switch_test.cc
index 3ef1a7be88d..7d896721186 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_switch_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_switch_test.cc
@@ -22,7 +22,7 @@ namespace {
using HlslGeneratorImplTest_Switch = TestHelper;
TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch) {
- Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.i32(), ast::StorageClass::kPrivate);
auto* s = Switch( //
Expr("cond"), //
Case(Expr(5_i), Block(Break())), //
@@ -46,8 +46,8 @@ TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch) {
}
TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch_OnlyDefaultCase) {
- Global("cond", ty.i32(), ast::StorageClass::kPrivate);
- Global("a", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
auto* s = Switch( //
Expr("cond"), //
DefaultCase(Block(Assign(Expr("a"), Expr(42_i)))));
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_test.cc
index a1e0edb33bf..35b9c82de75 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_test.cc
@@ -29,7 +29,7 @@ TEST_F(HlslGeneratorImplTest, InvalidProgram) {
}
TEST_F(HlslGeneratorImplTest, Generate) {
- Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+ Func("my_func", {}, ty.void_(), {});
GeneratorImpl& gen = Build();
@@ -40,7 +40,7 @@ TEST_F(HlslGeneratorImplTest, Generate) {
}
struct HlslBuiltinData {
- ast::Builtin builtin;
+ ast::BuiltinValue builtin;
const char* attribute_name;
};
inline std::ostream& operator<<(std::ostream& out, HlslBuiltinData data) {
@@ -57,17 +57,17 @@ TEST_P(HlslBuiltinConversionTest, Emit) {
INSTANTIATE_TEST_SUITE_P(
HlslGeneratorImplTest,
HlslBuiltinConversionTest,
- testing::Values(HlslBuiltinData{ast::Builtin::kPosition, "SV_Position"},
- HlslBuiltinData{ast::Builtin::kVertexIndex, "SV_VertexID"},
- HlslBuiltinData{ast::Builtin::kInstanceIndex, "SV_InstanceID"},
- HlslBuiltinData{ast::Builtin::kFrontFacing, "SV_IsFrontFace"},
- HlslBuiltinData{ast::Builtin::kFragDepth, "SV_Depth"},
- HlslBuiltinData{ast::Builtin::kLocalInvocationId, "SV_GroupThreadID"},
- HlslBuiltinData{ast::Builtin::kLocalInvocationIndex, "SV_GroupIndex"},
- HlslBuiltinData{ast::Builtin::kGlobalInvocationId, "SV_DispatchThreadID"},
- HlslBuiltinData{ast::Builtin::kWorkgroupId, "SV_GroupID"},
- HlslBuiltinData{ast::Builtin::kSampleIndex, "SV_SampleIndex"},
- HlslBuiltinData{ast::Builtin::kSampleMask, "SV_Coverage"}));
+ testing::Values(HlslBuiltinData{ast::BuiltinValue::kPosition, "SV_Position"},
+ HlslBuiltinData{ast::BuiltinValue::kVertexIndex, "SV_VertexID"},
+ HlslBuiltinData{ast::BuiltinValue::kInstanceIndex, "SV_InstanceID"},
+ HlslBuiltinData{ast::BuiltinValue::kFrontFacing, "SV_IsFrontFace"},
+ HlslBuiltinData{ast::BuiltinValue::kFragDepth, "SV_Depth"},
+ HlslBuiltinData{ast::BuiltinValue::kLocalInvocationId, "SV_GroupThreadID"},
+ HlslBuiltinData{ast::BuiltinValue::kLocalInvocationIndex, "SV_GroupIndex"},
+ HlslBuiltinData{ast::BuiltinValue::kGlobalInvocationId, "SV_DispatchThreadID"},
+ HlslBuiltinData{ast::BuiltinValue::kWorkgroupId, "SV_GroupID"},
+ HlslBuiltinData{ast::BuiltinValue::kSampleIndex, "SV_SampleIndex"},
+ HlslBuiltinData{ast::BuiltinValue::kSampleMask, "SV_Coverage"}));
} // namespace
} // namespace tint::writer::hlsl
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_type_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_type_test.cc
index b99f06eddcc..4e443d5651b 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_type_test.cc
@@ -33,7 +33,7 @@ using HlslGeneratorImplTest_Type = TestHelper;
TEST_F(HlslGeneratorImplTest_Type, EmitType_Array) {
auto* arr = ty.array<bool, 4>();
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -46,7 +46,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Array) {
TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
auto* arr = ty.array(ty.array<bool, 4>(), 5_u);
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -59,7 +59,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5_u), 6_u);
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -72,7 +72,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
TEST_F(HlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
auto* arr = ty.array<bool, 4>();
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -94,6 +94,17 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Bool) {
EXPECT_EQ(out.str(), "bool");
}
+TEST_F(HlslGeneratorImplTest_Type, EmitType_F16) {
+ auto* f16 = create<sem::F16>();
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, f16, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+ << gen.error();
+ EXPECT_EQ(out.str(), "float16_t");
+}
+
TEST_F(HlslGeneratorImplTest_Type, EmitType_F32) {
auto* f32 = create<sem::F32>();
@@ -116,7 +127,20 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_I32) {
EXPECT_EQ(out.str(), "int");
}
-TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix) {
+TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix_F16) {
+ auto* f16 = create<sem::F16>();
+ auto* vec3 = create<sem::Vector>(f16, 3u);
+ auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+ << gen.error();
+ EXPECT_EQ(out.str(), "matrix<float16_t, 2, 3>");
+}
+
+TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix_F32) {
auto* f32 = create<sem::F32>();
auto* vec3 = create<sem::Vector>(f32, 3u);
auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
@@ -130,11 +154,11 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix) {
}
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -149,15 +173,15 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
}
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -166,11 +190,11 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
}
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -182,11 +206,11 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
}
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("double", ty.i32()),
Member("float", ty.f32()),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = SanitizeAndBuild();
@@ -199,11 +223,11 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
}
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_WithOffsetAttributes) {
- auto* s = Structure("S", {
- Member("a", ty.i32(), {MemberOffset(0)}),
- Member("b", ty.f32(), {MemberOffset(8)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberOffset(0)}),
+ Member("b", ty.f32(), utils::Vector{MemberOffset(8)}),
});
- Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+ GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -287,14 +311,19 @@ TEST_P(HlslDepthTexturesTest, Emit) {
auto* t = ty.depth_texture(params.dim);
- Global("tex", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar("tex", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
@@ -317,14 +346,19 @@ using HlslDepthMultisampledTexturesTest = TestHelper;
TEST_F(HlslDepthMultisampledTexturesTest, Emit) {
auto* t = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
- Global("tex", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar("tex", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
@@ -360,14 +394,19 @@ TEST_P(HlslSampledTexturesTest, Emit) {
}
auto* t = ty.sampled_texture(params.dim, datatype);
- Global("tex", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar("tex", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
@@ -495,10 +534,18 @@ TEST_P(HlslStorageTexturesTest, Emit) {
auto* t = ty.storage_texture(params.dim, params.imgfmt, ast::Access::kWrite);
- Global("tex", t, ast::AttributeList{GroupAndBinding(2, 1)});
-
- Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
- {Stage(ast::PipelineStage::kFragment)});
+ GlobalVar("tex", t,
+ utils::Vector{
+ GroupAndBinding(2, 1),
+ });
+
+ Func("main", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call("textureDimensions", "tex")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_unary_op_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
index c9abf1f250e..74320ea7d17 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@ namespace {
using HlslUnaryOpTest = TestHelper;
TEST_F(HlslUnaryOpTest, AddressOf) {
- Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.f32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
WrapInFunction(op);
@@ -32,7 +32,7 @@ TEST_F(HlslUnaryOpTest, AddressOf) {
}
TEST_F(HlslUnaryOpTest, Complement) {
- Global("expr", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.u32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
WrapInFunction(op);
@@ -44,7 +44,7 @@ TEST_F(HlslUnaryOpTest, Complement) {
}
TEST_F(HlslUnaryOpTest, Indirection) {
- Global("G", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("G", ty.f32(), ast::StorageClass::kPrivate);
auto* p =
Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
@@ -58,7 +58,7 @@ TEST_F(HlslUnaryOpTest, Indirection) {
}
TEST_F(HlslUnaryOpTest, Not) {
- Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.bool_(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
WrapInFunction(op);
@@ -70,7 +70,7 @@ TEST_F(HlslUnaryOpTest, Not) {
}
TEST_F(HlslUnaryOpTest, Negation) {
- Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.i32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
WrapInFunction(op);
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index 5ed85f3a747..db8fb771b0b 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -16,6 +16,8 @@
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/writer/hlsl/test_helper.h"
+using namespace tint::number_suffixes; // NOLINT
+
namespace tint::writer::hlsl {
namespace {
@@ -36,7 +38,7 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement) {
EXPECT_EQ(gen.result(), " float a = 0.0f;\n");
}
-TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Let) {
auto* var = Let("a", ty.f32(), Construct(ty.f32()));
auto* stmt = Decl(var);
WrapInFunction(stmt);
@@ -49,6 +51,300 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
EXPECT_EQ(gen.result(), " const float a = 0.0f;\n");
}
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+ auto* var = Const("a", ty.f32(), Construct(ty.f32()));
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), ""); // Not a mistake - 'const' is inlined
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AInt) {
+ auto* C = Const("C", nullptr, Expr(1_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AFloat) {
+ auto* C = Const("C", nullptr, Expr(1._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_i32) {
+ auto* C = Const("C", nullptr, Expr(1_i));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_u32) {
+ auto* C = Const("C", nullptr, Expr(1_u));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const uint l = 1u;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f32) {
+ auto* C = Const("C", nullptr, Expr(1_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, Expr(1_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float16_t l = float16_t(1.0h);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AInt) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const int3 l = int3(1, 2, 3);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f32) {
+ auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const vector<float16_t, 3> l = vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+ auto* C =
+ Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+ auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const matrix<float16_t, 2, 3> l = matrix<float16_t, 2, 3>(vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)), vector<float16_t, 3>(float16_t(4.0h), float16_t(5.0h), float16_t(6.0h)));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_f32) {
+ auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const float l[3] = {1.0f, 2.0f, 3.0f};
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+ auto* C = Const("C", nullptr,
+ Construct(ty.array(ty.vec2<bool>(), 3_u), //
+ vec2<bool>(true, false), //
+ vec2<bool>(false, true), //
+ vec2<bool>(true, true)));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(void f() {
+ const bool2 l[3] = {bool2(true, false), bool2(false, true), (true).xx};
+}
+)");
+}
+
TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
auto* var = Var("a", ty.array<f32, 5>());
@@ -63,7 +359,7 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
}
TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
WrapInFunction(Expr("a"));
@@ -75,21 +371,23 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
EXPECT_THAT(gen.result(), HasSubstr(" static float a = 0.0f;\n"));
}
-TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_Private) {
- Global("initializer", ty.f32(), ast::StorageClass::kPrivate);
- Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_F32) {
+ auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
- WrapInFunction(Expr("a"));
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr(R"(float a = initializer;
-)"));
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), R"(float3 a = (0.0f).xxx;
+)");
}
-TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec) {
- auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("a", ty.vec3<f16>(), ast::StorageClass::kNone, vec3<f16>());
auto* stmt = Decl(var);
WrapInFunction(stmt);
@@ -97,11 +395,11 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initialize
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
- EXPECT_EQ(gen.result(), R"(float3 a = (0.0f).xxx;
+ EXPECT_EQ(gen.result(), R"(vector<float16_t, 3> a = (float16_t(0.0h)).xxx;
)");
}
-TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat) {
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_F32) {
auto* var = Var("a", ty.mat2x3<f32>(), ast::StorageClass::kNone, mat2x3<f32>());
auto* stmt = Decl(var);
@@ -115,5 +413,22 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initialize
)");
}
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("a", ty.mat2x3<f16>(), ast::StorageClass::kNone, mat2x3<f16>());
+
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(
+ gen.result(),
+ R"(matrix<float16_t, 2, 3> a = matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+)");
+}
+
} // namespace
} // namespace tint::writer::hlsl
diff --git a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
index 826a545b68c..9e8be017a5d 100644
--- a/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
@@ -27,10 +27,10 @@ namespace {
using HlslGeneratorImplTest_WorkgroupVar = TestHelper;
TEST_F(HlslGeneratorImplTest_WorkgroupVar, Basic) {
- Global("wg", ty.f32(), ast::StorageClass::kWorkgroup);
+ GlobalVar("wg", ty.f32(), ast::StorageClass::kWorkgroup);
- Func("main", {}, ty.void_(), {Assign("wg", 1.2_f)},
- {
+ Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -43,10 +43,10 @@ TEST_F(HlslGeneratorImplTest_WorkgroupVar, Basic) {
TEST_F(HlslGeneratorImplTest_WorkgroupVar, Aliased) {
auto* alias = Alias("F32", ty.f32());
- Global("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
+ GlobalVar("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
- Func("main", {}, ty.void_(), {Assign("wg", 1.2_f)},
- {
+ Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.cc
index 3228e867d32..602ec710bdb 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.cc
@@ -39,6 +39,7 @@
#include "src/tint/sem/constant.h"
#include "src/tint/sem/depth_multisampled_texture.h"
#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/f16.h"
#include "src/tint/sem/f32.h"
#include "src/tint/sem/function.h"
#include "src/tint/sem/i32.h"
@@ -64,14 +65,13 @@
#include "src/tint/transform/expand_compound_assignment.h"
#include "src/tint/transform/manager.h"
#include "src/tint/transform/module_scope_var_to_entry_point_param.h"
-#include "src/tint/transform/promote_initializers_to_const_var.h"
+#include "src/tint/transform/promote_initializers_to_let.h"
#include "src/tint/transform/promote_side_effects_to_decl.h"
#include "src/tint/transform/remove_phonies.h"
#include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/unshadow.h"
#include "src/tint/transform/unwind_discard_functions.h"
#include "src/tint/transform/vectorize_scalar_matrix_constructors.h"
-#include "src/tint/transform/wrap_arrays_in_structs.h"
#include "src/tint/transform/zero_init_workgroup_memory.h"
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
@@ -98,6 +98,20 @@ void PrintF32(std::ostream& out, float value) {
}
}
+void PrintF16(std::ostream& out, float value) {
+ // Note: Currently inf and nan should not be constructable, but this is implemented for the day
+ // we support them.
+ if (std::isinf(value)) {
+ // HUGE_VALH evaluates to +infinity.
+ out << (value >= 0 ? "HUGE_VALH" : "-HUGE_VALH");
+ } else if (std::isnan(value)) {
+ // There is no NaN expr for half in MSL, "NAN" is of float type.
+ out << "NAN";
+ } else {
+ out << FloatToString(value) << "h";
+ }
+}
+
void PrintI32(std::ostream& out, int32_t value) {
// MSL (and C++) parse `-2147483648` as a `long` because it parses unary minus and `2147483648`
// as separate tokens, and the latter doesn't fit into an (32-bit) `int`.
@@ -152,6 +166,8 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
{ // Builtin polyfills
transform::BuiltinPolyfill::Builtins polyfills;
+ polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
+ polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.first_leading_bit = true;
polyfills.first_trailing_bit = true;
@@ -205,10 +221,9 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
manager.Add<transform::ExpandCompoundAssignment>();
manager.Add<transform::PromoteSideEffectsToDecl>();
manager.Add<transform::UnwindDiscardFunctions>();
- manager.Add<transform::PromoteInitializersToConstVar>();
+ manager.Add<transform::PromoteInitializersToLet>();
manager.Add<transform::VectorizeScalarMatrixConstructors>();
- manager.Add<transform::WrapArraysInStructs>();
manager.Add<transform::RemovePhonies>();
manager.Add<transform::SimplifyPointers>();
// ArrayLengthFromUniform must come after SimplifyPointers, as
@@ -253,16 +268,12 @@ bool GeneratorImpl::Generate() {
[&](const ast::Alias*) {
return true; // folded away by the writer
},
- [&](const ast::Variable* var) {
- if (var->is_const) {
- TINT_DEFER(line());
- return EmitProgramConstVariable(var);
- }
- // These are pushed into the entry point by sanitizer transforms.
- TINT_ICE(Writer, diagnostics_)
- << "module-scope variables should have been handled by the MSL "
- "sanitizer";
- return false;
+ [&](const ast::Const*) {
+ return true; // Constants are embedded at their use
+ },
+ [&](const ast::Override* override) {
+ TINT_DEFER(line());
+ return EmitOverride(override);
},
[&](const ast::Function* func) {
TINT_DEFER(line());
@@ -275,6 +286,9 @@ bool GeneratorImpl::Generate() {
// Do nothing for enabling extension in MSL
return true;
},
+ [&](const ast::StaticAssert*) {
+ return true; // Not emitted
+ },
[&](Default) {
// These are pushed into the entry point by sanitizer transforms.
TINT_ICE(Writer, diagnostics_) << "unhandled type: " << decl->TypeInfo().name;
@@ -734,16 +748,36 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
const sem::TypeConstructor* ctor) {
auto* type = ctor->ReturnType();
- if (type->IsAnyOf<sem::Array, sem::Struct>()) {
- out << "{";
- } else {
- if (!EmitType(out, type, "")) {
- return false;
- }
- out << "(";
+ const char* terminator = ")";
+ TINT_DEFER(out << terminator);
+
+ bool ok = Switch(
+ type,
+ [&](const sem::Array*) {
+ if (!EmitType(out, type, "")) {
+ return false;
+ }
+ out << "{";
+ terminator = "}";
+ return true;
+ },
+ [&](const sem::Struct*) {
+ out << "{";
+ terminator = "}";
+ return true;
+ },
+ [&](Default) {
+ if (!EmitType(out, type, "")) {
+ return false;
+ }
+ out << "(";
+ return true;
+ });
+ if (!ok) {
+ return false;
}
- int i = 0;
+ size_t i = 0;
for (auto* arg : call->Arguments()) {
if (i > 0) {
out << ", ";
@@ -763,11 +797,6 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
i++;
}
- if (type->IsAnyOf<sem::Array, sem::Struct>()) {
- out << "}";
- } else {
- out << ")";
- }
return true;
}
@@ -778,7 +807,7 @@ bool GeneratorImpl::EmitAtomicCall(std::ostream& out,
out << name;
{
ScopedParen sp(out);
- for (size_t i = 0; i < expr->args.size(); i++) {
+ for (size_t i = 0; i < expr->args.Length(); i++) {
auto* arg = expr->args[i];
if (i > 0) {
out << ", ";
@@ -909,7 +938,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
// Returns the argument with the given usage
auto arg = [&](Usage usage) {
int idx = signature.IndexOf(usage);
- return (idx >= 0) ? arguments[idx] : nullptr;
+ return (idx >= 0) ? arguments[static_cast<size_t>(idx)] : nullptr;
};
auto* texture = arg(Usage::kTexture)->Declaration();
@@ -1190,7 +1219,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
break; // Other texture dimensions don't have an offset
}
}
- auto c = component->ConstantValue().Element<AInt>(0);
+ auto c = component->ConstantValue()->As<AInt>();
switch (c.value) {
case 0:
out << "component::x";
@@ -1279,9 +1308,9 @@ bool GeneratorImpl::EmitModfCall(std::ostream& out,
return false;
}
- line(b) << "float" << width << " whole;";
- line(b) << "float" << width << " fract = modf(" << in << ", whole);";
- line(b) << "return {fract, whole};";
+ line(b) << StructName(builtin->ReturnType()->As<sem::Struct>()) << " result;";
+ line(b) << "result.fract = modf(" << in << ", result.whole);";
+ line(b) << "return result;";
return true;
});
}
@@ -1305,9 +1334,9 @@ bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
return false;
}
- line(b) << "int" << width << " exp;";
- line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
- line(b) << "return {sig, exp};";
+ line(b) << StructName(builtin->ReturnType()->As<sem::Struct>()) << " result;";
+ line(b) << "result.sig = frexp(" << in << ", result.exp);";
+ line(b) << "return result;";
return true;
});
}
@@ -1338,9 +1367,12 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
std::string out = "";
switch (builtin->Type()) {
case sem::BuiltinType::kAcos:
+ case sem::BuiltinType::kAcosh:
case sem::BuiltinType::kAll:
case sem::BuiltinType::kAny:
case sem::BuiltinType::kAsin:
+ case sem::BuiltinType::kAsinh:
+ case sem::BuiltinType::kAtanh:
case sem::BuiltinType::kAtan:
case sem::BuiltinType::kAtan2:
case sem::BuiltinType::kCeil:
@@ -1452,7 +1484,6 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
out += "rint";
break;
case sem::BuiltinType::kSmoothstep:
- case sem::BuiltinType::kSmoothStep:
out += "smoothstep";
break;
case sem::BuiltinType::kInverseSqrt:
@@ -1496,7 +1527,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
return false;
}
out << ":";
- if (selector == stmt->selectors.back()) {
+ if (selector == stmt->selectors.Back()) {
out << " {";
}
}
@@ -1522,7 +1553,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
}
bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
- if (!emit_continuing_()) {
+ if (!emit_continuing_ || !emit_continuing_()) {
return false;
}
@@ -1538,10 +1569,8 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
return true;
},
[&](const sem::F16*) {
- // Placeholder for emitting f16 zero value
- diagnostics_.add_error(diag::System::Writer,
- "Type f16 is not completely implemented yet");
- return false;
+ out << "0.0h";
+ return true;
},
[&](const sem::F32*) {
out << "0.0f";
@@ -1565,10 +1594,9 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
ScopedParen sp(out);
return EmitZeroValue(out, mat->type());
},
- [&](const sem::Array* arr) {
- out << "{";
- TINT_DEFER(out << "}");
- return EmitZeroValue(out, arr->ElemType());
+ [&](const sem::Array*) {
+ out << "{}";
+ return true;
},
[&](const sem::Struct*) {
out << "{}";
@@ -1582,88 +1610,118 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
});
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant& constant) {
- auto emit_bool = [&](size_t element_idx) {
- out << (constant.Element<AInt>(element_idx) ? "true" : "false");
- return true;
- };
- auto emit_f32 = [&](size_t element_idx) {
- PrintF32(out, static_cast<float>(constant.Element<AFloat>(element_idx)));
- return true;
- };
- auto emit_i32 = [&](size_t element_idx) {
- PrintI32(out, static_cast<int32_t>(constant.Element<AInt>(element_idx).value));
- return true;
- };
- auto emit_u32 = [&](size_t element_idx) {
- out << constant.Element<AInt>(element_idx).value << "u";
- return true;
- };
- auto emit_vector = [&](const sem::Vector* vec_ty, size_t start, size_t end) {
- if (!EmitType(out, vec_ty, "")) {
- return false;
- }
+bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constant) {
+ return Switch(
+ constant->Type(), //
+ [&](const sem::Bool*) {
+ out << (constant->As<AInt>() ? "true" : "false");
+ return true;
+ },
+ [&](const sem::F32*) {
+ PrintF32(out, constant->As<float>());
+ return true;
+ },
+ [&](const sem::F16*) {
+ PrintF16(out, constant->As<float>());
+ return true;
+ },
+ [&](const sem::I32*) {
+ PrintI32(out, constant->As<int32_t>());
+ return true;
+ },
+ [&](const sem::U32*) {
+ out << constant->As<AInt>() << "u";
+ return true;
+ },
+ [&](const sem::Vector* v) {
+ if (!EmitType(out, v, "")) {
+ return false;
+ }
- ScopedParen sp(out);
+ ScopedParen sp(out);
- auto emit_els = [&](auto emit_el) {
- if (constant.AllEqual(start, end)) {
- return emit_el(start);
+ if (constant->AllEqual()) {
+ if (!EmitConstant(out, constant->Index(0))) {
+ return false;
+ }
+ return true;
}
- for (size_t i = start; i < end; i++) {
- if (i > start) {
+
+ for (size_t i = 0; i < v->Width(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!emit_el(i)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
return true;
- };
- return Switch(
- vec_ty->type(), //
- [&](const sem::Bool*) { return emit_els(emit_bool); }, //
- [&](const sem::F32*) { return emit_els(emit_f32); }, //
- [&](const sem::I32*) { return emit_els(emit_i32); }, //
- [&](const sem::U32*) { return emit_els(emit_u32); }, //
- [&](Default) {
- diagnostics_.add_error(diag::System::Writer,
- "unhandled constant vector element type: " +
- builder_.FriendlyName(vec_ty->type()));
+ },
+ [&](const sem::Matrix* m) {
+ if (!EmitType(out, m, "")) {
return false;
- });
- };
- auto emit_matrix = [&](const sem::Matrix* m) {
- if (!EmitType(out, constant.Type(), "")) {
- return false;
- }
+ }
- ScopedParen sp(out);
+ ScopedParen sp(out);
- for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
- if (column_idx > 0) {
- out << ", ";
+ for (size_t i = 0; i < m->columns(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
}
- size_t start = m->rows() * column_idx;
- size_t end = m->rows() * (column_idx + 1);
- if (!emit_vector(m->ColumnType(), start, end)) {
+ return true;
+ },
+ [&](const sem::Array* a) {
+ if (!EmitType(out, a, "")) {
return false;
}
- }
- return true;
- };
- return Switch(
- constant.Type(), //
- [&](const sem::Bool*) { return emit_bool(0); }, //
- [&](const sem::F32*) { return emit_f32(0); }, //
- [&](const sem::I32*) { return emit_i32(0); }, //
- [&](const sem::U32*) { return emit_u32(0); }, //
- [&](const sem::Vector* v) { return emit_vector(v, 0, constant.ElementCount()); }, //
- [&](const sem::Matrix* m) { return emit_matrix(m); }, //
+
+ out << "{";
+ TINT_DEFER(out << "}");
+
+ if (constant->AllZero()) {
+ return true;
+ }
+
+ for (size_t i = 0; i < a->Count(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+ [&](const sem::Struct* s) {
+ out << program_->Symbols().NameFor(s->Name()) << "{";
+ TINT_DEFER(out << "}");
+
+ if (constant->AllZero()) {
+ return true;
+ }
+
+ auto& members = s->Members();
+ for (size_t i = 0; i < members.size(); i++) {
+ if (i > 0) {
+ out << ", ";
+ }
+ out << "." << program_->Symbols().NameFor(members[i]->Name()) << "=";
+ if (!EmitConstant(out, constant->Index(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ },
[&](Default) {
diagnostics_.add_error(
diag::System::Writer,
- "unhandled constant type: " + builder_.FriendlyName(constant.Type()));
+ "unhandled constant type: " + builder_.FriendlyName(constant->Type()));
return false;
});
}
@@ -1676,7 +1734,11 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
return true;
},
[&](const ast::FloatLiteralExpression* l) {
- PrintF32(out, static_cast<float>(l->value));
+ if (l->suffix == ast::FloatLiteralExpression::Suffix::kH) {
+ PrintF16(out, static_cast<float>(l->value));
+ } else {
+ PrintF32(out, static_cast<float>(l->value));
+ }
return true;
},
[&](const ast::IntLiteralExpression* i) {
@@ -1702,8 +1764,14 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().Get(expr)) {
- if (auto constant = sem->ConstantValue()) {
- return EmitConstant(out, constant);
+ if (auto* user = sem->As<sem::VariableUser>();
+ !user || !user->Variable()->Declaration()->Is<ast::Let>()) {
+ // Disable constant inlining if the constant expression is from a 'let' declaration.
+ // TODO(crbug.com/tint/1580): Once 'const' is implemented, 'let' will no longer resolve
+ // to a shader-creation time constant value, and this can be removed.
+ if (auto constant = sem->ConstantValue()) {
+ return EmitConstant(out, constant);
+ }
}
}
return Switch(
@@ -1779,8 +1847,8 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
if (!EmitType(out, type, param_name)) {
return false;
}
- // Parameter name is output as part of the type for arrays and pointers.
- if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
+ // Parameter name is output as part of the type for pointers.
+ if (!type->Is<sem::Pointer>()) {
out << " " << program_->Symbols().NameFor(v->symbol);
}
}
@@ -1797,33 +1865,33 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
return true;
}
-std::string GeneratorImpl::builtin_to_attribute(ast::Builtin builtin) const {
+std::string GeneratorImpl::builtin_to_attribute(ast::BuiltinValue builtin) const {
switch (builtin) {
- case ast::Builtin::kPosition:
+ case ast::BuiltinValue::kPosition:
return "position";
- case ast::Builtin::kVertexIndex:
+ case ast::BuiltinValue::kVertexIndex:
return "vertex_id";
- case ast::Builtin::kInstanceIndex:
+ case ast::BuiltinValue::kInstanceIndex:
return "instance_id";
- case ast::Builtin::kFrontFacing:
+ case ast::BuiltinValue::kFrontFacing:
return "front_facing";
- case ast::Builtin::kFragDepth:
+ case ast::BuiltinValue::kFragDepth:
return "depth(any)";
- case ast::Builtin::kLocalInvocationId:
+ case ast::BuiltinValue::kLocalInvocationId:
return "thread_position_in_threadgroup";
- case ast::Builtin::kLocalInvocationIndex:
+ case ast::BuiltinValue::kLocalInvocationIndex:
return "thread_index_in_threadgroup";
- case ast::Builtin::kGlobalInvocationId:
+ case ast::BuiltinValue::kGlobalInvocationId:
return "thread_position_in_grid";
- case ast::Builtin::kWorkgroupId:
+ case ast::BuiltinValue::kWorkgroupId:
return "threadgroup_position_in_grid";
- case ast::Builtin::kNumWorkgroups:
+ case ast::BuiltinValue::kNumWorkgroups:
return "threadgroups_per_grid";
- case ast::Builtin::kSampleIndex:
+ case ast::BuiltinValue::kSampleIndex:
return "sample_id";
- case ast::Builtin::kSampleMask:
+ case ast::BuiltinValue::kSampleMask:
return "sample_mask";
- case ast::Builtin::kPointSize:
+ case ast::BuiltinValue::kPointSize:
return "point_size";
default:
break;
@@ -1867,8 +1935,8 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
// Returns the binding index of a variable, requiring that the group
// attribute have a value of zero.
const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max();
- auto get_binding_index = [&](const ast::Variable* var) -> uint32_t {
- auto bp = var->BindingPoint();
+ auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t {
+ auto bp = param->BindingPoint();
if (bp.group == nullptr || bp.binding == nullptr) {
TINT_ICE(Writer, diagnostics_)
<< "missing binding attributes for entry point parameter";
@@ -1891,46 +1959,46 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
// Emit entry point parameters.
bool first = true;
- for (auto* var : func->params) {
+ for (auto* param : func->params) {
if (!first) {
out << ", ";
}
first = false;
- auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
+ auto* type = program_->Sem().Get(param)->Type()->UnwrapRef();
- auto param_name = program_->Symbols().NameFor(var->symbol);
+ auto param_name = program_->Symbols().NameFor(param->symbol);
if (!EmitType(out, type, param_name)) {
return false;
}
- // Parameter name is output as part of the type for arrays and pointers.
- if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
+ // Parameter name is output as part of the type for pointers.
+ if (!type->Is<sem::Pointer>()) {
out << " " << param_name;
}
if (type->Is<sem::Struct>()) {
out << " [[stage_in]]";
} else if (type->is_handle()) {
- uint32_t binding = get_binding_index(var);
+ uint32_t binding = get_binding_index(param);
if (binding == kInvalidBindingIndex) {
return false;
}
- if (var->type->Is<ast::Sampler>()) {
+ if (param->type->Is<ast::Sampler>()) {
out << " [[sampler(" << binding << ")]]";
- } else if (var->type->Is<ast::Texture>()) {
+ } else if (param->type->Is<ast::Texture>()) {
out << " [[texture(" << binding << ")]]";
} else {
TINT_ICE(Writer, diagnostics_) << "invalid handle type entry point parameter";
return false;
}
- } else if (auto* ptr = var->type->As<ast::Pointer>()) {
+ } else if (auto* ptr = param->type->As<ast::Pointer>()) {
auto sc = ptr->storage_class;
if (sc == ast::StorageClass::kWorkgroup) {
auto& allocations = workgroup_allocations_[func_name];
out << " [[threadgroup(" << allocations.size() << ")]]";
allocations.push_back(program_->Sem().Get(ptr->type)->Size());
} else if (sc == ast::StorageClass::kStorage || sc == ast::StorageClass::kUniform) {
- uint32_t binding = get_binding_index(var);
+ uint32_t binding = get_binding_index(param);
if (binding == kInvalidBindingIndex) {
return false;
}
@@ -1941,7 +2009,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
return false;
}
} else {
- auto& attrs = var->attributes;
+ auto& attrs = param->attributes;
bool builtin_found = false;
for (auto* attr : attrs) {
auto* builtin = attr->As<ast::BuiltinAttribute>();
@@ -1974,7 +2042,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
}
if (!Is<ast::ReturnStatement>(func->body->Last())) {
- ast::ReturnStatement ret(ProgramID{}, Source{});
+ ast::ReturnStatement ret(ProgramID{}, ast::NodeID{}, Source{});
if (!EmitStatement(&ret)) {
return false;
}
@@ -2125,6 +2193,56 @@ bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
return true;
}
+bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
+ TextBuffer cond_pre;
+ std::stringstream cond_buf;
+
+ {
+ auto* cond = stmt->condition;
+ TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
+ if (!EmitExpression(cond_buf, cond)) {
+ return false;
+ }
+ }
+
+ auto emit_continuing = [&]() { return true; };
+ TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+
+ // If the while has a multi-statement conditional, then we cannot emit this
+ // as a regular while in MSL. Instead we need to generate a `while(true)` loop.
+ bool emit_as_loop = cond_pre.lines.size() > 0;
+ if (emit_as_loop) {
+ line() << "while (true) {";
+ increment_indent();
+ TINT_DEFER({
+ decrement_indent();
+ line() << "}";
+ });
+
+ current_buffer_->Append(cond_pre);
+ line() << "if (!(" << cond_buf.str() << ")) { break; }";
+ if (!EmitStatements(stmt->body->statements)) {
+ return false;
+ }
+ } else {
+ // While can be generated.
+ {
+ auto out = line();
+ out << "while";
+ {
+ ScopedParen sp(out);
+ out << cond_buf.str();
+ }
+ out << " {";
+ }
+ if (!EmitStatementsWithIndent(stmt->body->statements)) {
+ return false;
+ }
+ line() << "}";
+ }
+ return true;
+}
+
bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
// TODO(dsinclair): Verify this is correct when the discard semantics are
// defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
@@ -2153,7 +2271,7 @@ bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
return false;
}
} else {
- if (!EmitStatementsWithIndent({stmt->else_statement})) {
+ if (!EmitStatementsWithIndent(utils::Vector{stmt->else_statement})) {
return false;
}
}
@@ -2189,7 +2307,7 @@ bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
// For multi-element swizzles, we need to cast to a regular vector type
// first. Note that we do not currently allow assignments to swizzles, so
// the casting which will convert the l-value to r-value is fine.
- if (swizzle->Indices().size() == 1) {
+ if (swizzle->Indices().Length() == 1) {
if (!write_lhs()) {
return false;
}
@@ -2281,6 +2399,9 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
[&](const ast::ForLoopStatement* l) { //
return EmitForLoop(l);
},
+ [&](const ast::WhileStatement* l) { //
+ return EmitWhile(l);
+ },
[&](const ast::ReturnStatement* r) { //
return EmitReturn(r);
},
@@ -2288,8 +2409,21 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
return EmitSwitch(s);
},
[&](const ast::VariableDeclStatement* v) { //
- auto* var = program_->Sem().Get(v->variable);
- return EmitVariable(var);
+ return Switch(
+ v->variable, //
+ [&](const ast::Var* var) { return EmitVar(var); },
+ [&](const ast::Let* let) { return EmitLet(let); },
+ [&](const ast::Const*) {
+ return true; // Constants are embedded at their use
+ },
+ [&](Default) { //
+ TINT_ICE(Writer, diagnostics_)
+ << "unknown statement type: " << stmt->TypeInfo().name;
+ return false;
+ });
+ },
+ [&](const ast::StaticAssert*) {
+ return true; // Not emitted
},
[&](Default) {
diagnostics_.add_error(diag::System::Writer,
@@ -2298,7 +2432,7 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
});
}
-bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatements(utils::VectorRef<const ast::Statement*> stmts) {
for (auto* s : stmts) {
if (!EmitStatement(s)) {
return false;
@@ -2307,7 +2441,7 @@ bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
return true;
}
-bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts) {
ScopedIndent si(this);
return EmitStatements(stmts);
}
@@ -2359,29 +2493,12 @@ bool GeneratorImpl::EmitType(std::ostream& out,
<< "unhandled atomic type " << atomic->Type()->FriendlyName(builder_.Symbols());
return false;
},
- [&](const sem::Array* ary) {
- const sem::Type* base_type = ary;
- std::vector<uint32_t> sizes;
- while (auto* arr = base_type->As<sem::Array>()) {
- if (arr->IsRuntimeSized()) {
- sizes.push_back(1);
- } else {
- sizes.push_back(arr->Count());
- }
- base_type = arr->ElemType();
- }
- if (!EmitType(out, base_type, "")) {
+ [&](const sem::Array* arr) {
+ out << ArrayType() << "<";
+ if (!EmitType(out, arr->ElemType(), "")) {
return false;
}
- if (!name.empty()) {
- out << " " << name;
- if (name_printed) {
- *name_printed = true;
- }
- }
- for (uint32_t size : sizes) {
- out << "[" << size << "]";
- }
+ out << ", " << (arr->IsRuntimeSized() ? 1u : arr->Count()) << ">";
return true;
},
[&](const sem::Bool*) {
@@ -2389,9 +2506,8 @@ bool GeneratorImpl::EmitType(std::ostream& out,
return true;
},
[&](const sem::F16*) {
- diagnostics_.add_error(diag::System::Writer,
- "Type f16 is not completely implemented yet");
- return false;
+ out << "half";
+ return true;
},
[&](const sem::F32*) {
out << "float";
@@ -2416,22 +2532,12 @@ bool GeneratorImpl::EmitType(std::ostream& out,
return false;
}
out << " ";
- if (ptr->StoreType()->Is<sem::Array>()) {
- std::string inner = "(*" + name + ")";
- if (!EmitType(out, ptr->StoreType(), inner)) {
- return false;
- }
- if (name_printed) {
- *name_printed = true;
- }
- } else {
- if (!EmitType(out, ptr->StoreType(), "")) {
- return false;
- }
- out << "* " << name;
- if (name_printed) {
- *name_printed = true;
- }
+ if (!EmitType(out, ptr->StoreType(), "")) {
+ return false;
+ }
+ out << "* " << name;
+ if (name_printed) {
+ *name_printed = true;
}
return true;
},
@@ -2647,7 +2753,7 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
auto out = line(b);
add_byte_offset_comment(out, msl_offset);
- out << "int8_t " << name << "[" << size << "];";
+ out << ArrayType() << "<int8_t, " << size << "> " << name << ";";
};
b->IncrementIndent();
@@ -2685,11 +2791,7 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
auto* ty = mem->Type();
- // Array member name will be output with the type
- if (!ty->Is<sem::Array>()) {
- out << " " << mem_name;
- }
-
+ out << " " << mem_name;
// Emit attributes
if (auto* decl = mem->Declaration()) {
for (auto* attr : decl->attributes) {
@@ -2866,19 +2968,13 @@ bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression*
return true;
}
-bool GeneratorImpl::EmitVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
-
- for (auto* attr : decl->attributes) {
- if (!attr->Is<ast::InternalAttribute>()) {
- TINT_ICE(Writer, diagnostics_) << "unexpected variable attribute";
- return false;
- }
- }
+bool GeneratorImpl::EmitVar(const ast::Var* var) {
+ auto* sem = program_->Sem().Get(var);
+ auto* type = sem->Type()->UnwrapRef();
auto out = line();
- switch (var->StorageClass()) {
+ switch (sem->StorageClass()) {
case ast::StorageClass::kFunction:
case ast::StorageClass::kHandle:
case ast::StorageClass::kNone:
@@ -2894,28 +2990,23 @@ bool GeneratorImpl::EmitVariable(const sem::Variable* var) {
return false;
}
- auto* type = var->Type()->UnwrapRef();
-
- std::string name = program_->Symbols().NameFor(decl->symbol);
- if (decl->is_const) {
- name = "const " + name;
- }
+ std::string name = program_->Symbols().NameFor(var->symbol);
if (!EmitType(out, type, name)) {
return false;
}
- // Variable name is output as part of the type for arrays and pointers.
- if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
+ // Variable name is output as part of the type for pointers.
+ if (!type->Is<sem::Pointer>()) {
out << " " << name;
}
- if (decl->constructor != nullptr) {
+ if (var->constructor != nullptr) {
out << " = ";
- if (!EmitExpression(out, decl->constructor)) {
+ if (!EmitExpression(out, var->constructor)) {
return false;
}
- } else if (var->StorageClass() == ast::StorageClass::kPrivate ||
- var->StorageClass() == ast::StorageClass::kFunction ||
- var->StorageClass() == ast::StorageClass::kNone) {
+ } else if (sem->StorageClass() == ast::StorageClass::kPrivate ||
+ sem->StorageClass() == ast::StorageClass::kFunction ||
+ sem->StorageClass() == ast::StorageClass::kNone) {
out << " = ";
if (!EmitZeroValue(out, type)) {
return false;
@@ -2926,38 +3017,59 @@ bool GeneratorImpl::EmitVariable(const sem::Variable* var) {
return true;
}
-bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
- for (auto* d : var->attributes) {
- if (!d->Is<ast::IdAttribute>()) {
- diagnostics_.add_error(diag::System::Writer, "Decorated const values not valid");
+bool GeneratorImpl::EmitLet(const ast::Let* let) {
+ auto* sem = program_->Sem().Get(let);
+ auto* type = sem->Type();
+
+ auto out = line();
+
+ switch (sem->StorageClass()) {
+ case ast::StorageClass::kFunction:
+ case ast::StorageClass::kHandle:
+ case ast::StorageClass::kNone:
+ break;
+ case ast::StorageClass::kPrivate:
+ out << "thread ";
+ break;
+ case ast::StorageClass::kWorkgroup:
+ out << "threadgroup ";
+ break;
+ default:
+ TINT_ICE(Writer, diagnostics_) << "unhandled variable storage class";
return false;
- }
}
- if (!var->is_const) {
- diagnostics_.add_error(diag::System::Writer, "Expected a const value");
+
+ std::string name = "const " + program_->Symbols().NameFor(let->symbol);
+ if (!EmitType(out, type, name)) {
+ return false;
+ }
+
+ // Variable name is output as part of the type for pointers.
+ if (!type->Is<sem::Pointer>()) {
+ out << " " << name;
+ }
+
+ out << " = ";
+ if (!EmitExpression(out, let->constructor)) {
return false;
}
+ out << ";";
+
+ return true;
+}
+
+bool GeneratorImpl::EmitOverride(const ast::Override* override) {
+ auto* global = program_->Sem().Get<sem::GlobalVariable>(override);
+ auto* type = global->Type();
auto out = line();
out << "constant ";
- auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
- if (!EmitType(out, type, program_->Symbols().NameFor(var->symbol))) {
+ if (!EmitType(out, type, program_->Symbols().NameFor(override->symbol))) {
return false;
}
- if (!type->Is<sem::Array>()) {
- out << " " << program_->Symbols().NameFor(var->symbol);
- }
+ out << " " << program_->Symbols().NameFor(override->symbol);
- auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
- if (global && global->IsOverridable()) {
- out << " [[function_constant(" << global->ConstantId() << ")]]";
- } else if (var->constructor != nullptr) {
- out << " = ";
- if (!EmitExpression(out, var->constructor)) {
- return false;
- }
- }
- out << ";";
+ out << " [[function_constant(" << global->OverrideId().value << ")]];";
return true;
}
@@ -2977,20 +3089,25 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(const sem::
[&](const sem::F32*) {
return SizeAndAlign{4, 4};
},
+ [&](const sem::F16*) {
+ return SizeAndAlign{2, 2};
+ },
[&](const sem::Vector* vec) {
auto num_els = vec->Width();
auto* el_ty = vec->type();
- if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
+ SizeAndAlign el_size_align = MslPackedTypeSizeAndAlign(el_ty);
+ if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32, sem::F16>()) {
// Use a packed_vec type for 3-element vectors only.
if (num_els == 3) {
// https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
// 2.2.3 Packed Vector Types
- return SizeAndAlign{num_els * 4, 4};
+ return SizeAndAlign{num_els * el_size_align.size, el_size_align.align};
} else {
// https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
// 2.2 Vector Data Types
- return SizeAndAlign{num_els * 4, num_els * 4};
+ // Vector data types are aligned to their size.
+ return SizeAndAlign{num_els * el_size_align.size, num_els * el_size_align.size};
}
}
TINT_UNREACHABLE(Writer, diagnostics_)
@@ -3004,8 +3121,9 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(const sem::
auto cols = mat->columns();
auto rows = mat->rows();
auto* el_ty = mat->type();
- if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
- static constexpr SizeAndAlign table[] = {
+ // Metal only support half and float matrix.
+ if (el_ty->IsAnyOf<sem::F32, sem::F16>()) {
+ static constexpr SizeAndAlign table_f32[] = {
/* float2x2 */ {16, 8},
/* float2x3 */ {32, 16},
/* float2x4 */ {32, 16},
@@ -3016,8 +3134,23 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(const sem::
/* float4x3 */ {64, 16},
/* float4x4 */ {64, 16},
};
+ static constexpr SizeAndAlign table_f16[] = {
+ /* half2x2 */ {8, 4},
+ /* half2x3 */ {16, 8},
+ /* half2x4 */ {16, 8},
+ /* half3x2 */ {12, 4},
+ /* half3x3 */ {24, 8},
+ /* half3x4 */ {24, 8},
+ /* half4x2 */ {16, 4},
+ /* half4x3 */ {32, 8},
+ /* half4x4 */ {32, 8},
+ };
if (cols >= 2 && cols <= 4 && rows >= 2 && rows <= 4) {
- return table[(3 * (cols - 2)) + (rows - 2)];
+ if (el_ty->Is<sem::F32>()) {
+ return table_f32[(3 * (cols - 2)) + (rows - 2)];
+ } else {
+ return table_f16[(3 * (cols - 2)) + (rows - 2)];
+ }
}
}
@@ -3028,8 +3161,8 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(const sem::
[&](const sem::Array* arr) {
if (!arr->IsStrideImplicit()) {
- TINT_ICE(Writer, diagnostics_) << "arrays with explicit strides not "
- "exist past the SPIR-V reader";
+ TINT_ICE(Writer, diagnostics_)
+ << "arrays with explicit strides should not exist past the SPIR-V reader";
return SizeAndAlign{};
}
auto num_els = std::max<uint32_t>(arr->Count(), 1);
@@ -3116,4 +3249,25 @@ bool GeneratorImpl::CallBuiltinHelper(std::ostream& out,
return true;
}
+const std::string& GeneratorImpl::ArrayType() {
+ if (array_template_name_.empty()) {
+ array_template_name_ = UniqueIdentifier("tint_array");
+ auto* buf = &helpers_;
+ line(buf) << "template<typename T, size_t N>";
+ line(buf) << "struct " << array_template_name_ << " {";
+ line(buf) << " const constant T& operator[](size_t i) const constant"
+ << " { return elements[i]; }";
+ for (auto* space : {"device", "thread", "threadgroup"}) {
+ line(buf) << " " << space << " T& operator[](size_t i) " << space
+ << " { return elements[i]; }";
+ line(buf) << " const " << space << " T& operator[](size_t i) const " << space
+ << " { return elements[i]; }";
+ }
+ line(buf) << " T elements[N];";
+ line(buf) << "};";
+ line(buf);
+ }
+ return array_template_name_;
+}
+
} // namespace tint::writer::msl
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.h b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.h
index be98a86b431..72ee42c376c 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.h
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl.h
@@ -256,7 +256,7 @@ class GeneratorImpl : public TextGenerator {
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const sem::Constant& constant);
+ bool EmitConstant(std::ostream& out, const sem::Constant* constant);
/// Handles a literal
/// @param out the output of the expression stream
/// @param lit the literal to emit
@@ -270,6 +270,10 @@ class GeneratorImpl : public TextGenerator {
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
bool EmitForLoop(const ast::ForLoopStatement* stmt);
+ /// Handles a while statement
+ /// @param stmt the statement to emit
+ /// @returns true if the statement was emitted
+ bool EmitWhile(const ast::WhileStatement* stmt);
/// Handles a member accessor expression
/// @param out the output of the expression stream
/// @param expr the member accessor expression
@@ -290,11 +294,11 @@ class GeneratorImpl : public TextGenerator {
/// Emits a list of statements
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
- bool EmitStatements(const ast::StatementList& stmts);
+ bool EmitStatements(utils::VectorRef<const ast::Statement*> stmts);
/// Emits a list of statements with an indentation
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
- bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+ bool EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts);
/// Handles generating a switch statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
@@ -344,14 +348,18 @@ class GeneratorImpl : public TextGenerator {
/// @param expr the expression to emit
/// @returns true if the expression was emitted
bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
- /// Handles generating a variable
+ /// Handles generating a 'var' declaration
/// @param var the variable to generate
/// @returns true if the variable was emitted
- bool EmitVariable(const sem::Variable* var);
- /// Handles generating a program scope constant variable
- /// @param var the variable to emit
+ bool EmitVar(const ast::Var* var);
+ /// Handles generating a function-scope 'let' declaration
+ /// @param let the variable to generate
+ /// @returns true if the variable was emitted
+ bool EmitLet(const ast::Let* let);
+ /// Handles generating a module-scope 'override' declaration
+ /// @param override the 'override' to emit
/// @returns true if the variable was emitted
- bool EmitProgramConstVariable(const ast::Variable* var);
+ bool EmitOverride(const ast::Override* override);
/// Emits the zero value for the given type
/// @param out the output of the expression stream
/// @param type the type to emit the value for
@@ -366,7 +374,7 @@ class GeneratorImpl : public TextGenerator {
/// Converts a builtin to an attribute name
/// @param builtin the builtin to convert
/// @returns the string name of the builtin or blank on error
- std::string builtin_to_attribute(ast::Builtin builtin) const;
+ std::string builtin_to_attribute(ast::BuiltinValue builtin) const;
/// Converts interpolation attributes to an MSL attribute
/// @param type the interpolation type
@@ -401,6 +409,10 @@ class GeneratorImpl : public TextGenerator {
const sem::Builtin* builtin,
F&& build);
+ /// @returns the name of the templated tint_array helper type, generating it if this is the
+ /// first call.
+ const std::string& ArrayType();
+
TextBuffer helpers_; // Helper functions emitted at the top of the output
/// @returns the MSL packed type size and alignment in bytes for the given
@@ -415,13 +427,17 @@ class GeneratorImpl : public TextGenerator {
utils::UnorderedKeyWrapper<std::tuple<ast::StorageClass, const sem::Struct*>>;
std::unordered_map<ACEWKeyType, std::string> atomicCompareExchangeWeak_;
- /// Unique name of the 'TINT_INVARIANT' preprocessor define. Non-empty only if
- /// an invariant attribute has been generated.
+ /// Unique name of the 'TINT_INVARIANT' preprocessor define.
+ /// Non-empty only if an invariant attribute has been generated.
std::string invariant_define_name_;
/// True if matrix-packed_vector operator overloads have been generated.
bool matrix_packed_vector_overloads_ = false;
+ /// Unique name of the tint_array<T, N> template.
+ /// Non-empty only if the template has been generated.
+ std::string array_template_name_;
+
/// A map from entry point name to a list of dynamic workgroup allocations.
/// Each entry in the vector is the size of the workgroup allocation that
/// should be created for that index.
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_array_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_array_accessor_test.cc
index 7475b6768a4..bfa76dc4e80 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_array_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_array_accessor_test.cc
@@ -34,7 +34,7 @@ TEST_F(MslGeneratorImplTest, IndexAccessor) {
}
TEST_F(MslGeneratorImplTest, IndexAccessor_OfDref) {
- Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+ GlobalVar("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
auto* p = Let("p", nullptr, AddressOf("ary"));
auto* expr = IndexAccessor(Deref("p"), 5_i);
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_binary_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_binary_test.cc
index 02daae25503..cfc8c7efa70 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_binary_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_binary_test.cc
@@ -158,6 +158,21 @@ TEST_F(MslBinaryTest, ModF32) {
EXPECT_EQ(out.str(), "fmod(left, right)");
}
+TEST_F(MslBinaryTest, ModF16) {
+ Enable(ast::Extension::kF16);
+
+ auto* left = Var("left", ty.f16());
+ auto* right = Var("right", ty.f16());
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left), Expr(right));
+ WrapInFunction(left, right, expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "fmod(left, right)");
+}
+
TEST_F(MslBinaryTest, ModVec3F32) {
auto* left = Var("left", ty.vec3<f32>());
auto* right = Var("right", ty.vec3<f32>());
@@ -171,6 +186,21 @@ TEST_F(MslBinaryTest, ModVec3F32) {
EXPECT_EQ(out.str(), "fmod(left, right)");
}
+TEST_F(MslBinaryTest, ModVec3F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* left = Var("left", ty.vec3<f16>());
+ auto* right = Var("right", ty.vec3<f16>());
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left), Expr(right));
+ WrapInFunction(left, right, expr);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+ EXPECT_EQ(out.str(), "fmod(left, right)");
+}
+
TEST_F(MslBinaryTest, BoolAnd) {
auto* left = Var("left", nullptr, Expr(true));
auto* right = Var("right", nullptr, Expr(false));
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_test.cc
index 0c1f2a4bd2d..9f756912375 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -25,36 +25,40 @@ using BuiltinType = sem::BuiltinType;
using MslGeneratorImplTest = TestHelper;
-enum class ParamType {
+enum class CallParamType {
kF32,
kU32,
kBool,
+ kF16,
};
struct BuiltinData {
BuiltinType builtin;
- ParamType type;
+ CallParamType type;
const char* msl_name;
};
inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
out << data.msl_name << "<";
switch (data.type) {
- case ParamType::kF32:
+ case CallParamType::kF32:
out << "f32";
break;
- case ParamType::kU32:
+ case CallParamType::kU32:
out << "u32";
break;
- case ParamType::kBool:
+ case CallParamType::kBool:
out << "bool";
break;
+ case CallParamType::kF16:
+ out << "f16";
+ break;
}
out << ">";
return out;
}
const ast::CallExpression* GenerateCall(BuiltinType builtin,
- ParamType type,
+ CallParamType type,
ProgramBuilder* builder) {
std::string name;
std::ostringstream str(name);
@@ -92,32 +96,53 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
case BuiltinType::kTanh:
case BuiltinType::kTrunc:
case BuiltinType::kSign:
- return builder->Call(str.str(), "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2");
+ } else {
+ return builder->Call(str.str(), "f2");
+ }
case BuiltinType::kLdexp:
- return builder->Call(str.str(), "f2", "i2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "i2");
+ } else {
+ return builder->Call(str.str(), "f2", "i2");
+ }
case BuiltinType::kAtan2:
case BuiltinType::kDot:
case BuiltinType::kDistance:
case BuiltinType::kPow:
case BuiltinType::kReflect:
case BuiltinType::kStep:
- return builder->Call(str.str(), "f2", "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2");
+ }
case BuiltinType::kStorageBarrier:
return builder->Call(str.str());
case BuiltinType::kCross:
- return builder->Call(str.str(), "f3", "f3");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h3", "h3");
+ } else {
+ return builder->Call(str.str(), "f3", "f3");
+ }
case BuiltinType::kFma:
case BuiltinType::kMix:
case BuiltinType::kFaceForward:
case BuiltinType::kSmoothstep:
- case BuiltinType::kSmoothStep:
- return builder->Call(str.str(), "f2", "f2", "f2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "h2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2", "f2");
+ }
case BuiltinType::kAll:
case BuiltinType::kAny:
return builder->Call(str.str(), "b2");
case BuiltinType::kAbs:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2");
} else {
return builder->Call(str.str(), "u2");
}
@@ -132,21 +157,33 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
return builder->Call(str.str(), "u2", "u2", "u1", "u1");
case BuiltinType::kMax:
case BuiltinType::kMin:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2", "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2");
} else {
return builder->Call(str.str(), "u2", "u2");
}
case BuiltinType::kClamp:
- if (type == ParamType::kF32) {
+ if (type == CallParamType::kF32) {
return builder->Call(str.str(), "f2", "f2", "f2");
+ } else if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "h2");
} else {
return builder->Call(str.str(), "u2", "u2", "u2");
}
case BuiltinType::kSelect:
- return builder->Call(str.str(), "f2", "f2", "b2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "h2", "h2", "b2");
+ } else {
+ return builder->Call(str.str(), "f2", "f2", "b2");
+ }
case BuiltinType::kDeterminant:
- return builder->Call(str.str(), "m2x2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "hm2x2");
+ } else {
+ return builder->Call(str.str(), "m2x2");
+ }
case BuiltinType::kPack2x16snorm:
case BuiltinType::kPack2x16unorm:
return builder->Call(str.str(), "f2");
@@ -161,7 +198,11 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
case BuiltinType::kWorkgroupBarrier:
return builder->Call(str.str());
case BuiltinType::kTranspose:
- return builder->Call(str.str(), "m3x2");
+ if (type == CallParamType::kF16) {
+ return builder->Call(str.str(), "hm3x2");
+ } else {
+ return builder->Call(str.str(), "m3x2");
+ }
default:
break;
}
@@ -172,20 +213,29 @@ using MslBuiltinTest = TestParamHelper<BuiltinData>;
TEST_P(MslBuiltinTest, Emit) {
auto param = GetParam();
- Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
- Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- Global("f4", ty.vec4<f32>(), ast::StorageClass::kPrivate);
- Global("u1", ty.u32(), ast::StorageClass::kPrivate);
- Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
- Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
- Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
- Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
- Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
+ if (param.type == CallParamType::kF16) {
+ Enable(ast::Extension::kF16);
+
+ GlobalVar("h2", ty.vec2<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("h3", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("hm2x2", ty.mat2x2<f16>(), ast::StorageClass::kPrivate);
+ GlobalVar("hm3x2", ty.mat3x2<f16>(), ast::StorageClass::kPrivate);
+ }
+
+ GlobalVar("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("f4", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("u1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
+ GlobalVar("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+ GlobalVar("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
auto* call = GenerateCall(param.builtin, param.type, this);
ASSERT_NE(nullptr, call) << "Unhandled builtin";
- Func("func", {}, ty.void_(), {Ignore(call)},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(call)},
+ utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build();
@@ -202,81 +252,126 @@ INSTANTIATE_TEST_SUITE_P(
MslGeneratorImplTest,
MslBuiltinTest,
testing::Values(
- BuiltinData{BuiltinType::kAbs, ParamType::kF32, "fabs"},
- BuiltinData{BuiltinType::kAbs, ParamType::kU32, "abs"},
- BuiltinData{BuiltinType::kAcos, ParamType::kF32, "acos"},
- BuiltinData{BuiltinType::kAll, ParamType::kBool, "all"},
- BuiltinData{BuiltinType::kAny, ParamType::kBool, "any"},
- BuiltinData{BuiltinType::kAsin, ParamType::kF32, "asin"},
- BuiltinData{BuiltinType::kAtan, ParamType::kF32, "atan"},
- BuiltinData{BuiltinType::kAtan2, ParamType::kF32, "atan2"},
- BuiltinData{BuiltinType::kCeil, ParamType::kF32, "ceil"},
- BuiltinData{BuiltinType::kClamp, ParamType::kF32, "clamp"},
- BuiltinData{BuiltinType::kClamp, ParamType::kU32, "clamp"},
- BuiltinData{BuiltinType::kCos, ParamType::kF32, "cos"},
- BuiltinData{BuiltinType::kCosh, ParamType::kF32, "cosh"},
- BuiltinData{BuiltinType::kCountLeadingZeros, ParamType::kU32, "clz"},
- BuiltinData{BuiltinType::kCountOneBits, ParamType::kU32, "popcount"},
- BuiltinData{BuiltinType::kCountTrailingZeros, ParamType::kU32, "ctz"},
- BuiltinData{BuiltinType::kCross, ParamType::kF32, "cross"},
- BuiltinData{BuiltinType::kDeterminant, ParamType::kF32, "determinant"},
- BuiltinData{BuiltinType::kDistance, ParamType::kF32, "distance"},
- BuiltinData{BuiltinType::kDot, ParamType::kF32, "dot"},
- BuiltinData{BuiltinType::kDpdx, ParamType::kF32, "dfdx"},
- BuiltinData{BuiltinType::kDpdxCoarse, ParamType::kF32, "dfdx"},
- BuiltinData{BuiltinType::kDpdxFine, ParamType::kF32, "dfdx"},
- BuiltinData{BuiltinType::kDpdy, ParamType::kF32, "dfdy"},
- BuiltinData{BuiltinType::kDpdyCoarse, ParamType::kF32, "dfdy"},
- BuiltinData{BuiltinType::kDpdyFine, ParamType::kF32, "dfdy"},
- BuiltinData{BuiltinType::kExp, ParamType::kF32, "exp"},
- BuiltinData{BuiltinType::kExp2, ParamType::kF32, "exp2"},
- BuiltinData{BuiltinType::kExtractBits, ParamType::kU32, "extract_bits"},
- BuiltinData{BuiltinType::kFaceForward, ParamType::kF32, "faceforward"},
- BuiltinData{BuiltinType::kFloor, ParamType::kF32, "floor"},
- BuiltinData{BuiltinType::kFma, ParamType::kF32, "fma"},
- BuiltinData{BuiltinType::kFract, ParamType::kF32, "fract"},
- BuiltinData{BuiltinType::kFwidth, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
- BuiltinData{BuiltinType::kInsertBits, ParamType::kU32, "insert_bits"},
- BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "rsqrt"},
- BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
- BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
- BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
- BuiltinData{BuiltinType::kLog2, ParamType::kF32, "log2"},
- BuiltinData{BuiltinType::kMax, ParamType::kF32, "fmax"},
- BuiltinData{BuiltinType::kMax, ParamType::kU32, "max"},
- BuiltinData{BuiltinType::kMin, ParamType::kF32, "fmin"},
- BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
- BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
- BuiltinData{BuiltinType::kPack4x8snorm, ParamType::kF32, "pack_float_to_snorm4x8"},
- BuiltinData{BuiltinType::kPack4x8unorm, ParamType::kF32, "pack_float_to_unorm4x8"},
- BuiltinData{BuiltinType::kPack2x16snorm, ParamType::kF32, "pack_float_to_snorm2x16"},
- BuiltinData{BuiltinType::kPack2x16unorm, ParamType::kF32, "pack_float_to_unorm2x16"},
- BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
- BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
- BuiltinData{BuiltinType::kReverseBits, ParamType::kU32, "reverse_bits"},
- BuiltinData{BuiltinType::kRound, ParamType::kU32, "rint"},
- BuiltinData{BuiltinType::kSelect, ParamType::kF32, "select"},
- BuiltinData{BuiltinType::kSign, ParamType::kF32, "sign"},
- BuiltinData{BuiltinType::kSin, ParamType::kF32, "sin"},
- BuiltinData{BuiltinType::kSinh, ParamType::kF32, "sinh"},
- BuiltinData{BuiltinType::kSmoothstep, ParamType::kF32, "smoothstep"},
- BuiltinData{BuiltinType::kSmoothStep, ParamType::kF32, "smoothstep"},
- BuiltinData{BuiltinType::kSqrt, ParamType::kF32, "sqrt"},
- BuiltinData{BuiltinType::kStep, ParamType::kF32, "step"},
- BuiltinData{BuiltinType::kTan, ParamType::kF32, "tan"},
- BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
- BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
- BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"},
- BuiltinData{BuiltinType::kUnpack4x8snorm, ParamType::kU32, "unpack_snorm4x8_to_float"},
- BuiltinData{BuiltinType::kUnpack4x8unorm, ParamType::kU32, "unpack_unorm4x8_to_float"},
- BuiltinData{BuiltinType::kUnpack2x16snorm, ParamType::kU32, "unpack_snorm2x16_to_float"},
- BuiltinData{BuiltinType::kUnpack2x16unorm, ParamType::kU32, "unpack_unorm2x16_to_float"}));
+ /* Logical built-in */
+ BuiltinData{BuiltinType::kAll, CallParamType::kBool, "all"},
+ BuiltinData{BuiltinType::kAny, CallParamType::kBool, "any"},
+ BuiltinData{BuiltinType::kSelect, CallParamType::kF32, "select"},
+ /* Float built-in */
+ BuiltinData{BuiltinType::kAbs, CallParamType::kF32, "fabs"},
+ BuiltinData{BuiltinType::kAbs, CallParamType::kF16, "fabs"},
+ BuiltinData{BuiltinType::kAcos, CallParamType::kF32, "acos"},
+ BuiltinData{BuiltinType::kAcos, CallParamType::kF16, "acos"},
+ BuiltinData{BuiltinType::kAsin, CallParamType::kF32, "asin"},
+ BuiltinData{BuiltinType::kAsin, CallParamType::kF16, "asin"},
+ BuiltinData{BuiltinType::kAtan, CallParamType::kF32, "atan"},
+ BuiltinData{BuiltinType::kAtan, CallParamType::kF16, "atan"},
+ BuiltinData{BuiltinType::kAtan2, CallParamType::kF32, "atan2"},
+ BuiltinData{BuiltinType::kAtan2, CallParamType::kF16, "atan2"},
+ BuiltinData{BuiltinType::kCeil, CallParamType::kF32, "ceil"},
+ BuiltinData{BuiltinType::kCeil, CallParamType::kF16, "ceil"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kF32, "clamp"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kF16, "clamp"},
+ BuiltinData{BuiltinType::kCos, CallParamType::kF32, "cos"},
+ BuiltinData{BuiltinType::kCos, CallParamType::kF16, "cos"},
+ BuiltinData{BuiltinType::kCosh, CallParamType::kF32, "cosh"},
+ BuiltinData{BuiltinType::kCosh, CallParamType::kF16, "cosh"},
+ BuiltinData{BuiltinType::kCross, CallParamType::kF32, "cross"},
+ BuiltinData{BuiltinType::kCross, CallParamType::kF16, "cross"},
+ BuiltinData{BuiltinType::kDistance, CallParamType::kF32, "distance"},
+ BuiltinData{BuiltinType::kDistance, CallParamType::kF16, "distance"},
+ BuiltinData{BuiltinType::kExp, CallParamType::kF32, "exp"},
+ BuiltinData{BuiltinType::kExp, CallParamType::kF16, "exp"},
+ BuiltinData{BuiltinType::kExp2, CallParamType::kF32, "exp2"},
+ BuiltinData{BuiltinType::kExp2, CallParamType::kF16, "exp2"},
+ BuiltinData{BuiltinType::kFaceForward, CallParamType::kF32, "faceforward"},
+ BuiltinData{BuiltinType::kFaceForward, CallParamType::kF16, "faceforward"},
+ BuiltinData{BuiltinType::kFloor, CallParamType::kF32, "floor"},
+ BuiltinData{BuiltinType::kFloor, CallParamType::kF16, "floor"},
+ BuiltinData{BuiltinType::kFma, CallParamType::kF32, "fma"},
+ BuiltinData{BuiltinType::kFma, CallParamType::kF16, "fma"},
+ BuiltinData{BuiltinType::kFract, CallParamType::kF32, "fract"},
+ BuiltinData{BuiltinType::kFract, CallParamType::kF16, "fract"},
+ BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+ BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+ BuiltinData{BuiltinType::kLdexp, CallParamType::kF32, "ldexp"},
+ BuiltinData{BuiltinType::kLdexp, CallParamType::kF16, "ldexp"},
+ BuiltinData{BuiltinType::kLength, CallParamType::kF32, "length"},
+ BuiltinData{BuiltinType::kLength, CallParamType::kF16, "length"},
+ BuiltinData{BuiltinType::kLog, CallParamType::kF32, "log"},
+ BuiltinData{BuiltinType::kLog, CallParamType::kF16, "log"},
+ BuiltinData{BuiltinType::kLog2, CallParamType::kF32, "log2"},
+ BuiltinData{BuiltinType::kLog2, CallParamType::kF16, "log2"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kF32, "fmax"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kF16, "fmax"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kF32, "fmin"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kF16, "fmin"},
+ BuiltinData{BuiltinType::kNormalize, CallParamType::kF32, "normalize"},
+ BuiltinData{BuiltinType::kNormalize, CallParamType::kF16, "normalize"},
+ BuiltinData{BuiltinType::kPow, CallParamType::kF32, "pow"},
+ BuiltinData{BuiltinType::kPow, CallParamType::kF16, "pow"},
+ BuiltinData{BuiltinType::kReflect, CallParamType::kF32, "reflect"},
+ BuiltinData{BuiltinType::kReflect, CallParamType::kF16, "reflect"},
+ BuiltinData{BuiltinType::kSign, CallParamType::kF32, "sign"},
+ BuiltinData{BuiltinType::kSign, CallParamType::kF16, "sign"},
+ BuiltinData{BuiltinType::kSin, CallParamType::kF32, "sin"},
+ BuiltinData{BuiltinType::kSin, CallParamType::kF16, "sin"},
+ BuiltinData{BuiltinType::kSinh, CallParamType::kF32, "sinh"},
+ BuiltinData{BuiltinType::kSinh, CallParamType::kF16, "sinh"},
+ BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF32, "smoothstep"},
+ BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF16, "smoothstep"},
+ BuiltinData{BuiltinType::kSqrt, CallParamType::kF32, "sqrt"},
+ BuiltinData{BuiltinType::kSqrt, CallParamType::kF16, "sqrt"},
+ BuiltinData{BuiltinType::kStep, CallParamType::kF32, "step"},
+ BuiltinData{BuiltinType::kStep, CallParamType::kF16, "step"},
+ BuiltinData{BuiltinType::kTan, CallParamType::kF32, "tan"},
+ BuiltinData{BuiltinType::kTan, CallParamType::kF16, "tan"},
+ BuiltinData{BuiltinType::kTanh, CallParamType::kF32, "tanh"},
+ BuiltinData{BuiltinType::kTanh, CallParamType::kF16, "tanh"},
+ BuiltinData{BuiltinType::kTrunc, CallParamType::kF32, "trunc"},
+ BuiltinData{BuiltinType::kTrunc, CallParamType::kF16, "trunc"},
+ /* Integer built-in */
+ BuiltinData{BuiltinType::kAbs, CallParamType::kU32, "abs"},
+ BuiltinData{BuiltinType::kClamp, CallParamType::kU32, "clamp"},
+ BuiltinData{BuiltinType::kCountLeadingZeros, CallParamType::kU32, "clz"},
+ BuiltinData{BuiltinType::kCountOneBits, CallParamType::kU32, "popcount"},
+ BuiltinData{BuiltinType::kCountTrailingZeros, CallParamType::kU32, "ctz"},
+ BuiltinData{BuiltinType::kExtractBits, CallParamType::kU32, "extract_bits"},
+ BuiltinData{BuiltinType::kInsertBits, CallParamType::kU32, "insert_bits"},
+ BuiltinData{BuiltinType::kMax, CallParamType::kU32, "max"},
+ BuiltinData{BuiltinType::kMin, CallParamType::kU32, "min"},
+ BuiltinData{BuiltinType::kReverseBits, CallParamType::kU32, "reverse_bits"},
+ BuiltinData{BuiltinType::kRound, CallParamType::kU32, "rint"},
+ /* Matrix built-in */
+ BuiltinData{BuiltinType::kDeterminant, CallParamType::kF32, "determinant"},
+ BuiltinData{BuiltinType::kTranspose, CallParamType::kF32, "transpose"},
+ /* Vector built-in */
+ BuiltinData{BuiltinType::kDot, CallParamType::kF32, "dot"},
+ /* Derivate built-in */
+ BuiltinData{BuiltinType::kDpdx, CallParamType::kF32, "dfdx"},
+ BuiltinData{BuiltinType::kDpdxCoarse, CallParamType::kF32, "dfdx"},
+ BuiltinData{BuiltinType::kDpdxFine, CallParamType::kF32, "dfdx"},
+ BuiltinData{BuiltinType::kDpdy, CallParamType::kF32, "dfdy"},
+ BuiltinData{BuiltinType::kDpdyCoarse, CallParamType::kF32, "dfdy"},
+ BuiltinData{BuiltinType::kDpdyFine, CallParamType::kF32, "dfdy"},
+ BuiltinData{BuiltinType::kFwidth, CallParamType::kF32, "fwidth"},
+ BuiltinData{BuiltinType::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+ BuiltinData{BuiltinType::kFwidthFine, CallParamType::kF32, "fwidth"},
+ /* Data packing builtin */
+ BuiltinData{BuiltinType::kPack4x8snorm, CallParamType::kF32, "pack_float_to_snorm4x8"},
+ BuiltinData{BuiltinType::kPack4x8unorm, CallParamType::kF32, "pack_float_to_unorm4x8"},
+ BuiltinData{BuiltinType::kPack2x16snorm, CallParamType::kF32, "pack_float_to_snorm2x16"},
+ BuiltinData{BuiltinType::kPack2x16unorm, CallParamType::kF32, "pack_float_to_unorm2x16"},
+ /* Data unpacking builtin */
+ BuiltinData{BuiltinType::kUnpack4x8snorm, CallParamType::kU32, "unpack_snorm4x8_to_float"},
+ BuiltinData{BuiltinType::kUnpack4x8unorm, CallParamType::kU32, "unpack_unorm4x8_to_float"},
+ BuiltinData{BuiltinType::kUnpack2x16snorm, CallParamType::kU32,
+ "unpack_snorm2x16_to_float"},
+ BuiltinData{BuiltinType::kUnpack2x16unorm, CallParamType::kU32,
+ "unpack_unorm2x16_to_float"}));
TEST_F(MslGeneratorImplTest, Builtin_Call) {
- Global("param1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
- Global("param2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("param1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
auto* call = Call("dot", "param1", "param2");
WrapInFunction(CallStmt(call));
@@ -310,12 +405,252 @@ TEST_F(MslGeneratorImplTest, WorkgroupBarrier) {
EXPECT_EQ(out.str(), "threadgroup_barrier(mem_flags::mem_threadgroup)");
}
-TEST_F(MslGeneratorImplTest, Degrees_Scalar) {
+TEST_F(MslGeneratorImplTest, Modf_Scalar_f32) {
+ auto* call = Call("modf", 1_f);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct modf_result {
+ float fract;
+ float whole;
+};
+modf_result tint_modf(float param_0) {
+ modf_result result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+kernel void test_function() {
+ tint_modf(1.0f);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Modf_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", 1_h);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct modf_result_f16 {
+ half fract;
+ half whole;
+};
+modf_result_f16 tint_modf(half param_0) {
+ modf_result_f16 result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+kernel void test_function() {
+ tint_modf(1.0h);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Modf_Vector_f32) {
+ auto* call = Call("modf", vec3<f32>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct modf_result_vec3 {
+ float3 fract;
+ float3 whole;
+};
+modf_result_vec3 tint_modf(float3 param_0) {
+ modf_result_vec3 result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+kernel void test_function() {
+ tint_modf(float3(0.0f));
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Modf_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("modf", vec3<f16>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct modf_result_vec3_f16 {
+ half3 fract;
+ half3 whole;
+};
+modf_result_vec3_f16 tint_modf(half3 param_0) {
+ modf_result_vec3_f16 result;
+ result.fract = modf(param_0, result.whole);
+ return result;
+}
+
+kernel void test_function() {
+ tint_modf(half3(0.0h));
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Frexp_Scalar_f32) {
+ auto* call = Call("frexp", 1_f);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct frexp_result {
+ float sig;
+ int exp;
+};
+frexp_result tint_frexp(float param_0) {
+ frexp_result result;
+ result.sig = frexp(param_0, result.exp);
+ return result;
+}
+
+kernel void test_function() {
+ tint_frexp(1.0f);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Frexp_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", 1_h);
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct frexp_result_f16 {
+ half sig;
+ int exp;
+};
+frexp_result_f16 tint_frexp(half param_0) {
+ frexp_result_f16 result;
+ result.sig = frexp(param_0, result.exp);
+ return result;
+}
+
+kernel void test_function() {
+ tint_frexp(1.0h);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Frexp_Vector_f32) {
+ auto* call = Call("frexp", vec3<f32>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct frexp_result_vec3 {
+ float3 sig;
+ int3 exp;
+};
+frexp_result_vec3 tint_frexp(float3 param_0) {
+ frexp_result_vec3 result;
+ result.sig = frexp(param_0, result.exp);
+ return result;
+}
+
+kernel void test_function() {
+ tint_frexp(float3(0.0f));
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Frexp_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* call = Call("frexp", vec3<f16>());
+ WrapInFunction(CallStmt(call));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+struct frexp_result_vec3_f16 {
+ half3 sig;
+ int3 exp;
+};
+frexp_result_vec3_f16 tint_frexp(half3 param_0) {
+ frexp_result_vec3_f16 result;
+ result.sig = frexp(param_0, result.exp);
+ return result;
+}
+
+kernel void test_function() {
+ tint_frexp(half3(0.0h));
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Degrees_Scalar_f32) {
auto* val = Var("val", ty.f32());
auto* call = Call("degrees", val);
WrapInFunction(val, call);
- GeneratorImpl& gen = Build();
+ GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
@@ -335,12 +670,12 @@ kernel void test_function() {
)");
}
-TEST_F(MslGeneratorImplTest, Degrees_Vector) {
+TEST_F(MslGeneratorImplTest, Degrees_Vector_f32) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("degrees", val);
WrapInFunction(val, call);
- GeneratorImpl& gen = Build();
+ GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
@@ -360,12 +695,66 @@ kernel void test_function() {
)");
}
-TEST_F(MslGeneratorImplTest, Radians_Scalar) {
+TEST_F(MslGeneratorImplTest, Degrees_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.f16());
+ auto* call = Call("degrees", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+half tint_degrees(half param_0) {
+ return param_0 * 57.295779513082322865;
+}
+
+kernel void test_function() {
+ half val = 0.0h;
+ half const tint_symbol = tint_degrees(val);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Degrees_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.vec3<f16>());
+ auto* call = Call("degrees", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+half3 tint_degrees(half3 param_0) {
+ return param_0 * 57.295779513082322865;
+}
+
+kernel void test_function() {
+ half3 val = 0.0h;
+ half3 const tint_symbol = tint_degrees(val);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Radians_Scalar_f32) {
auto* val = Var("val", ty.f32());
auto* call = Call("radians", val);
WrapInFunction(val, call);
- GeneratorImpl& gen = Build();
+ GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
@@ -385,12 +774,12 @@ kernel void test_function() {
)");
}
-TEST_F(MslGeneratorImplTest, Radians_Vector) {
+TEST_F(MslGeneratorImplTest, Radians_Vector_f32) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("radians", val);
WrapInFunction(val, call);
- GeneratorImpl& gen = Build();
+ GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
@@ -410,9 +799,63 @@ kernel void test_function() {
)");
}
+TEST_F(MslGeneratorImplTest, Radians_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.f16());
+ auto* call = Call("radians", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+half tint_radians(half param_0) {
+ return param_0 * 0.017453292519943295474;
+}
+
+kernel void test_function() {
+ half val = 0.0h;
+ half const tint_symbol = tint_radians(val);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Radians_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* val = Var("val", ty.vec3<f16>());
+ auto* call = Call("radians", val);
+ WrapInFunction(val, call);
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+half3 tint_radians(half3 param_0) {
+ return param_0 * 0.017453292519943295474;
+}
+
+kernel void test_function() {
+ half3 val = 0.0h;
+ half3 const tint_symbol = tint_radians(val);
+ return;
+}
+
+)");
+}
+
TEST_F(MslGeneratorImplTest, Pack2x16Float) {
auto* call = Call("pack2x16float", "p1");
- Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -424,7 +867,7 @@ TEST_F(MslGeneratorImplTest, Pack2x16Float) {
TEST_F(MslGeneratorImplTest, Unpack2x16Float) {
auto* call = Call("unpack2x16float", "p1");
- Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("p1", ty.u32(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(call));
GeneratorImpl& gen = Build();
@@ -435,7 +878,7 @@ TEST_F(MslGeneratorImplTest, Unpack2x16Float) {
}
TEST_F(MslGeneratorImplTest, DotI32) {
- Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+ GlobalVar("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
WrapInFunction(CallStmt(Call("dot", "v", "v")));
GeneratorImpl& gen = SanitizeAndBuild();
@@ -459,11 +902,11 @@ kernel void test_function() {
}
TEST_F(MslGeneratorImplTest, Ignore) {
- Func("f", {Param("a", ty.i32()), Param("b", ty.i32()), Param("c", ty.i32())}, ty.i32(),
- {Return(Mul(Add("a", "b"), "c"))});
+ Func("f", utils::Vector{Param("a", ty.i32()), Param("b", ty.i32()), Param("c", ty.i32())},
+ ty.i32(), utils::Vector{Return(Mul(Add("a", "b"), "c"))});
- Func("func", {}, ty.void_(), {CallStmt(Call("f", 1_i, 2_i, 3_i))},
- {
+ Func("func", utils::Empty, ty.void_(), utils::Vector{CallStmt(Call("f", 1_i, 2_i, 3_i))},
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_texture_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
index 20813fabc6f..dd4a92f3710 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
@@ -280,7 +280,8 @@ TEST_P(MslGeneratorBuiltinTextureTest, Call) {
auto* call = Call(Expr(param.function), param.args(this));
auto* stmt = CallStmt(call);
- Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_call_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_call_test.cc
index 93c9b830364..1011ebd7251 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_call_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_call_test.cc
@@ -23,7 +23,7 @@ namespace {
using MslGeneratorImplTest = TestHelper;
TEST_F(MslGeneratorImplTest, EmitExpression_Call_WithoutParams) {
- Func("my_func", {}, ty.f32(), {Return(1.23_f)});
+ Func("my_func", utils::Empty, ty.f32(), utils::Vector{Return(1.23_f)});
auto* call = Call("my_func");
WrapInFunction(call);
@@ -37,13 +37,16 @@ TEST_F(MslGeneratorImplTest, EmitExpression_Call_WithoutParams) {
TEST_F(MslGeneratorImplTest, EmitExpression_Call_WithParams) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.f32(), {Return(1.23_f)});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.f32(),
+ utils::Vector{
+ Return(1.23_f),
+ });
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = Call("my_func", "param1", "param2");
WrapInFunction(call);
@@ -57,13 +60,13 @@ TEST_F(MslGeneratorImplTest, EmitExpression_Call_WithParams) {
TEST_F(MslGeneratorImplTest, EmitStatement_Call) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.void_(), ast::StatementList{}, ast::AttributeList{});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.void_(), utils::Empty, utils::Empty);
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = Call("my_func", "param1", "param2");
auto* stmt = CallStmt(call);
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_case_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_case_test.cc
index 8fc1bc95b5b..250d67d9c70 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_case_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_case_test.cc
@@ -69,7 +69,13 @@ TEST_F(MslGeneratorImplTest, Emit_Case_WithFallthrough) {
}
TEST_F(MslGeneratorImplTest, Emit_Case_MultipleSelectors) {
- auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+ auto* s = Switch(1_i,
+ Case(
+ utils::Vector{
+ Expr(5_i),
+ Expr(6_i),
+ },
+ Block(create<ast::BreakStatement>())),
DefaultCase());
WrapInFunction(s);
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_constructor_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_constructor_test.cc
index 2fa85f01cee..b0bbbea697e 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_constructor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_constructor_test.cc
@@ -61,6 +61,18 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Float) {
EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
}
+TEST_F(MslGeneratorImplTest, EmitConstructor_F16) {
+ Enable(ast::Extension::kF16);
+
+ // Use a number close to 1<<16 but whose decimal representation ends in 0.
+ WrapInFunction(Expr(f16((1 << 15) - 8)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("32752.0h"));
+}
+
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Float) {
WrapInFunction(Construct<f32>(-1.2e-5_f));
@@ -70,6 +82,17 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Float) {
EXPECT_THAT(gen.result(), HasSubstr("-0.000012f"));
}
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(Construct<f16>(-1.2e-3_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("-0.00119972229h"));
+}
+
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Bool) {
WrapInFunction(Construct<bool>(true));
@@ -97,7 +120,7 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Uint) {
EXPECT_THAT(gen.result(), HasSubstr("12345u"));
}
-TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec) {
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_F32) {
WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
GeneratorImpl& gen = Build();
@@ -106,7 +129,18 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec) {
EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
}
-TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_Empty) {
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("half3(1.0h, 2.0h, 3.0h)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_Empty_F32) {
WrapInFunction(vec3<f32>());
GeneratorImpl& gen = Build();
@@ -115,26 +149,230 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_Empty) {
EXPECT_THAT(gen.result(), HasSubstr("float3(0.0f)"));
}
-TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat) {
- WrapInFunction(Construct(ty.mat2x3<f32>(), vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_Empty_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>());
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("half3(0.0h)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_SingleScalar_F32_Literal) {
+ WrapInFunction(vec3<f32>(2_f));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("float3(2.0f)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_SingleScalar_F16_Literal) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(2_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("half3(2.0h)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_SingleScalar_F32_Var) {
+ auto* var = Var("v", nullptr, Expr(2_f));
+ auto* cast = vec3<f32>(var);
+ WrapInFunction(var, cast);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr(R"(float v = 2.0f;
+ float3 const tint_symbol = float3(v);)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_SingleScalar_F16_Var) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("v", nullptr, Expr(2_h));
+ auto* cast = vec3<f16>(var);
+ WrapInFunction(var, cast);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr(R"(half v = 2.0h;
+ half3 const tint_symbol = half3(v);)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_SingleScalar_Bool) {
+ WrapInFunction(vec3<bool>(true));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("bool3(true)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_SingleScalar_Int) {
+ WrapInFunction(vec3<i32>(2_i));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("int3(2)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_SingleScalar_UInt) {
+ WrapInFunction(vec3<u32>(2_u));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("uint3(2u)"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_F32) {
+ WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.Generate()) << gen.error();
- // A matrix of type T with n columns and m rows can also be constructed from
- // n vectors of type T with m components.
EXPECT_THAT(gen.result(),
HasSubstr("float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
}
-TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Empty) {
- WrapInFunction(mat4x4<f32>());
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("half2x3(half3(1.0h, 2.0h, 3.0h), half3(3.0h, 4.0h, 5.0h))"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Complex_F32) {
+ // mat4x4<f32>(
+ // vec4<f32>(2.0f, 3.0f, 4.0f, 8.0f),
+ // vec4<f32>(),
+ // vec4<f32>(7.0f),
+ // vec4<f32>(vec4<f32>(42.0f, 21.0f, 6.0f, -5.0f)),
+ // );
+ auto* vector_literal =
+ vec4<f32>(Expr(f32(2.0)), Expr(f32(3.0)), Expr(f32(4.0)), Expr(f32(8.0)));
+ auto* vector_zero_ctor = vec4<f32>();
+ auto* vector_single_scalar_ctor = vec4<f32>(Expr(f32(7.0)));
+ auto* vector_identical_ctor =
+ vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
+
+ auto* constructor = mat4x4<f32>(vector_literal, vector_zero_ctor, vector_single_scalar_ctor,
+ vector_identical_ctor);
+
+ WrapInFunction(constructor);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("float4x4(float4(2.0f, 3.0f, 4.0f, 8.0f), float4(0.0f), "
+ "float4(7.0f), float4(42.0f, 21.0f, 6.0f, -5.0f))"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Complex_F16) {
+ // mat4x4<f16>(
+ // vec4<f16>(2.0h, 3.0h, 4.0h, 8.0h),
+ // vec4<f16>(),
+ // vec4<f16>(7.0h),
+ // vec4<f16>(vec4<f16>(42.0h, 21.0h, 6.0h, -5.0h)),
+ // );
+ Enable(ast::Extension::kF16);
+
+ auto* vector_literal =
+ vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
+ auto* vector_zero_ctor = vec4<f16>();
+ auto* vector_single_scalar_ctor = vec4<f16>(Expr(f16(7.0)));
+ auto* vector_identical_ctor =
+ vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
+
+ auto* constructor = mat4x4<f16>(vector_literal, vector_zero_ctor, vector_single_scalar_ctor,
+ vector_identical_ctor);
+
+ WrapInFunction(constructor);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("half4x4(half4(2.0h, 3.0h, 4.0h, 8.0h), half4(0.0h), "
+ "half4(7.0h), half4(42.0h, 21.0h, 6.0h, -5.0h))"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Empty_F32) {
+ WrapInFunction(mat2x3<f32>());
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("float2x3 const tint_symbol = float2x3(float3(0.0f), float3(0.0f))"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Empty_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(mat2x3<f16>());
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(),
+ HasSubstr("half2x3 const tint_symbol = half2x3(half3(0.0h), half3(0.0h))"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Identity_F32) {
+ // fn f() {
+ // var m_1: mat4x4<f32> = mat4x4<f32>();
+ // var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
+ // }
+
+ auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), mat4x4<f32>());
+ auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), mat4x4<f32>(m_1));
+
+ WrapInFunction(m_1, m_2);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_THAT(gen.result(), HasSubstr("float4x4 m_2 = float4x4(m_1);"));
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Identity_F16) {
+ // fn f() {
+ // var m_1: mat4x4<f16> = mat4x4<f16>();
+ // var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
+ // }
+
+ Enable(ast::Extension::kF16);
+
+ auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
+ auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
+
+ WrapInFunction(m_1, m_2);
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr("float4x4(float4(0.0f), float4(0.0f)"));
+
+ EXPECT_THAT(gen.result(), HasSubstr("half4x4 m_2 = half4x4(m_1);"));
}
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Array) {
@@ -149,7 +387,7 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Array) {
}
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
Member("c", ty.vec3<i32>()),
@@ -164,7 +402,7 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct) {
}
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct_Empty) {
- auto* str = Structure("S", {
+ auto* str = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
Member("c", ty.vec3<i32>()),
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_function_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_function_test.cc
index 3c78522487a..0f891a28e81 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_function_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_function_test.cc
@@ -24,11 +24,10 @@ namespace {
using MslGeneratorImplTest = TestHelper;
TEST_F(MslGeneratorImplTest, Emit_Function) {
- Func("my_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
- },
- {});
+ });
GeneratorImpl& gen = Build();
@@ -46,15 +45,15 @@ TEST_F(MslGeneratorImplTest, Emit_Function) {
}
TEST_F(MslGeneratorImplTest, Emit_Function_WithParams) {
- ast::VariableList params;
- params.push_back(Param("a", ty.f32()));
- params.push_back(Param("b", ty.i32()));
-
- Func("my_func", params, ty.void_(),
- ast::StatementList{
- Return(),
+ Func("my_func",
+ utils::Vector{
+ Param("a", ty.f32()),
+ Param("b", ty.i32()),
},
- {});
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ });
GeneratorImpl& gen = Build();
@@ -72,8 +71,8 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithParams) {
}
TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_NoReturn_Void) {
- Func("main", ast::VariableList{}, ty.void_(), ast::StatementList{/* no explicit return */},
- {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(), {/* no explicit return */},
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build();
@@ -92,9 +91,17 @@ TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_WithInOutVars) {
// fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
// return foo;
// }
- auto* foo_in = Param("foo", ty.f32(), {Location(0)});
- Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
- {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
+ auto* foo_in = Param("foo", ty.f32(), utils::Vector{Location(0)});
+ Func("frag_main", utils::Vector{foo_in}, ty.f32(),
+ utils::Vector{
+ Return("foo"),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Location(1),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -128,9 +135,18 @@ TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_WithInOut_Builtins) {
// fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
// return coord.x;
// }
- auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
- Func("frag_main", ast::VariableList{coord_in}, ty.f32(), {Return(MemberAccessor("coord", "x"))},
- {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
+ auto* coord_in =
+ Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+ Func("frag_main", utils::Vector{coord_in}, ty.f32(),
+ utils::Vector{
+ Return(MemberAccessor("coord", "x")),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFragDepth),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -170,23 +186,24 @@ TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_SharedStruct_DifferentSta
// const g = colors.col2;
// }
auto* interface_struct = Structure(
- "Interface", {
- Member("col1", ty.f32(), {Location(1)}),
- Member("col2", ty.f32(), {Location(2)}),
- Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
- });
-
- Func("vert_main", {}, ty.Of(interface_struct),
- {Return(Construct(ty.Of(interface_struct), Expr(0.5_f), Expr(0.25_f),
- Construct(ty.vec4<f32>())))},
- {Stage(ast::PipelineStage::kVertex)});
-
- Func("frag_main", {Param("colors", ty.Of(interface_struct))}, ty.void_(),
- {
+ "Interface",
+ utils::Vector{
+ Member("col1", ty.f32(), utils::Vector{Location(1)}),
+ Member("col2", ty.f32(), utils::Vector{Location(2)}),
+ Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+ });
+
+ Func("vert_main", utils::Empty, ty.Of(interface_struct),
+ utils::Vector{Return(Construct(ty.Of(interface_struct), Expr(0.5_f), Expr(0.25_f),
+ Construct(ty.vec4<f32>())))},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
+
+ Func("frag_main", utils::Vector{Param("colors", ty.Of(interface_struct))}, ty.void_(),
+ utils::Vector{
WrapInStatement(Let("r", ty.f32(), MemberAccessor("colors", "col1"))),
WrapInStatement(Let("g", ty.f32(), MemberAccessor("colors", "col2"))),
},
- {Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -207,7 +224,7 @@ struct tint_symbol {
};
Interface vert_main_inner() {
- Interface const tint_symbol_3 = {.col1=0.5f, .col2=0.25f, .pos=float4(0.0f)};
+ Interface const tint_symbol_3 = Interface{.col1=0.5f, .col2=0.25f, .pos=float4(0.0f)};
return tint_symbol_3;
}
@@ -253,18 +270,23 @@ TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_SharedStruct_HelperFuncti
// return foo(0.25);
// }
auto* vertex_output_struct = Structure(
- "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
-
- Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
- {Return(Construct(ty.Of(vertex_output_struct),
- Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1_f))))},
- {});
-
- Func("vert_main1", {}, ty.Of(vertex_output_struct), {Return(Expr(Call("foo", Expr(0.5_f))))},
- {Stage(ast::PipelineStage::kVertex)});
+ "VertexOutput",
+ utils::Vector{
+ Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+ });
+
+ Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
+ utils::Vector{
+ Return(Construct(ty.Of(vertex_output_struct),
+ Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1_f)))),
+ });
+ Func("vert_main1", utils::Empty, ty.Of(vertex_output_struct),
+ utils::Vector{Return(Expr(Call("foo", Expr(0.5_f))))},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
- Func("vert_main2", {}, ty.Of(vertex_output_struct), {Return(Expr(Call("foo", Expr(0.25_f))))},
- {Stage(ast::PipelineStage::kVertex)});
+ Func("vert_main2", utils::Empty, ty.Of(vertex_output_struct),
+ utils::Vector{Return(Expr(Call("foo", Expr(0.25_f))))},
+ utils::Vector{Stage(ast::PipelineStage::kVertex)});
GeneratorImpl& gen = SanitizeAndBuild();
@@ -315,25 +337,22 @@ vertex tint_symbol_1 vert_main2() {
}
TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_EntryPoint_With_RW_StorageBuffer) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ GroupAndBinding(0, 0));
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -357,25 +376,22 @@ fragment void frag_main(device Data* tint_symbol [[buffer(0)]]) {
}
TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_EntryPoint_With_RO_StorageBuffer) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -399,30 +415,26 @@ fragment void frag_main(const device Data* tint_symbol [[buffer(0)]]) {
}
TEST_F(MslGeneratorImplTest, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
- auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
- auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* ubo_ty = Structure("UBO", utils::Vector{Member("coord", ty.vec4<f32>())});
+ auto* ubo = GlobalVar("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
Func("sub_func",
- {
+ utils::Vector{
Param("param", ty.f32()),
},
ty.f32(),
- {
+ utils::Vector{
Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
});
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", {}, ty.void_(),
- {
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -449,32 +461,31 @@ fragment void frag_main(const constant UBO* tint_symbol_1 [[buffer(0)]]) {
}
TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_Called_By_EntryPoint_With_RW_StorageBuffer) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
-
- ast::VariableList params;
- params.push_back(Param("param", ty.f32()));
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ GroupAndBinding(0, 0));
- auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
-
- Func("sub_func", params, ty.f32(), body, {});
+ Func("sub_func",
+ utils::Vector{
+ Param("param", ty.f32()),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(MemberAccessor("coord", "b")),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -502,32 +513,31 @@ fragment void frag_main(device Data* tint_symbol_1 [[buffer(0)]]) {
}
TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_Called_By_EntryPoint_With_RO_StorageBuffer) {
- auto* s = Structure("Data", {
+ auto* s = Structure("Data", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
-
- ast::VariableList params;
- params.push_back(Param("param", ty.f32()));
+ GlobalVar("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ GroupAndBinding(0, 0));
- auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
-
- Func("sub_func", params, ty.f32(), body, {});
+ Func("sub_func",
+ utils::Vector{
+ Param("param", ty.f32()),
+ },
+ ty.f32(),
+ utils::Vector{
+ Return(MemberAccessor("coord", "b")),
+ });
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1_f));
- Func("frag_main", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("frag_main", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -555,11 +565,12 @@ fragment void frag_main(const device Data* tint_symbol_1 [[buffer(0)]]) {
}
TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayParams) {
- ast::VariableList params;
- params.push_back(Param("a", ty.array<f32, 5>()));
-
- Func("my_func", params, ty.void_(),
- {
+ Func("my_func",
+ utils::Vector{
+ Param("a", ty.array<f32, 5>()),
+ },
+ ty.void_(),
+ utils::Vector{
Return(),
});
@@ -571,11 +582,20 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayParams) {
EXPECT_EQ(gen.result(), R"( #include <metal_stdlib>
using namespace metal;
- struct tint_array_wrapper {
- float arr[5];
- };
- void my_func(tint_array_wrapper a) {
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+ void my_func(tint_array<float, 5> a) {
return;
}
@@ -583,8 +603,8 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayParams) {
}
TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayReturn) {
- Func("my_func", {}, ty.array<f32, 5>(),
- {
+ Func("my_func", utils::Empty, ty.array<f32, 5>(),
+ utils::Vector{
Return(Construct(ty.array<f32, 5>())),
});
@@ -596,12 +616,21 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayReturn) {
EXPECT_EQ(gen.result(), R"( #include <metal_stdlib>
using namespace metal;
- struct tint_array_wrapper {
- float arr[5];
- };
- tint_array_wrapper my_func() {
- tint_array_wrapper const tint_symbol = {.arr={}};
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+ tint_array<float, 5> my_func() {
+ tint_array<float, 5> const tint_symbol = tint_array<float, 5>{};
return tint_symbol;
}
@@ -625,23 +654,20 @@ TEST_F(MslGeneratorImplTest, Emit_Function_Multiple_EntryPoint_With_Same_ModuleV
// return;
// }
- auto* s = Structure("Data", {Member("d", ty.f32())});
+ auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
- Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ GroupAndBinding(0, 0));
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("a", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("a", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- {
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -650,8 +676,12 @@ TEST_F(MslGeneratorImplTest, Emit_Function_Multiple_EntryPoint_With_Same_ModuleV
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("b", ast::VariableList{}, ty.void_(), ast::StatementList{Decl(var), Return()},
- {
+ Func("b", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(var),
+ Return(),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_import_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_import_test.cc
index de9353ea446..7b79569b176 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_import_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_import_test.cc
@@ -234,7 +234,7 @@ INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
MslImportData{"clamp", "clamp"}));
TEST_F(MslGeneratorImplTest, MslImportData_Determinant) {
- Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("determinant", "var");
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_loop_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_loop_test.cc
index 248e7116928..7c84db01506 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_loop_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_loop_test.cc
@@ -40,7 +40,7 @@ TEST_F(MslGeneratorImplTest, Emit_Loop) {
}
TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing) {
- Func("a_statement", {}, ty.void_(), {});
+ Func("a_statement", {}, ty.void_(), utils::Empty);
auto* body = Block(create<ast::DiscardStatement>());
auto* continuing = Block(CallStmt(Call("a_statement")));
@@ -62,10 +62,10 @@ TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing) {
}
TEST_F(MslGeneratorImplTest, Emit_LoopNestedWithContinuing) {
- Func("a_statement", {}, ty.void_(), {});
+ Func("a_statement", {}, ty.void_(), utils::Empty);
- Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
- Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("lhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.f32(), ast::StorageClass::kPrivate);
auto* body = Block(create<ast::DiscardStatement>());
auto* continuing = Block(CallStmt(Call("a_statement")));
@@ -107,7 +107,7 @@ TEST_F(MslGeneratorImplTest, Emit_LoopWithVarUsedInContinuing) {
// }
//
- Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("rhs", ty.f32(), ast::StorageClass::kPrivate);
auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4_f))), //
Decl(Var("other", ty.f32())), //
@@ -181,10 +181,10 @@ TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtInit) {
// return;
// }
- Func("f", {Param("i", ty.i32())}, ty.void_(), {});
+ Func("f", utils::Vector{Param("i", ty.i32())}, ty.void_(), utils::Empty);
auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
- Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
auto* multi_stmt = Block(f(1_i), f(2_i));
auto* loop = For(multi_stmt, nullptr, nullptr, //
Block(Return()));
@@ -257,10 +257,10 @@ TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtCont) {
// return;
// }
- Func("f", {Param("i", ty.i32())}, ty.void_(), {});
+ Func("f", utils::Vector{Param("i", ty.i32())}, ty.void_(), utils::Empty);
auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
- Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
auto* multi_stmt = Block(f(1_i), f(2_i));
auto* loop = For(nullptr, nullptr, multi_stmt, //
Block(Return()));
@@ -286,7 +286,7 @@ TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleInitCondCont) {
// return;
// }
- Func("a_statement", {}, ty.void_(), {});
+ Func("a_statement", {}, ty.void_(), utils::Empty);
auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1_i)),
Block(CallStmt(Call("a_statement"))));
@@ -312,10 +312,10 @@ TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtInitCondCont) {
// return;
// }
- Func("f", {Param("i", ty.i32())}, ty.void_(), {});
+ Func("f", utils::Vector{Param("i", ty.i32())}, ty.void_(), utils::Empty);
auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
- Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
auto* multi_stmt_a = Block(f(1_i), f(2_i));
auto* multi_stmt_b = Block(f(3_i), f(4_i));
auto* loop = For(multi_stmt_a, Expr(true), multi_stmt_b, //
@@ -344,5 +344,64 @@ TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtInitCondCont) {
)");
}
+TEST_F(MslGeneratorImplTest, Emit_While) {
+ // while(true) {
+ // return;
+ // }
+
+ auto* f = While(Expr(true), Block(Return()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while(true) {
+ return;
+ }
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_While_WithContinue) {
+ // while(true) {
+ // continue;
+ // }
+
+ auto* f = While(Expr(true), Block(Continue()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while(true) {
+ continue;
+ }
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_WhileWithMultiCond) {
+ // while(true && false) {
+ // return;
+ // }
+
+ auto* multi_stmt =
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+ auto* f = While(multi_stmt, Block(Return()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while((true && false)) {
+ return;
+ }
+)");
+}
+
} // namespace
} // namespace tint::writer::msl
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_member_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_member_accessor_test.cc
index c9f3da074a7..e1899103ef6 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_member_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_member_accessor_test.cc
@@ -20,8 +20,8 @@ namespace {
using MslGeneratorImplTest = TestHelper;
TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor) {
- Global("str", ty.Of(Structure("my_str", {Member("mem", ty.f32())})),
- ast::StorageClass::kPrivate);
+ GlobalVar("str", ty.Of(Structure("my_str", utils::Vector{Member("mem", ty.f32())})),
+ ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("str", "mem");
WrapInFunction(expr);
@@ -33,7 +33,7 @@ TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor) {
}
TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_xyz) {
- Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("my_vec", "xyz");
WrapInFunction(expr);
@@ -45,7 +45,7 @@ TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_xyz) {
}
TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_gbr) {
- Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("my_vec", "gbr");
WrapInFunction(expr);
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_module_constant_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_module_constant_test.cc
index 2b70da48d3b..054a0f4407c 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_module_constant_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_module_constant_test.cc
@@ -22,38 +22,336 @@ namespace {
using MslGeneratorImplTest = TestHelper;
-TEST_F(MslGeneratorImplTest, Emit_ModuleConstant) {
- auto* var = GlobalConst("pos", ty.array<f32, 3>(), array<f32, 3>(1_f, 2_f, 3_f));
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_AInt) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
- EXPECT_EQ(gen.result(), "constant float pos[3] = {1.0f, 2.0f, 3.0f};\n");
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_AFloat) {
+ auto* var = GlobalConst("G", nullptr, Expr(1._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_i32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_i));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_u32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_u));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ uint const l = 1u;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_f32) {
+ auto* var = GlobalConst("G", nullptr, Expr(1_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, Expr(1_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ half const l = 1.0h;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_AInt) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ int3 const l = int3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_AFloat) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_f32) {
+ auto* var = GlobalConst("G", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ half3 const l = half3(1.0h, 2.0h, 3.0h);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_AFloat) {
+ auto* var = GlobalConst("G", nullptr,
+ Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_f32) {
+ auto* var = GlobalConst("G", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalConst("G", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ half2x3 const l = half2x3(half3(1.0h, 2.0h, 3.0h), half3(4.0h, 5.0h, 6.0h));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_arr_f32) {
+ auto* var = GlobalConst("G", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+void f() {
+ tint_array<float, 3> const l = tint_array<float, 3>{1.0f, 2.0f, 3.0f};
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_arr_vec2_bool) {
+ auto* var = GlobalConst("G", nullptr,
+ Construct(ty.array(ty.vec2<bool>(), 3_u), //
+ vec2<bool>(true, false), //
+ vec2<bool>(false, true), //
+ vec2<bool>(true, true)));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", nullptr, Expr(var)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+void f() {
+ tint_array<bool2, 3> const l = tint_array<bool2, 3>{bool2(true, false), bool2(false, true), bool2(true)};
+}
+
+)");
}
-TEST_F(MslGeneratorImplTest, Emit_SpecConstant) {
+TEST_F(MslGeneratorImplTest, Emit_Override) {
auto* var = Override("pos", ty.f32(), Expr(3_f),
- ast::AttributeList{
+ utils::Vector{
Id(23),
});
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(var)) << gen.error();
EXPECT_EQ(gen.result(), "constant float pos [[function_constant(23)]];\n");
}
-TEST_F(MslGeneratorImplTest, Emit_SpecConstant_NoId) {
+TEST_F(MslGeneratorImplTest, Emit_Override_NoId) {
auto* var_a = Override("a", ty.f32(), nullptr,
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
auto* var_b = Override("b", ty.f32(), nullptr);
GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var_a)) << gen.error();
- ASSERT_TRUE(gen.EmitProgramConstVariable(var_b)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(var_a)) << gen.error();
+ ASSERT_TRUE(gen.EmitOverride(var_b)) << gen.error();
EXPECT_EQ(gen.result(), R"(constant float a [[function_constant(0)]];
constant float b [[function_constant(1)]];
)");
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_return_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_return_test.cc
index 144320962b7..c9c3de786e0 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_return_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_return_test.cc
@@ -35,7 +35,7 @@ TEST_F(MslGeneratorImplTest, Emit_Return) {
TEST_F(MslGeneratorImplTest, Emit_ReturnWithValue) {
auto* r = Return(123_i);
- Func("f", {}, ty.i32(), {r});
+ Func("f", utils::Empty, ty.i32(), utils::Vector{r});
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_sanitizer_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_sanitizer_test.cc
index 32ddb42700f..62ada064b9d 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_sanitizer_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_sanitizer_test.cc
@@ -26,19 +26,19 @@ using ::testing::HasSubstr;
using MslSanitizerTest = TestHelper;
TEST_F(MslSanitizerTest, Call_ArrayLength) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -50,12 +50,25 @@ TEST_F(MslSanitizerTest, Call_ArrayLength) {
auto* expect = R"(#include <metal_stdlib>
using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
struct tint_symbol {
- /* 0x0000 */ uint4 buffer_size[1];
+ /* 0x0000 */ tint_array<uint4, 1> buffer_size;
};
struct my_struct {
- float a[1];
+ tint_array<float, 1> a;
};
fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(30)]]) {
@@ -68,22 +81,22 @@ fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(30)]]) {
}
TEST_F(MslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member(0, "z", ty.f32()),
Member(4, "a", ty.array<f32>(4)),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -95,13 +108,26 @@ TEST_F(MslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
auto* expect = R"(#include <metal_stdlib>
using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
struct tint_symbol {
- /* 0x0000 */ uint4 buffer_size[1];
+ /* 0x0000 */ tint_array<uint4, 1> buffer_size;
};
struct my_struct {
float z;
- float a[1];
+ tint_array<float, 1> a;
};
fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(30)]]) {
@@ -115,23 +141,23 @@ fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(30)]]) {
}
TEST_F(MslSanitizerTest, Call_ArrayLength_ViaLets) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
auto* p = Let("p", nullptr, AddressOf("b"));
auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(p),
Decl(p2),
Decl(Var("len", ty.u32(), ast::StorageClass::kNone, Call("arrayLength", p2))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -143,12 +169,25 @@ TEST_F(MslSanitizerTest, Call_ArrayLength_ViaLets) {
auto* expect = R"(#include <metal_stdlib>
using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
struct tint_symbol {
- /* 0x0000 */ uint4 buffer_size[1];
+ /* 0x0000 */ tint_array<uint4, 1> buffer_size;
};
struct my_struct {
- float a[1];
+ tint_array<float, 1> a;
};
fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(30)]]) {
@@ -162,25 +201,25 @@ fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(30)]]) {
}
TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
- Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(2),
- create<ast::GroupAttribute>(0),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
+ GlobalVar("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(2u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -196,12 +235,25 @@ TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
auto* expect = R"(#include <metal_stdlib>
using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
struct tint_symbol {
- /* 0x0000 */ uint4 buffer_size[2];
+ /* 0x0000 */ tint_array<uint4, 2> buffer_size;
};
struct my_struct {
- float a[1];
+ tint_array<float, 1> a;
};
fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(29)]]) {
@@ -214,25 +266,25 @@ fragment void a_func(const constant tint_symbol* tint_symbol_2 [[buffer(29)]]) {
}
TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniformMissingBinding) {
- auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
- Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(2),
- create<ast::GroupAttribute>(0),
- });
-
- Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
+ GlobalVar("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(2u),
+ create<ast::GroupAttribute>(0u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_static_assert_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_static_assert_test.cc
new file mode 100644
index 00000000000..5b8ca3fd941
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_static_assert_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/writer/msl/test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::writer::msl {
+namespace {
+
+using MslGeneratorImplTest = TestHelper;
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalStaticAssert) {
+ GlobalStaticAssert(true);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ // static asserts are not emitted
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_FunctionStaticAssert) {
+ Func("f", utils::Empty, ty.void_(), utils::Vector{StaticAssert(true)});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ // static asserts are not emitted
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+}
+
+)");
+}
+
+} // namespace
+} // namespace tint::writer::msl
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_switch_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_switch_test.cc
index ce8087b0a39..b327f34f36a 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_switch_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_switch_test.cc
@@ -25,19 +25,15 @@ TEST_F(MslGeneratorImplTest, Emit_Switch) {
auto* cond = Var("cond", ty.i32());
auto* def_body = Block(create<ast::BreakStatement>());
- auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
+ auto* def = create<ast::CaseStatement>(utils::Empty, def_body);
- ast::CaseSelectorList case_val;
- case_val.push_back(Expr(5_i));
+ utils::Vector case_val{Expr(5_i)};
auto* case_body = Block(create<ast::BreakStatement>());
auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
- ast::CaseStatementList body;
- body.push_back(case_stmt);
- body.push_back(def);
-
+ utils::Vector body{case_stmt, def};
auto* s = create<ast::SwitchStatement>(Expr(cond), body);
WrapInFunction(cond, s);
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_test.cc
index 7cef2684197..63c56b0f73b 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_test.cc
@@ -32,8 +32,8 @@ TEST_F(MslGeneratorImplTest, InvalidProgram) {
}
TEST_F(MslGeneratorImplTest, Generate) {
- Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ Func("my_func", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -52,7 +52,7 @@ kernel void my_func() {
}
struct MslBuiltinData {
- ast::Builtin builtin;
+ ast::BuiltinValue builtin;
const char* attribute_name;
};
inline std::ostream& operator<<(std::ostream& out, MslBuiltinData data) {
@@ -71,25 +71,32 @@ INSTANTIATE_TEST_SUITE_P(
MslGeneratorImplTest,
MslBuiltinConversionTest,
testing::Values(
- MslBuiltinData{ast::Builtin::kPosition, "position"},
- MslBuiltinData{ast::Builtin::kVertexIndex, "vertex_id"},
- MslBuiltinData{ast::Builtin::kInstanceIndex, "instance_id"},
- MslBuiltinData{ast::Builtin::kFrontFacing, "front_facing"},
- MslBuiltinData{ast::Builtin::kFragDepth, "depth(any)"},
- MslBuiltinData{ast::Builtin::kLocalInvocationId, "thread_position_in_threadgroup"},
- MslBuiltinData{ast::Builtin::kLocalInvocationIndex, "thread_index_in_threadgroup"},
- MslBuiltinData{ast::Builtin::kGlobalInvocationId, "thread_position_in_grid"},
- MslBuiltinData{ast::Builtin::kWorkgroupId, "threadgroup_position_in_grid"},
- MslBuiltinData{ast::Builtin::kNumWorkgroups, "threadgroups_per_grid"},
- MslBuiltinData{ast::Builtin::kSampleIndex, "sample_id"},
- MslBuiltinData{ast::Builtin::kSampleMask, "sample_mask"},
- MslBuiltinData{ast::Builtin::kPointSize, "point_size"}));
+ MslBuiltinData{ast::BuiltinValue::kPosition, "position"},
+ MslBuiltinData{ast::BuiltinValue::kVertexIndex, "vertex_id"},
+ MslBuiltinData{ast::BuiltinValue::kInstanceIndex, "instance_id"},
+ MslBuiltinData{ast::BuiltinValue::kFrontFacing, "front_facing"},
+ MslBuiltinData{ast::BuiltinValue::kFragDepth, "depth(any)"},
+ MslBuiltinData{ast::BuiltinValue::kLocalInvocationId, "thread_position_in_threadgroup"},
+ MslBuiltinData{ast::BuiltinValue::kLocalInvocationIndex, "thread_index_in_threadgroup"},
+ MslBuiltinData{ast::BuiltinValue::kGlobalInvocationId, "thread_position_in_grid"},
+ MslBuiltinData{ast::BuiltinValue::kWorkgroupId, "threadgroup_position_in_grid"},
+ MslBuiltinData{ast::BuiltinValue::kNumWorkgroups, "threadgroups_per_grid"},
+ MslBuiltinData{ast::BuiltinValue::kSampleIndex, "sample_id"},
+ MslBuiltinData{ast::BuiltinValue::kSampleMask, "sample_mask"},
+ MslBuiltinData{ast::BuiltinValue::kPointSize, "point_size"}));
TEST_F(MslGeneratorImplTest, HasInvariantAttribute_True) {
- auto* out = Structure(
- "Out", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition), Invariant()})});
- Func("vert_main", ast::VariableList{}, ty.Of(out), {Return(Construct(ty.Of(out)))},
- {Stage(ast::PipelineStage::kVertex)});
+ auto* out = Structure("Out", utils::Vector{
+ Member("pos", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ Invariant(),
+ }),
+ });
+ Func("vert_main", utils::Empty, ty.Of(out), utils::Vector{Return(Construct(ty.Of(out)))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ });
GeneratorImpl& gen = Build();
@@ -110,17 +117,23 @@ struct Out {
};
vertex Out vert_main() {
- return {};
+ return Out{};
}
)");
}
TEST_F(MslGeneratorImplTest, HasInvariantAttribute_False) {
- auto* out =
- Structure("Out", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
- Func("vert_main", ast::VariableList{}, ty.Of(out), {Return(Construct(ty.Of(out)))},
- {Stage(ast::PipelineStage::kVertex)});
+ auto* out = Structure("Out", utils::Vector{
+ Member("pos", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ }),
+ });
+ Func("vert_main", utils::Empty, ty.Of(out), utils::Vector{Return(Construct(ty.Of(out)))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ });
GeneratorImpl& gen = Build();
@@ -134,16 +147,19 @@ struct Out {
};
vertex Out vert_main() {
- return {};
+ return Out{};
}
)");
}
TEST_F(MslGeneratorImplTest, WorkgroupMatrix) {
- Global("m", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
- Func("comp_main", ast::VariableList{}, ty.void_(), {Decl(Let("x", nullptr, Expr("m")))},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ GlobalVar("m", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
+ Func("comp_main", utils::Empty, ty.void_(), utils::Vector{Decl(Let("x", nullptr, Expr("m")))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -178,9 +194,12 @@ kernel void comp_main(threadgroup tint_symbol_3* tint_symbol_2 [[threadgroup(0)]
}
TEST_F(MslGeneratorImplTest, WorkgroupMatrixInArray) {
- Global("m", ty.array(ty.mat2x2<f32>(), 4_i), ast::StorageClass::kWorkgroup);
- Func("comp_main", ast::VariableList{}, ty.void_(), {Decl(Let("x", nullptr, Expr("m")))},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ GlobalVar("m", ty.array(ty.mat2x2<f32>(), 4_i), ast::StorageClass::kWorkgroup);
+ Func("comp_main", utils::Empty, ty.void_(), utils::Vector{Decl(Let("x", nullptr, Expr("m")))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -188,25 +207,34 @@ TEST_F(MslGeneratorImplTest, WorkgroupMatrixInArray) {
EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
using namespace metal;
-struct tint_array_wrapper {
- float2x2 arr[4];
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
};
struct tint_symbol_3 {
- tint_array_wrapper m;
+ tint_array<float2x2, 4> m;
};
-void comp_main_inner(uint local_invocation_index, threadgroup tint_array_wrapper* const tint_symbol) {
+void comp_main_inner(uint local_invocation_index, threadgroup tint_array<float2x2, 4>* const tint_symbol) {
for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
uint const i = idx;
- (*(tint_symbol)).arr[i] = float2x2(float2(0.0f), float2(0.0f));
+ (*(tint_symbol))[i] = float2x2(float2(0.0f), float2(0.0f));
}
threadgroup_barrier(mem_flags::mem_threadgroup);
- tint_array_wrapper const x = *(tint_symbol);
+ tint_array<float2x2, 4> const x = *(tint_symbol);
}
kernel void comp_main(threadgroup tint_symbol_3* tint_symbol_2 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
- threadgroup tint_array_wrapper* const tint_symbol_1 = &((*(tint_symbol_2)).m);
+ threadgroup tint_array<float2x2, 4>* const tint_symbol_1 = &((*(tint_symbol_2)).m);
comp_main_inner(local_invocation_index, tint_symbol_1);
return;
}
@@ -220,16 +248,19 @@ kernel void comp_main(threadgroup tint_symbol_3* tint_symbol_2 [[threadgroup(0)]
}
TEST_F(MslGeneratorImplTest, WorkgroupMatrixInStruct) {
- Structure("S1", {
+ Structure("S1", utils::Vector{
Member("m1", ty.mat2x2<f32>()),
Member("m2", ty.mat4x4<f32>()),
});
- Structure("S2", {
+ Structure("S2", utils::Vector{
Member("s", ty.type_name("S1")),
});
- Global("s", ty.type_name("S2"), ast::StorageClass::kWorkgroup);
- Func("comp_main", ast::VariableList{}, ty.void_(), {Decl(Let("x", nullptr, Expr("s")))},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ GlobalVar("s", ty.type_name("S2"), ast::StorageClass::kWorkgroup);
+ Func("comp_main", utils::Empty, ty.void_(), utils::Vector{Decl(Let("x", nullptr, Expr("s")))},
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
@@ -252,7 +283,7 @@ struct tint_symbol_4 {
void comp_main_inner(uint local_invocation_index, threadgroup S2* const tint_symbol_1) {
{
- S2 const tint_symbol = {};
+ S2 const tint_symbol = S2{};
*(tint_symbol_1) = tint_symbol;
}
threadgroup_barrier(mem_flags::mem_threadgroup);
@@ -274,38 +305,50 @@ kernel void comp_main(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]
}
TEST_F(MslGeneratorImplTest, WorkgroupMatrix_Multiples) {
- Global("m1", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
- Global("m2", ty.mat2x3<f32>(), ast::StorageClass::kWorkgroup);
- Global("m3", ty.mat2x4<f32>(), ast::StorageClass::kWorkgroup);
- Global("m4", ty.mat3x2<f32>(), ast::StorageClass::kWorkgroup);
- Global("m5", ty.mat3x3<f32>(), ast::StorageClass::kWorkgroup);
- Global("m6", ty.mat3x4<f32>(), ast::StorageClass::kWorkgroup);
- Global("m7", ty.mat4x2<f32>(), ast::StorageClass::kWorkgroup);
- Global("m8", ty.mat4x3<f32>(), ast::StorageClass::kWorkgroup);
- Global("m9", ty.mat4x4<f32>(), ast::StorageClass::kWorkgroup);
- Func("main1", ast::VariableList{}, ty.void_(),
- {
+ GlobalVar("m1", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m2", ty.mat2x3<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m3", ty.mat2x4<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m4", ty.mat3x2<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m5", ty.mat3x3<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m6", ty.mat3x4<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m7", ty.mat4x2<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m8", ty.mat4x3<f32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("m9", ty.mat4x4<f32>(), ast::StorageClass::kWorkgroup);
+ Func("main1", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("a1", nullptr, Expr("m1"))),
Decl(Let("a2", nullptr, Expr("m2"))),
Decl(Let("a3", nullptr, Expr("m3"))),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
- Func("main2", ast::VariableList{}, ty.void_(),
- {
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
+ Func("main2", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("a1", nullptr, Expr("m4"))),
Decl(Let("a2", nullptr, Expr("m5"))),
Decl(Let("a3", nullptr, Expr("m6"))),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
- Func("main3", ast::VariableList{}, ty.void_(),
- {
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
+ Func("main3", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("a1", nullptr, Expr("m7"))),
Decl(Let("a2", nullptr, Expr("m8"))),
Decl(Let("a3", nullptr, Expr("m9"))),
},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
- Func("main4_no_usages", ast::VariableList{}, ty.void_(), {},
- {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
+ Func("main4_no_usages", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kCompute),
+ WorkgroupSize(1_i),
+ });
GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_type_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_type_test.cc
index 257468bff31..a3e85a56faa 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_type_test.cc
@@ -31,6 +31,20 @@ using namespace tint::number_suffixes; // NOLINT
namespace tint::writer::msl {
namespace {
+void FormatMSLField(std::stringstream& out,
+ const char* addr,
+ const char* type,
+ size_t array_count,
+ const char* name) {
+ out << " /* " << std::string(addr) << " */ ";
+ if (array_count == 0) {
+ out << type << " ";
+ } else {
+ out << "tint_array<" << type << ", " << std::to_string(array_count) << "> ";
+ }
+ out << name << ";\n";
+}
+
#define CHECK_TYPE_SIZE_AND_ALIGN(TYPE, SIZE, ALIGN) \
static_assert(sizeof(TYPE) == SIZE, "Bad type size"); \
static_assert(alignof(TYPE) == ALIGN, "Bad type alignment")
@@ -57,66 +71,78 @@ DECLARE_TYPE(float3x4, 48, 16);
DECLARE_TYPE(float4x2, 32, 8);
DECLARE_TYPE(float4x3, 64, 16);
DECLARE_TYPE(float4x4, 64, 16);
+DECLARE_TYPE(half2, 4, 4);
+DECLARE_TYPE(packed_half3, 6, 2);
+DECLARE_TYPE(half4, 8, 8);
+DECLARE_TYPE(half2x2, 8, 4);
+DECLARE_TYPE(half2x3, 16, 8);
+DECLARE_TYPE(half2x4, 16, 8);
+DECLARE_TYPE(half3x2, 12, 4);
+DECLARE_TYPE(half3x3, 24, 8);
+DECLARE_TYPE(half3x4, 24, 8);
+DECLARE_TYPE(half4x2, 16, 4);
+DECLARE_TYPE(half4x3, 32, 8);
+DECLARE_TYPE(half4x4, 32, 8);
using uint = unsigned int;
using MslGeneratorImplTest = TestHelper;
TEST_F(MslGeneratorImplTest, EmitType_Array) {
auto* arr = ty.array<bool, 4>();
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "ary")) << gen.error();
- EXPECT_EQ(out.str(), "bool ary[4]");
+ EXPECT_EQ(out.str(), "tint_array<bool, 4>");
}
TEST_F(MslGeneratorImplTest, EmitType_ArrayOfArray) {
auto* a = ty.array<bool, 4>();
auto* b = ty.array(a, 5_u);
- Global("G", b, ast::StorageClass::kPrivate);
+ GlobalVar("G", b, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(b), "ary")) << gen.error();
- EXPECT_EQ(out.str(), "bool ary[5][4]");
+ EXPECT_EQ(out.str(), "tint_array<tint_array<bool, 4>, 5>");
}
TEST_F(MslGeneratorImplTest, EmitType_ArrayOfArrayOfArray) {
auto* a = ty.array<bool, 4>();
auto* b = ty.array(a, 5_u);
auto* c = ty.array(b, 6_u);
- Global("G", c, ast::StorageClass::kPrivate);
+ GlobalVar("G", c, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(c), "ary")) << gen.error();
- EXPECT_EQ(out.str(), "bool ary[6][5][4]");
+ EXPECT_EQ(out.str(), "tint_array<tint_array<tint_array<bool, 4>, 5>, 6>");
}
TEST_F(MslGeneratorImplTest, EmitType_Array_WithoutName) {
auto* arr = ty.array<bool, 4>();
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "")) << gen.error();
- EXPECT_EQ(out.str(), "bool[4]");
+ EXPECT_EQ(out.str(), "tint_array<bool, 4>");
}
TEST_F(MslGeneratorImplTest, EmitType_RuntimeArray) {
auto* arr = ty.array<bool, 1>();
- Global("G", arr, ast::StorageClass::kPrivate);
+ GlobalVar("G", arr, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "ary")) << gen.error();
- EXPECT_EQ(out.str(), "bool ary[1]");
+ EXPECT_EQ(out.str(), "tint_array<bool, 1>");
}
TEST_F(MslGeneratorImplTest, EmitType_Bool) {
@@ -139,6 +165,16 @@ TEST_F(MslGeneratorImplTest, EmitType_F32) {
EXPECT_EQ(out.str(), "float");
}
+TEST_F(MslGeneratorImplTest, EmitType_F16) {
+ auto* f16 = create<sem::F16>();
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, f16, "")) << gen.error();
+ EXPECT_EQ(out.str(), "half");
+}
+
TEST_F(MslGeneratorImplTest, EmitType_I32) {
auto* i32 = create<sem::I32>();
@@ -149,7 +185,7 @@ TEST_F(MslGeneratorImplTest, EmitType_I32) {
EXPECT_EQ(out.str(), "int");
}
-TEST_F(MslGeneratorImplTest, EmitType_Matrix) {
+TEST_F(MslGeneratorImplTest, EmitType_Matrix_F32) {
auto* f32 = create<sem::F32>();
auto* vec3 = create<sem::Vector>(f32, 3u);
auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
@@ -161,6 +197,18 @@ TEST_F(MslGeneratorImplTest, EmitType_Matrix) {
EXPECT_EQ(out.str(), "float2x3");
}
+TEST_F(MslGeneratorImplTest, EmitType_Matrix_F16) {
+ auto* f16 = create<sem::F16>();
+ auto* vec3 = create<sem::Vector>(f16, 3u);
+ auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, mat2x3, "")) << gen.error();
+ EXPECT_EQ(out.str(), "half2x3");
+}
+
TEST_F(MslGeneratorImplTest, EmitType_Pointer) {
auto* f32 = create<sem::F32>();
auto* p = create<sem::Pointer>(f32, ast::StorageClass::kWorkgroup, ast::Access::kReadWrite);
@@ -173,7 +221,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Pointer) {
}
TEST_F(MslGeneratorImplTest, EmitType_Struct) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
@@ -186,7 +234,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct) {
}
TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
@@ -204,40 +252,41 @@ TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
}
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
- auto* s = Structure("S", {
- Member("a", ty.i32(), {MemberSize(32)}),
- Member("b", ty.f32(), {MemberAlign(128), MemberSize(128)}),
- Member("c", ty.vec2<f32>()),
- Member("d", ty.u32()),
- Member("e", ty.vec3<f32>()),
- Member("f", ty.u32()),
- Member("g", ty.vec4<f32>()),
- Member("h", ty.u32()),
- Member("i", ty.mat2x2<f32>()),
- Member("j", ty.u32()),
- Member("k", ty.mat2x3<f32>()),
- Member("l", ty.u32()),
- Member("m", ty.mat2x4<f32>()),
- Member("n", ty.u32()),
- Member("o", ty.mat3x2<f32>()),
- Member("p", ty.u32()),
- Member("q", ty.mat3x3<f32>()),
- Member("r", ty.u32()),
- Member("s", ty.mat3x4<f32>()),
- Member("t", ty.u32()),
- Member("u", ty.mat4x2<f32>()),
- Member("v", ty.u32()),
- Member("w", ty.mat4x3<f32>()),
- Member("x", ty.u32()),
- Member("y", ty.mat4x4<f32>()),
- Member("z", ty.f32()),
- });
+ auto* s =
+ Structure("S", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberSize(32)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(128), MemberSize(128)}),
+ Member("c", ty.vec2<f32>()),
+ Member("d", ty.u32()),
+ Member("e", ty.vec3<f32>()),
+ Member("f", ty.u32()),
+ Member("g", ty.vec4<f32>()),
+ Member("h", ty.u32()),
+ Member("i", ty.mat2x2<f32>()),
+ Member("j", ty.u32()),
+ Member("k", ty.mat2x3<f32>()),
+ Member("l", ty.u32()),
+ Member("m", ty.mat2x4<f32>()),
+ Member("n", ty.u32()),
+ Member("o", ty.mat3x2<f32>()),
+ Member("p", ty.u32()),
+ Member("q", ty.mat3x3<f32>()),
+ Member("r", ty.u32()),
+ Member("s", ty.mat3x4<f32>()),
+ Member("t", ty.u32()),
+ Member("u", ty.mat4x2<f32>()),
+ Member("v", ty.u32()),
+ Member("w", ty.mat4x3<f32>()),
+ Member("x", ty.u32()),
+ Member("y", ty.mat4x4<f32>()),
+ Member("z", ty.f32()),
+ });
- Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -245,54 +294,58 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
- // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+ // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
-#define ALL_FIELDS() \
- FIELD(0x0000, int, a, /*NO SUFFIX*/) \
- FIELD(0x0004, int8_t, tint_pad, [124]) \
- FIELD(0x0080, float, b, /*NO SUFFIX*/) \
- FIELD(0x0084, int8_t, tint_pad_1, [124]) \
- FIELD(0x0100, float2, c, /*NO SUFFIX*/) \
- FIELD(0x0108, uint, d, /*NO SUFFIX*/) \
- FIELD(0x010c, int8_t, tint_pad_2, [4]) \
- FIELD(0x0110, packed_float3, e, /*NO SUFFIX*/) \
- FIELD(0x011c, uint, f, /*NO SUFFIX*/) \
- FIELD(0x0120, float4, g, /*NO SUFFIX*/) \
- FIELD(0x0130, uint, h, /*NO SUFFIX*/) \
- FIELD(0x0134, int8_t, tint_pad_3, [4]) \
- FIELD(0x0138, float2x2, i, /*NO SUFFIX*/) \
- FIELD(0x0148, uint, j, /*NO SUFFIX*/) \
- FIELD(0x014c, int8_t, tint_pad_4, [4]) \
- FIELD(0x0150, float2x3, k, /*NO SUFFIX*/) \
- FIELD(0x0170, uint, l, /*NO SUFFIX*/) \
- FIELD(0x0174, int8_t, tint_pad_5, [12]) \
- FIELD(0x0180, float2x4, m, /*NO SUFFIX*/) \
- FIELD(0x01a0, uint, n, /*NO SUFFIX*/) \
- FIELD(0x01a4, int8_t, tint_pad_6, [4]) \
- FIELD(0x01a8, float3x2, o, /*NO SUFFIX*/) \
- FIELD(0x01c0, uint, p, /*NO SUFFIX*/) \
- FIELD(0x01c4, int8_t, tint_pad_7, [12]) \
- FIELD(0x01d0, float3x3, q, /*NO SUFFIX*/) \
- FIELD(0x0200, uint, r, /*NO SUFFIX*/) \
- FIELD(0x0204, int8_t, tint_pad_8, [12]) \
- FIELD(0x0210, float3x4, s, /*NO SUFFIX*/) \
- FIELD(0x0240, uint, t, /*NO SUFFIX*/) \
- FIELD(0x0244, int8_t, tint_pad_9, [4]) \
- FIELD(0x0248, float4x2, u, /*NO SUFFIX*/) \
- FIELD(0x0268, uint, v, /*NO SUFFIX*/) \
- FIELD(0x026c, int8_t, tint_pad_10, [4]) \
- FIELD(0x0270, float4x3, w, /*NO SUFFIX*/) \
- FIELD(0x02b0, uint, x, /*NO SUFFIX*/) \
- FIELD(0x02b4, int8_t, tint_pad_11, [12]) \
- FIELD(0x02c0, float4x4, y, /*NO SUFFIX*/) \
- FIELD(0x0300, float, z, /*NO SUFFIX*/) \
- FIELD(0x0304, int8_t, tint_pad_12, [124])
+#define ALL_FIELDS() \
+ FIELD(0x0000, int, 0, a) \
+ FIELD(0x0004, int8_t, 124, tint_pad) \
+ FIELD(0x0080, float, 0, b) \
+ FIELD(0x0084, int8_t, 124, tint_pad_1) \
+ FIELD(0x0100, float2, 0, c) \
+ FIELD(0x0108, uint, 0, d) \
+ FIELD(0x010c, int8_t, 4, tint_pad_2) \
+ FIELD(0x0110, packed_float3, 0, e) \
+ FIELD(0x011c, uint, 0, f) \
+ FIELD(0x0120, float4, 0, g) \
+ FIELD(0x0130, uint, 0, h) \
+ FIELD(0x0134, int8_t, 4, tint_pad_3) \
+ FIELD(0x0138, float2x2, 0, i) \
+ FIELD(0x0148, uint, 0, j) \
+ FIELD(0x014c, int8_t, 4, tint_pad_4) \
+ FIELD(0x0150, float2x3, 0, k) \
+ FIELD(0x0170, uint, 0, l) \
+ FIELD(0x0174, int8_t, 12, tint_pad_5) \
+ FIELD(0x0180, float2x4, 0, m) \
+ FIELD(0x01a0, uint, 0, n) \
+ FIELD(0x01a4, int8_t, 4, tint_pad_6) \
+ FIELD(0x01a8, float3x2, 0, o) \
+ FIELD(0x01c0, uint, 0, p) \
+ FIELD(0x01c4, int8_t, 12, tint_pad_7) \
+ FIELD(0x01d0, float3x3, 0, q) \
+ FIELD(0x0200, uint, 0, r) \
+ FIELD(0x0204, int8_t, 12, tint_pad_8) \
+ FIELD(0x0210, float3x4, 0, s) \
+ FIELD(0x0240, uint, 0, t) \
+ FIELD(0x0244, int8_t, 4, tint_pad_9) \
+ FIELD(0x0248, float4x2, 0, u) \
+ FIELD(0x0268, uint, 0, v) \
+ FIELD(0x026c, int8_t, 4, tint_pad_10) \
+ FIELD(0x0270, float4x3, 0, w) \
+ FIELD(0x02b0, uint, 0, x) \
+ FIELD(0x02b4, int8_t, 12, tint_pad_11) \
+ FIELD(0x02c0, float4x4, 0, y) \
+ FIELD(0x0300, float, 0, z) \
+ FIELD(0x0304, int8_t, 124, tint_pad_12)
// Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) " /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
- auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
+ std::stringstream expect;
+ expect << "struct S {\n";
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
+ FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
+ ALL_FIELDS()
#undef FIELD
- EXPECT_EQ(buf.String(), expect);
+ expect << "};\n";
+ EXPECT_EQ(buf.String(), expect.str());
// 1.4 Metal and C++14
// The Metal programming language is a C++14-based Specification with
@@ -304,12 +357,12 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
// layout is as expected for C++14 / MSL.
{
struct S {
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) TYPE NAME SUFFIX;
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) std::array<TYPE, ARRAY_COUNT ? ARRAY_COUNT : 1> NAME;
ALL_FIELDS()
#undef FIELD
};
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) \
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
ALL_FIELDS()
#undef FIELD
@@ -319,18 +372,18 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
// inner_x: size(1024), align(512)
- auto* inner_x = Structure("inner_x", {
+ auto* inner_x = Structure("inner_x", utils::Vector{
Member("a", ty.i32()),
- Member("b", ty.f32(), {MemberAlign(512)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(512)}),
});
// inner_y: size(516), align(4)
- auto* inner_y = Structure("inner_y", {
- Member("a", ty.i32(), {MemberSize(512)}),
+ auto* inner_y = Structure("inner_y", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberSize(512)}),
Member("b", ty.f32()),
});
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.Of(inner_x)),
Member("c", ty.f32()),
@@ -338,11 +391,11 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
Member("e", ty.f32()),
});
- Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -350,22 +403,26 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
- // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+ // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
-#define ALL_FIELDS() \
- FIELD(0x0000, int, a, /*NO SUFFIX*/) \
- FIELD(0x0004, int8_t, tint_pad, [508]) \
- FIELD(0x0200, inner_x, b, /*NO SUFFIX*/) \
- FIELD(0x0600, float, c, /*NO SUFFIX*/) \
- FIELD(0x0604, inner_y, d, /*NO SUFFIX*/) \
- FIELD(0x0808, float, e, /*NO SUFFIX*/) \
- FIELD(0x080c, int8_t, tint_pad_1, [500])
+#define ALL_FIELDS() \
+ FIELD(0x0000, int, 0, a) \
+ FIELD(0x0004, int8_t, 508, tint_pad) \
+ FIELD(0x0200, inner_x, 0, b) \
+ FIELD(0x0600, float, 0, c) \
+ FIELD(0x0604, inner_y, 0, d) \
+ FIELD(0x0808, float, 0, e) \
+ FIELD(0x080c, int8_t, 500, tint_pad_1)
// Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) " /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
- auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
+ std::stringstream expect;
+ expect << "struct S {\n";
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
+ FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
+ ALL_FIELDS()
#undef FIELD
- EXPECT_EQ(buf.String(), expect);
+ expect << "};\n";
+ EXPECT_EQ(buf.String(), expect.str());
// 1.4 Metal and C++14
// The Metal programming language is a C++14-based Specification with
@@ -389,12 +446,12 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
CHECK_TYPE_SIZE_AND_ALIGN(inner_y, 516, 4);
struct S {
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) TYPE NAME SUFFIX;
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) std::array<TYPE, ARRAY_COUNT ? ARRAY_COUNT : 1> NAME;
ALL_FIELDS()
#undef FIELD
};
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) \
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
ALL_FIELDS()
#undef FIELD
@@ -405,9 +462,9 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
// inner: size(1024), align(512)
- auto* inner = Structure("inner", {
+ auto* inner = Structure("inner", utils::Vector{
Member("a", ty.i32()),
- Member("b", ty.f32(), {MemberAlign(512)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(512)}),
});
// array_x: size(28), align(4)
@@ -419,7 +476,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
// array_z: size(4), align(4)
auto* array_z = ty.array<f32>();
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", array_x),
Member("c", ty.f32()),
@@ -428,11 +485,11 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
Member("f", array_z),
});
- Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -440,23 +497,27 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
- // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+ // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
-#define ALL_FIELDS() \
- FIELD(0x0000, int, a, /*NO SUFFIX*/) \
- FIELD(0x0004, float, b, [7]) \
- FIELD(0x0020, float, c, /*NO SUFFIX*/) \
- FIELD(0x0024, int8_t, tint_pad, [476]) \
- FIELD(0x0200, inner, d, [4]) \
- FIELD(0x1200, float, e, /*NO SUFFIX*/) \
- FIELD(0x1204, float, f, [1]) \
- FIELD(0x1208, int8_t, tint_pad_1, [504])
+#define ALL_FIELDS() \
+ FIELD(0x0000, int, 0, a) \
+ FIELD(0x0004, float, 7, b) \
+ FIELD(0x0020, float, 0, c) \
+ FIELD(0x0024, int8_t, 476, tint_pad) \
+ FIELD(0x0200, inner, 4, d) \
+ FIELD(0x1200, float, 0, e) \
+ FIELD(0x1204, float, 1, f) \
+ FIELD(0x1208, int8_t, 504, tint_pad_1)
// Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) " /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
- auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
+ std::stringstream expect;
+ expect << "struct S {\n";
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
+ FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
+ ALL_FIELDS()
#undef FIELD
- EXPECT_EQ(buf.String(), expect);
+ expect << "};\n";
+ EXPECT_EQ(buf.String(), expect.str());
// 1.4 Metal and C++14
// The Metal programming language is a C++14-based Specification with
@@ -486,12 +547,12 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
CHECK_TYPE_SIZE_AND_ALIGN(array_z, 4, 4);
struct S {
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) TYPE NAME SUFFIX;
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) std::array<TYPE, ARRAY_COUNT ? ARRAY_COUNT : 1> NAME;
ALL_FIELDS()
#undef FIELD
};
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) \
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
ALL_FIELDS()
#undef FIELD
@@ -504,17 +565,17 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayVec3DefaultStride) {
// array: size(64), align(16)
auto* array = ty.array(ty.vec3<f32>(), 4_u);
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", array),
Member("c", ty.i32()),
});
- Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -522,59 +583,63 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayVec3DefaultStride) {
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
- // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+ // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
-#define ALL_FIELDS() \
- FIELD(0x0000, int, a, /*NO SUFFIX*/) \
- FIELD(0x0004, int8_t, tint_pad, [12]) \
- FIELD(0x0010, float3, b, [4]) \
- FIELD(0x0050, int, c, /*NO SUFFIX*/) \
- FIELD(0x0054, int8_t, tint_pad_1, [12])
+#define ALL_FIELDS() \
+ FIELD(0x0000, int, 0, a) \
+ FIELD(0x0004, int8_t, 12, tint_pad) \
+ FIELD(0x0010, float3, 4, b) \
+ FIELD(0x0050, int, 0, c) \
+ FIELD(0x0054, int8_t, 12, tint_pad_1)
// Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) " /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
- auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
+ std::stringstream expect;
+ expect << "struct S {\n";
+#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
+ FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
+ ALL_FIELDS()
#undef FIELD
- EXPECT_EQ(buf.String(), expect);
+ expect << "};\n";
+ EXPECT_EQ(buf.String(), expect.str());
}
TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
- auto* s =
- Structure("S", {
- // uses symbols tint_pad_[0..9] and tint_pad_[20..35]
- Member("tint_pad_2", ty.i32(), {MemberSize(32)}),
- Member("tint_pad_20", ty.f32(), {MemberAlign(128), MemberSize(128)}),
- Member("tint_pad_33", ty.vec2<f32>()),
- Member("tint_pad_1", ty.u32()),
- Member("tint_pad_3", ty.vec3<f32>()),
- Member("tint_pad_7", ty.u32()),
- Member("tint_pad_25", ty.vec4<f32>()),
- Member("tint_pad_5", ty.u32()),
- Member("tint_pad_27", ty.mat2x2<f32>()),
- Member("tint_pad_24", ty.u32()),
- Member("tint_pad_23", ty.mat2x3<f32>()),
- Member("tint_pad", ty.u32()),
- Member("tint_pad_8", ty.mat2x4<f32>()),
- Member("tint_pad_26", ty.u32()),
- Member("tint_pad_29", ty.mat3x2<f32>()),
- Member("tint_pad_6", ty.u32()),
- Member("tint_pad_22", ty.mat3x3<f32>()),
- Member("tint_pad_32", ty.u32()),
- Member("tint_pad_34", ty.mat3x4<f32>()),
- Member("tint_pad_35", ty.u32()),
- Member("tint_pad_30", ty.mat4x2<f32>()),
- Member("tint_pad_9", ty.u32()),
- Member("tint_pad_31", ty.mat4x3<f32>()),
- Member("tint_pad_28", ty.u32()),
- Member("tint_pad_4", ty.mat4x4<f32>()),
- Member("tint_pad_21", ty.f32()),
- });
-
- Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure(
+ "S", utils::Vector{
+ // uses symbols tint_pad_[0..9] and tint_pad_[20..35]
+ Member("tint_pad_2", ty.i32(), utils::Vector{MemberSize(32)}),
+ Member("tint_pad_20", ty.f32(), utils::Vector{MemberAlign(128), MemberSize(128)}),
+ Member("tint_pad_33", ty.vec2<f32>()),
+ Member("tint_pad_1", ty.u32()),
+ Member("tint_pad_3", ty.vec3<f32>()),
+ Member("tint_pad_7", ty.u32()),
+ Member("tint_pad_25", ty.vec4<f32>()),
+ Member("tint_pad_5", ty.u32()),
+ Member("tint_pad_27", ty.mat2x2<f32>()),
+ Member("tint_pad_24", ty.u32()),
+ Member("tint_pad_23", ty.mat2x3<f32>()),
+ Member("tint_pad", ty.u32()),
+ Member("tint_pad_8", ty.mat2x4<f32>()),
+ Member("tint_pad_26", ty.u32()),
+ Member("tint_pad_29", ty.mat3x2<f32>()),
+ Member("tint_pad_6", ty.u32()),
+ Member("tint_pad_22", ty.mat3x3<f32>()),
+ Member("tint_pad_32", ty.u32()),
+ Member("tint_pad_34", ty.mat3x4<f32>()),
+ Member("tint_pad_35", ty.u32()),
+ Member("tint_pad_30", ty.mat4x2<f32>()),
+ Member("tint_pad_9", ty.u32()),
+ Member("tint_pad_31", ty.mat4x3<f32>()),
+ Member("tint_pad_28", ty.u32()),
+ Member("tint_pad_4", ty.mat4x4<f32>()),
+ Member("tint_pad_21", ty.f32()),
+ });
+
+ GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -583,59 +648,59 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
EXPECT_EQ(buf.String(), R"(struct S {
/* 0x0000 */ int tint_pad_2;
- /* 0x0004 */ int8_t tint_pad_10[124];
+ /* 0x0004 */ tint_array<int8_t, 124> tint_pad_10;
/* 0x0080 */ float tint_pad_20;
- /* 0x0084 */ int8_t tint_pad_11[124];
+ /* 0x0084 */ tint_array<int8_t, 124> tint_pad_11;
/* 0x0100 */ float2 tint_pad_33;
/* 0x0108 */ uint tint_pad_1;
- /* 0x010c */ int8_t tint_pad_12[4];
+ /* 0x010c */ tint_array<int8_t, 4> tint_pad_12;
/* 0x0110 */ packed_float3 tint_pad_3;
/* 0x011c */ uint tint_pad_7;
/* 0x0120 */ float4 tint_pad_25;
/* 0x0130 */ uint tint_pad_5;
- /* 0x0134 */ int8_t tint_pad_13[4];
+ /* 0x0134 */ tint_array<int8_t, 4> tint_pad_13;
/* 0x0138 */ float2x2 tint_pad_27;
/* 0x0148 */ uint tint_pad_24;
- /* 0x014c */ int8_t tint_pad_14[4];
+ /* 0x014c */ tint_array<int8_t, 4> tint_pad_14;
/* 0x0150 */ float2x3 tint_pad_23;
/* 0x0170 */ uint tint_pad;
- /* 0x0174 */ int8_t tint_pad_15[12];
+ /* 0x0174 */ tint_array<int8_t, 12> tint_pad_15;
/* 0x0180 */ float2x4 tint_pad_8;
/* 0x01a0 */ uint tint_pad_26;
- /* 0x01a4 */ int8_t tint_pad_16[4];
+ /* 0x01a4 */ tint_array<int8_t, 4> tint_pad_16;
/* 0x01a8 */ float3x2 tint_pad_29;
/* 0x01c0 */ uint tint_pad_6;
- /* 0x01c4 */ int8_t tint_pad_17[12];
+ /* 0x01c4 */ tint_array<int8_t, 12> tint_pad_17;
/* 0x01d0 */ float3x3 tint_pad_22;
/* 0x0200 */ uint tint_pad_32;
- /* 0x0204 */ int8_t tint_pad_18[12];
+ /* 0x0204 */ tint_array<int8_t, 12> tint_pad_18;
/* 0x0210 */ float3x4 tint_pad_34;
/* 0x0240 */ uint tint_pad_35;
- /* 0x0244 */ int8_t tint_pad_19[4];
+ /* 0x0244 */ tint_array<int8_t, 4> tint_pad_19;
/* 0x0248 */ float4x2 tint_pad_30;
/* 0x0268 */ uint tint_pad_9;
- /* 0x026c */ int8_t tint_pad_36[4];
+ /* 0x026c */ tint_array<int8_t, 4> tint_pad_36;
/* 0x0270 */ float4x3 tint_pad_31;
/* 0x02b0 */ uint tint_pad_28;
- /* 0x02b4 */ int8_t tint_pad_37[12];
+ /* 0x02b4 */ tint_array<int8_t, 12> tint_pad_37;
/* 0x02c0 */ float4x4 tint_pad_4;
/* 0x0300 */ float tint_pad_21;
- /* 0x0304 */ int8_t tint_pad_38[124];
+ /* 0x0304 */ tint_array<int8_t, 124> tint_pad_38;
};
)");
}
TEST_F(MslGeneratorImplTest, EmitType_Struct_WithAttribute) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
- Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -798,11 +863,11 @@ TEST_P(MslStorageTexturesTest, Emit) {
auto params = GetParam();
auto* s = ty.storage_texture(params.dim, ast::TexelFormat::kR32Float, ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_unary_op_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_unary_op_test.cc
index a1aecd9e643..21d63575b6c 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_unary_op_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@ namespace {
using MslUnaryOpTest = TestHelper;
TEST_F(MslUnaryOpTest, AddressOf) {
- Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.f32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
WrapInFunction(op);
@@ -32,7 +32,7 @@ TEST_F(MslUnaryOpTest, AddressOf) {
}
TEST_F(MslUnaryOpTest, Complement) {
- Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.i32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
WrapInFunction(op);
@@ -44,7 +44,7 @@ TEST_F(MslUnaryOpTest, Complement) {
}
TEST_F(MslUnaryOpTest, Indirection) {
- Global("G", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("G", ty.f32(), ast::StorageClass::kPrivate);
auto* p =
Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
@@ -58,7 +58,7 @@ TEST_F(MslUnaryOpTest, Indirection) {
}
TEST_F(MslUnaryOpTest, Not) {
- Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.bool_(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
WrapInFunction(op);
@@ -70,7 +70,7 @@ TEST_F(MslUnaryOpTest, Not) {
}
TEST_F(MslUnaryOpTest, Negation) {
- Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.i32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
WrapInFunction(op);
@@ -81,16 +81,15 @@ TEST_F(MslUnaryOpTest, Negation) {
EXPECT_EQ(out.str(), "tint_unary_minus(expr)");
}
-TEST_F(MslUnaryOpTest, NegationOfIntMin) {
- auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation,
- Expr(i32(std::numeric_limits<int32_t>::min())));
+TEST_F(MslUnaryOpTest, IntMin) {
+ auto* op = Expr(i32(std::numeric_limits<int32_t>::min()));
WrapInFunction(op);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
- EXPECT_EQ(out.str(), "tint_unary_minus((-2147483647 - 1))");
+ EXPECT_EQ(out.str(), "(-2147483647 - 1)");
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
index e41cc3b2813..726e63408fe 100644
--- a/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -38,7 +38,7 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement) {
EXPECT_EQ(gen.result(), " float a = 0.0f;\n");
}
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Let) {
auto* var = Let("a", ty.f32(), Construct(ty.f32()));
auto* stmt = Decl(var);
WrapInFunction(stmt);
@@ -51,6 +51,326 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
EXPECT_EQ(gen.result(), " float const a = 0.0f;\n");
}
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
+ auto* var = Const("a", ty.f32(), Construct(ty.f32()));
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), ""); // Not a mistake - 'const' is inlined
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_AInt) {
+ auto* C = Const("C", nullptr, Expr(1_a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_AFloat) {
+ auto* C = Const("C", nullptr, Expr(1._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_i32) {
+ auto* C = Const("C", nullptr, Expr(1_i));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_u32) {
+ auto* C = Const("C", nullptr, Expr(1_u));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ uint const l = 1u;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_f32) {
+ auto* C = Const("C", nullptr, Expr(1_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, Expr(1_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ half const l = 1.0h;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AInt) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ int3 const l = int3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f32) {
+ auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ half3 const l = half3(1.0h, 2.0h, 3.0h);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+ auto* C =
+ Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+ auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+ half2x3 const l = half2x3(half3(1.0h, 2.0h, 3.0h), half3(4.0h, 5.0h, 6.0h));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_f32) {
+ auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+void f() {
+ tint_array<float, 3> const l = tint_array<float, 3>{1.0f, 2.0f, 3.0f};
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+ auto* C = Const("C", nullptr,
+ Construct(ty.array(ty.vec2<bool>(), 3_u), //
+ vec2<bool>(true, false), //
+ vec2<bool>(false, true), //
+ vec2<bool>(true, true)));
+ Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+void f() {
+ tint_array<bool2, 3> const l = tint_array<bool2, 3>{bool2(true, false), bool2(false, true), bool2(true)};
+}
+
+)");
+}
+
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
auto* var = Var("a", ty.array<f32, 5>(), ast::StorageClass::kNone);
auto* stmt = Decl(var);
@@ -61,11 +381,11 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
gen.increment_indent();
ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
- EXPECT_EQ(gen.result(), " float a[5] = {0.0f};\n");
+ EXPECT_EQ(gen.result(), " tint_array<float, 5> a = {};\n");
}
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
@@ -83,7 +403,7 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
)");
}
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Vector) {
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Vector_f32) {
auto* var = Var("a", ty.vec2<f32>());
auto* stmt = Decl(var);
WrapInFunction(stmt);
@@ -96,7 +416,22 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Vector) {
EXPECT_EQ(gen.result(), " float2 a = 0.0f;\n");
}
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Matrix) {
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("a", ty.vec2<f16>());
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), " half2 a = 0.0h;\n");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Matrix_f32) {
auto* var = Var("a", ty.mat3x2<f32>());
auto* stmt = Decl(var);
@@ -110,57 +445,105 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Matrix) {
EXPECT_EQ(gen.result(), " float3x2 a = float3x2(0.0f);\n");
}
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Matrix_f16) {
+ Enable(ast::Extension::kF16);
- WrapInFunction(Expr("a"));
+ auto* var = Var("a", ty.mat3x2<f16>());
- GeneratorImpl& gen = SanitizeAndBuild();
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
gen.increment_indent();
- ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr("thread float tint_symbol_1 = 0.0f;\n"));
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), " half3x2 a = half3x2(0.0h);\n");
}
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_Private) {
- GlobalConst("initializer", ty.f32(), Expr(0_f));
- Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroVec_f32) {
+ auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
- WrapInFunction(Expr("a"));
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
- GeneratorImpl& gen = SanitizeAndBuild();
+ GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr("thread float tint_symbol_1 = 0.0f;\n float const tint_symbol = tint_symbol_1;\n return;\n"));
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), R"(float3 a = float3(0.0f);
+)");
}
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Workgroup) {
- Global("a", ty.f32(), ast::StorageClass::kWorkgroup);
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroVec_f16) {
+ Enable(ast::Extension::kF16);
- WrapInFunction(Expr("a"));
+ auto* var = Var("a", ty.vec3<f16>(), ast::StorageClass::kNone, vec3<f16>());
- GeneratorImpl& gen = SanitizeAndBuild();
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
- gen.increment_indent();
+ GeneratorImpl& gen = Build();
- ASSERT_TRUE(gen.Generate()) << gen.error();
- EXPECT_THAT(gen.result(), HasSubstr("threadgroup float tint_symbol_2;\n"));
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(), R"(half3 a = half3(0.0h);
+)");
}
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroVec) {
- auto* zero_vec = vec3<f32>();
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroMat_f32) {
+ auto* var = Var("a", ty.mat2x3<f32>(), ast::StorageClass::kNone, mat2x3<f32>());
- auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, zero_vec);
auto* stmt = Decl(var);
WrapInFunction(stmt);
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
- EXPECT_EQ(gen.result(), R"(float3 a = float3(0.0f);
+ EXPECT_EQ(gen.result(),
+ R"(float2x3 a = float2x3(float3(0.0f), float3(0.0f));
)");
}
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroMat_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("a", ty.mat2x3<f16>(), ast::StorageClass::kNone, mat2x3<f16>());
+
+ auto* stmt = Decl(var);
+ WrapInFunction(stmt);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+ EXPECT_EQ(gen.result(),
+ R"(half2x3 a = half2x3(half3(0.0h), half3(0.0h));
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
+
+ WrapInFunction(Expr("a"));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("thread float tint_symbol_1 = 0.0f;\n"));
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Workgroup) {
+ GlobalVar("a", ty.f32(), ast::StorageClass::kWorkgroup);
+
+ WrapInFunction(Expr("a"));
+
+ GeneratorImpl& gen = SanitizeAndBuild();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("threadgroup float tint_symbol_2;\n"));
+}
+
} // namespace
} // namespace tint::writer::msl
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder.cc
index 18f983af354..933b562bc5e 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder.cc
@@ -103,12 +103,18 @@ uint32_t builtin_to_glsl_method(const sem::Builtin* builtin) {
switch (builtin->Type()) {
case BuiltinType::kAcos:
return GLSLstd450Acos;
+ case BuiltinType::kAcosh:
+ return GLSLstd450Acosh;
case BuiltinType::kAsin:
return GLSLstd450Asin;
+ case BuiltinType::kAsinh:
+ return GLSLstd450Asinh;
case BuiltinType::kAtan:
return GLSLstd450Atan;
case BuiltinType::kAtan2:
return GLSLstd450Atan2;
+ case BuiltinType::kAtanh:
+ return GLSLstd450Atanh;
case BuiltinType::kCeil:
return GLSLstd450Ceil;
case BuiltinType::kClamp:
@@ -204,7 +210,6 @@ uint32_t builtin_to_glsl_method(const sem::Builtin* builtin) {
case BuiltinType::kSinh:
return GLSLstd450Sinh;
case BuiltinType::kSmoothstep:
- case BuiltinType::kSmoothStep:
return GLSLstd450SmoothStep;
case BuiltinType::kSqrt:
return GLSLstd450Sqrt;
@@ -374,22 +379,18 @@ void Builder::push_extension(const char* extension) {
}
bool Builder::GenerateExtension(ast::Extension extension) {
- /*
- For each supported extension, push corresponding capability into the builder.
- For example:
- if (kind == ast::Extension::Kind::kF16) {
- push_capability(SpvCapabilityFloat16);
- push_capability(SpvCapabilityUniformAndStorageBuffer16BitAccess);
- push_capability(SpvCapabilityStorageBuffer16BitAccess);
- push_capability(SpvCapabilityStorageInputOutput16);
- }
- */
switch (extension) {
- case ast::Extension::kChromiumExperimentalDP4a:
+ case ast::Extension::kChromiumExperimentalDp4A:
push_extension("SPV_KHR_integer_dot_product");
push_capability(SpvCapabilityDotProductKHR);
push_capability(SpvCapabilityDotProductInput4x8BitPackedKHR);
break;
+ case ast::Extension::kF16:
+ push_capability(SpvCapabilityFloat16);
+ push_capability(SpvCapabilityUniformAndStorageBuffer16BitAccess);
+ push_capability(SpvCapabilityStorageBuffer16BitAccess);
+ push_capability(SpvCapabilityStorageInputOutput16);
+ break;
default:
return false;
}
@@ -476,8 +477,8 @@ bool Builder::GenerateEntryPoint(const ast::Function* func, uint32_t id) {
for (const auto* var : func_sem->TransitivelyReferencedGlobals()) {
// For SPIR-V 1.3 we only output Input/output variables. If we update to
// SPIR-V 1.4 or later this should be all variables.
- if (var->StorageClass() != ast::StorageClass::kInput &&
- var->StorageClass() != ast::StorageClass::kOutput) {
+ if (var->StorageClass() != ast::StorageClass::kIn &&
+ var->StorageClass() != ast::StorageClass::kOut) {
continue;
}
@@ -528,18 +529,18 @@ bool Builder::GenerateExecutionModes(const ast::Function* func, uint32_t id) {
wgsize_ops.push_back(wgsize_result);
// Generate OpConstant instructions for each dimension.
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
auto constant = ScalarConstant::U32(wgsize[i].value);
if (wgsize[i].overridable_const) {
// Make the constant specializable.
auto* sem_const =
builder_.Sem().Get<sem::GlobalVariable>(wgsize[i].overridable_const);
- if (!sem_const->IsOverridable()) {
+ if (!sem_const->Declaration()->Is<ast::Override>()) {
TINT_ICE(Writer, builder_.Diagnostics())
<< "expected a pipeline-overridable constant";
}
constant.is_spec_op = true;
- constant.constant_id = sem_const->ConstantId();
+ constant.constant_id = sem_const->OverrideId().value;
}
auto result = GenerateConstantIfNeeded(constant);
@@ -562,7 +563,7 @@ bool Builder::GenerateExecutionModes(const ast::Function* func, uint32_t id) {
}
for (auto builtin : func_sem->TransitivelyReferencedBuiltinVariables()) {
- if (builtin.second->builtin == ast::Builtin::kFragDepth) {
+ if (builtin.second->builtin == ast::BuiltinValue::kFragDepth) {
push_execution_mode(spv::Op::OpExecutionMode,
{Operand(id), U32Operand(SpvExecutionModeDepthReplacing)});
}
@@ -693,20 +694,26 @@ uint32_t Builder::GenerateFunctionTypeIfNeeded(const sem::Function* func) {
});
}
-bool Builder::GenerateFunctionVariable(const ast::Variable* var) {
+bool Builder::GenerateFunctionVariable(const ast::Variable* v) {
+ if (v->Is<ast::Const>()) {
+ // Constants are generated at their use. This is required as the 'const' declaration may be
+ // abstract-numeric, which has no SPIR-V type.
+ return true;
+ }
+
uint32_t init_id = 0;
- if (var->constructor) {
- init_id = GenerateExpressionWithLoadIfNeeded(var->constructor);
+ if (v->constructor) {
+ init_id = GenerateExpressionWithLoadIfNeeded(v->constructor);
if (init_id == 0) {
return false;
}
}
- auto* sem = builder_.Sem().Get(var);
+ auto* sem = builder_.Sem().Get(v);
- if (var->is_const) {
- if (!var->constructor) {
- error_ = "missing constructor for constant";
+ if (v->Is<ast::Let>()) {
+ if (!v->constructor) {
+ error_ = "missing constructor for let";
return false;
}
RegisterVariable(sem, init_id);
@@ -722,8 +729,7 @@ bool Builder::GenerateFunctionVariable(const ast::Variable* var) {
return false;
}
- push_debug(spv::Op::OpName,
- {Operand(var_id), Operand(builder_.Symbols().NameFor(var->symbol))});
+ push_debug(spv::Op::OpName, {Operand(var_id), Operand(builder_.Symbols().NameFor(v->symbol))});
// TODO(dsinclair) We could detect if the constructor is fully const and emit
// an initializer value for the variable instead of doing the OpLoad.
@@ -734,7 +740,7 @@ bool Builder::GenerateFunctionVariable(const ast::Variable* var) {
push_function_var(
{Operand(type_id), result, U32Operand(ConvertStorageClass(sc)), Operand(null_id)});
- if (var->constructor) {
+ if (v->constructor) {
if (!GenerateStore(var_id, init_id)) {
return false;
}
@@ -749,66 +755,59 @@ bool Builder::GenerateStore(uint32_t to, uint32_t from) {
return push_function_inst(spv::Op::OpStore, {Operand(to), Operand(from)});
}
-bool Builder::GenerateGlobalVariable(const ast::Variable* var) {
- auto* sem = builder_.Sem().Get(var);
+bool Builder::GenerateGlobalVariable(const ast::Variable* v) {
+ if (v->Is<ast::Const>()) {
+ // Constants are generated at their use. This is required as the 'const' declaration may be
+ // abstract-numeric, which has no SPIR-V type.
+ return true;
+ }
+
+ auto* sem = builder_.Sem().Get(v);
auto* type = sem->Type()->UnwrapRef();
uint32_t init_id = 0;
- if (var->constructor) {
- if (!var->is_overridable) {
- auto* ctor = builder_.Sem().Get(var->constructor);
- if (auto constant = ctor->ConstantValue()) {
- init_id = GenerateConstantIfNeeded(std::move(constant));
- }
- }
- if (init_id == 0) {
- init_id = GenerateConstructorExpression(var, var->constructor);
- }
+ if (auto* ctor = v->constructor) {
+ init_id = GenerateConstructorExpression(v, ctor);
if (init_id == 0) {
return false;
}
}
- if (var->is_const) {
- if (!var->constructor) {
- // Constants must have an initializer unless they are overridable.
- if (!var->is_overridable) {
- error_ = "missing constructor for constant";
- return false;
- }
-
- // SPIR-V requires specialization constants to have initializers.
- init_id = Switch(
- type, //
- [&](const sem::F32*) {
- ast::FloatLiteralExpression l(ProgramID{}, Source{}, 0,
- ast::FloatLiteralExpression::Suffix::kF);
- return GenerateLiteralIfNeeded(var, &l);
- },
- [&](const sem::U32*) {
- ast::IntLiteralExpression l(ProgramID{}, Source{}, 0,
- ast::IntLiteralExpression::Suffix::kU);
- return GenerateLiteralIfNeeded(var, &l);
- },
- [&](const sem::I32*) {
- ast::IntLiteralExpression l(ProgramID{}, Source{}, 0,
- ast::IntLiteralExpression::Suffix::kI);
- return GenerateLiteralIfNeeded(var, &l);
- },
- [&](const sem::Bool*) {
- ast::BoolLiteralExpression l(ProgramID{}, Source{}, false);
- return GenerateLiteralIfNeeded(var, &l);
- },
- [&](Default) {
- error_ = "invalid type for pipeline constant ID, must be scalar";
- return 0;
- });
- if (init_id == 0) {
+ if (auto* override = v->As<ast::Override>(); override && !override->constructor) {
+ // SPIR-V requires specialization constants to have initializers.
+ init_id = Switch(
+ type, //
+ [&](const sem::F32*) {
+ ast::FloatLiteralExpression l(ProgramID{}, ast::NodeID{}, Source{}, 0,
+ ast::FloatLiteralExpression::Suffix::kF);
+ return GenerateLiteralIfNeeded(override, &l);
+ },
+ [&](const sem::U32*) {
+ ast::IntLiteralExpression l(ProgramID{}, ast::NodeID{}, Source{}, 0,
+ ast::IntLiteralExpression::Suffix::kU);
+ return GenerateLiteralIfNeeded(override, &l);
+ },
+ [&](const sem::I32*) {
+ ast::IntLiteralExpression l(ProgramID{}, ast::NodeID{}, Source{}, 0,
+ ast::IntLiteralExpression::Suffix::kI);
+ return GenerateLiteralIfNeeded(override, &l);
+ },
+ [&](const sem::Bool*) {
+ ast::BoolLiteralExpression l(ProgramID{}, ast::NodeID{}, Source{}, false);
+ return GenerateLiteralIfNeeded(override, &l);
+ },
+ [&](Default) {
+ error_ = "invalid type for pipeline constant ID, must be scalar";
return 0;
- }
+ });
+ if (init_id == 0) {
+ return 0;
}
+ }
+
+ if (v->Is<ast::Override>()) {
push_debug(spv::Op::OpName,
- {Operand(init_id), Operand(builder_.Symbols().NameFor(var->symbol))});
+ {Operand(init_id), Operand(builder_.Symbols().NameFor(v->symbol))});
RegisterVariable(sem, init_id);
return true;
@@ -825,12 +824,11 @@ bool Builder::GenerateGlobalVariable(const ast::Variable* var) {
return false;
}
- push_debug(spv::Op::OpName,
- {Operand(var_id), Operand(builder_.Symbols().NameFor(var->symbol))});
+ push_debug(spv::Op::OpName, {Operand(var_id), Operand(builder_.Symbols().NameFor(v->symbol))});
OperandList ops = {Operand(type_id), result, U32Operand(ConvertStorageClass(sc))};
- if (var->constructor) {
+ if (v->constructor) {
ops.push_back(Operand(init_id));
} else {
auto* st = type->As<sem::StorageTexture>();
@@ -858,7 +856,7 @@ bool Builder::GenerateGlobalVariable(const ast::Variable* var) {
// VK_KHR_zero_initialize_workgroup_memory extension is enabled, we should
// also zero-initialize.
if (sem->StorageClass() == ast::StorageClass::kPrivate ||
- sem->StorageClass() == ast::StorageClass::kOutput ||
+ sem->StorageClass() == ast::StorageClass::kOut ||
(zero_initialize_workgroup_memory_ &&
sem->StorageClass() == ast::StorageClass::kWorkgroup)) {
init_id = GenerateConstantNullIfNeeded(type);
@@ -872,7 +870,7 @@ bool Builder::GenerateGlobalVariable(const ast::Variable* var) {
push_type(spv::Op::OpVariable, std::move(ops));
- for (auto* attr : var->attributes) {
+ for (auto* attr : v->attributes) {
bool ok = Switch(
attr,
[&](const ast::BuiltinAttribute* builtin) {
@@ -957,7 +955,7 @@ bool Builder::GenerateIndexAccessor(const ast::IndexAccessorExpression* expr, Ac
Operand(result_type_id),
extract,
Operand(info->source_id),
- Operand(idx_constval.Element<uint32_t>(0)),
+ Operand(idx_constval->As<uint32_t>()),
})) {
return false;
}
@@ -1025,7 +1023,7 @@ bool Builder::GenerateMemberAccessor(const ast::MemberAccessorExpression* expr,
if (auto* swizzle = expr_sem->As<sem::Swizzle>()) {
// Single element swizzle is either an access chain or a composite extract
auto& indices = swizzle->Indices();
- if (indices.size() == 1) {
+ if (indices.Length() == 1) {
if (info->source_type->Is<sem::Reference>()) {
auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(indices[0]));
if (idx_id == 0) {
@@ -1288,8 +1286,16 @@ uint32_t Builder::GetGLSLstd450Import() {
uint32_t Builder::GenerateConstructorExpression(const ast::Variable* var,
const ast::Expression* expr) {
- if (auto* literal = expr->As<ast::LiteralExpression>()) {
- return GenerateLiteralIfNeeded(var, literal);
+ if (Is<ast::Override>(var)) {
+ if (auto* literal = expr->As<ast::LiteralExpression>()) {
+ return GenerateLiteralIfNeeded(var, literal);
+ }
+ } else {
+ if (auto* sem = builder_.Sem().Get(expr)) {
+ if (auto constant = sem->ConstantValue()) {
+ return GenerateConstantIfNeeded(constant);
+ }
+ }
}
if (auto* call = builder_.Sem().Get<sem::Call>(expr)) {
if (call->Target()->IsAnyOf<sem::TypeConstructor, sem::TypeConversion>()) {
@@ -1332,9 +1338,9 @@ uint32_t Builder::GenerateTypeConstructorOrConversion(const sem::Call* call,
auto* result_type = call->Type();
// Generate the zero initializer if there are no values provided.
- if (args.empty()) {
- if (global_var && global_var->IsOverridable()) {
- auto constant_id = global_var->ConstantId();
+ if (args.IsEmpty()) {
+ if (global_var && global_var->Declaration()->Is<ast::Override>()) {
+ auto constant_id = global_var->OverrideId().value;
if (result_type->Is<sem::I32>()) {
return GenerateConstantIfNeeded(ScalarConstant::I32(0).AsSpecOp(constant_id));
}
@@ -1344,6 +1350,9 @@ uint32_t Builder::GenerateTypeConstructorOrConversion(const sem::Call* call,
if (result_type->Is<sem::F32>()) {
return GenerateConstantIfNeeded(ScalarConstant::F32(0).AsSpecOp(constant_id));
}
+ if (result_type->Is<sem::F16>()) {
+ return GenerateConstantIfNeeded(ScalarConstant::F16(0).AsSpecOp(constant_id));
+ }
if (result_type->Is<sem::Bool>()) {
return GenerateConstantIfNeeded(ScalarConstant::Bool(false).AsSpecOp(constant_id));
}
@@ -1370,6 +1379,15 @@ uint32_t Builder::GenerateTypeConstructorOrConversion(const sem::Call* call,
}
}
+ if (auto* res_mat = result_type->As<sem::Matrix>()) {
+ auto* value_type = args[0]->Type()->UnwrapRef();
+ if (auto* val_mat = value_type->As<sem::Matrix>()) {
+ // Generate passthrough for matrices of the same type
+ can_cast_or_copy =
+ (res_mat->columns() == val_mat->columns()) && (res_mat->rows() == val_mat->rows());
+ }
+ }
+
if (can_cast_or_copy) {
return GenerateCastOrCopyOrPassthrough(result_type, args[0]->Declaration(), global_var);
}
@@ -1473,7 +1491,7 @@ uint32_t Builder::GenerateTypeConstructorOrConversion(const sem::Call* call,
// For a single-value vector initializer, splat the initializer value.
auto* const init_result_type = call->Type()->UnwrapRef();
- if (args.size() == 1 && init_result_type->is_scalar_vector() &&
+ if (args.Length() == 1 && init_result_type->is_scalar_vector() &&
args[0]->Type()->UnwrapRef()->is_scalar()) {
size_t vec_size = init_result_type->As<sem::Vector>()->Width();
for (size_t i = 0; i < (vec_size - 1); ++i) {
@@ -1541,22 +1559,23 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const sem::Type* to_type,
auto* from_type = TypeOf(from_expr)->UnwrapRef();
spv::Op op = spv::Op::OpNop;
- if ((from_type->Is<sem::I32>() && to_type->Is<sem::F32>()) ||
+ if ((from_type->Is<sem::I32>() && to_type->is_float_scalar()) ||
(from_type->is_signed_integer_vector() && to_type->is_float_vector())) {
op = spv::Op::OpConvertSToF;
- } else if ((from_type->Is<sem::U32>() && to_type->Is<sem::F32>()) ||
+ } else if ((from_type->Is<sem::U32>() && to_type->is_float_scalar()) ||
(from_type->is_unsigned_integer_vector() && to_type->is_float_vector())) {
op = spv::Op::OpConvertUToF;
- } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::I32>()) ||
+ } else if ((from_type->is_float_scalar() && to_type->Is<sem::I32>()) ||
(from_type->is_float_vector() && to_type->is_signed_integer_vector())) {
op = spv::Op::OpConvertFToS;
- } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::U32>()) ||
+ } else if ((from_type->is_float_scalar() && to_type->Is<sem::U32>()) ||
(from_type->is_float_vector() && to_type->is_unsigned_integer_vector())) {
op = spv::Op::OpConvertFToU;
} else if ((from_type->Is<sem::Bool>() && to_type->Is<sem::Bool>()) ||
(from_type->Is<sem::U32>() && to_type->Is<sem::U32>()) ||
(from_type->Is<sem::I32>() && to_type->Is<sem::I32>()) ||
(from_type->Is<sem::F32>() && to_type->Is<sem::F32>()) ||
+ (from_type->Is<sem::F16>() && to_type->Is<sem::F16>()) ||
(from_type->Is<sem::Vector>() && (from_type == to_type))) {
return val_id;
} else if ((from_type->Is<sem::I32>() && to_type->Is<sem::U32>()) ||
@@ -1589,6 +1608,9 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const sem::Type* to_type,
if (to_elem_type->Is<sem::F32>()) {
zero_id = GenerateConstantIfNeeded(ScalarConstant::F32(0));
one_id = GenerateConstantIfNeeded(ScalarConstant::F32(1));
+ } else if (to_elem_type->Is<sem::F16>()) {
+ zero_id = GenerateConstantIfNeeded(ScalarConstant::F16(0));
+ one_id = GenerateConstantIfNeeded(ScalarConstant::F16(1));
} else if (to_elem_type->Is<sem::U32>()) {
zero_id = GenerateConstantIfNeeded(ScalarConstant::U32(0));
one_id = GenerateConstantIfNeeded(ScalarConstant::U32(1));
@@ -1615,6 +1637,8 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const sem::Type* to_type,
}
return result_id;
+ } else if (from_type->Is<sem::Matrix>()) {
+ return val_id;
} else {
TINT_ICE(Writer, builder_.Diagnostics()) << "Invalid from_type";
}
@@ -1638,9 +1662,9 @@ uint32_t Builder::GenerateLiteralIfNeeded(const ast::Variable* var,
ScalarConstant constant;
auto* global = builder_.Sem().Get<sem::GlobalVariable>(var);
- if (global && global->IsOverridable()) {
+ if (global && global->Declaration()->Is<ast::Override>()) {
constant.is_spec_op = true;
- constant.constant_id = global->ConstantId();
+ constant.constant_id = global->OverrideId().value;
}
Switch(
@@ -1670,7 +1694,9 @@ uint32_t Builder::GenerateLiteralIfNeeded(const ast::Variable* var,
constant.value.f32 = static_cast<float>(f->value);
return;
case ast::FloatLiteralExpression::Suffix::kH:
- error_ = "Type f16 is not completely implemented yet";
+ constant.kind = ScalarConstant::Kind::kF16;
+ constant.value.f16 = {f16(static_cast<float>(f->value)).BitsRepresentation()};
+ return;
}
},
[&](Default) { error_ = "unknown literal type"; });
@@ -1682,93 +1708,34 @@ uint32_t Builder::GenerateLiteralIfNeeded(const ast::Variable* var,
return GenerateConstantIfNeeded(constant);
}
-uint32_t Builder::GenerateConstantIfNeeded(const sem::Constant& constant) {
- if (constant.AllZero()) {
- return GenerateConstantNullIfNeeded(constant.Type());
+uint32_t Builder::GenerateConstantIfNeeded(const sem::Constant* constant) {
+ if (constant->AllZero()) {
+ return GenerateConstantNullIfNeeded(constant->Type());
}
+ auto* ty = constant->Type();
- static constexpr size_t kOpsResultIdx = 1; // operand index of the result
- auto& global_scope = scope_stack_[0];
-
- auto gen_bool = [&](size_t element_idx) {
- bool val = constant.Element<AInt>(element_idx);
- return GenerateConstantIfNeeded(ScalarConstant::Bool(val));
- };
- auto gen_f32 = [&](size_t element_idx) {
- auto val = f32(constant.Element<AFloat>(element_idx));
- return GenerateConstantIfNeeded(ScalarConstant::F32(val.value));
- };
- auto gen_i32 = [&](size_t element_idx) {
- auto val = i32(constant.Element<AInt>(element_idx));
- return GenerateConstantIfNeeded(ScalarConstant::I32(val.value));
- };
- auto gen_u32 = [&](size_t element_idx) {
- auto val = u32(constant.Element<AInt>(element_idx));
- return GenerateConstantIfNeeded(ScalarConstant::U32(val.value));
- };
- auto gen_els = [&](std::vector<Operand>& ids, size_t start, size_t end, auto gen_el) {
- for (size_t i = start; i < end; i++) {
- auto id = gen_el(i);
- if (!id) {
- return false;
- }
- ids.emplace_back(id);
- }
- return true;
- };
- auto gen_vector = [&](const sem::Vector* ty, size_t start, size_t end) -> uint32_t {
+ auto composite = [&](size_t el_count) -> uint32_t {
auto type_id = GenerateTypeIfNeeded(ty);
if (!type_id) {
return 0;
}
- std::vector<Operand> ops;
- ops.reserve(end - start + 2);
- ops.emplace_back(type_id);
- ops.push_back(Operand(0u)); // Placeholder for the result ID
- auto ok = Switch(
- constant.ElementType(), //
- [&](const sem::Bool*) { return gen_els(ops, start, end, gen_bool); }, //
- [&](const sem::F32*) { return gen_els(ops, start, end, gen_f32); }, //
- [&](const sem::I32*) { return gen_els(ops, start, end, gen_i32); }, //
- [&](const sem::U32*) { return gen_els(ops, start, end, gen_u32); }, //
- [&](Default) {
- error_ = "unhandled constant element type: " + builder_.FriendlyName(ty);
- return false;
- });
- if (!ok) {
- return 0;
- }
-
- return utils::GetOrCreate(global_scope.type_ctor_to_id_, OperandListKey{ops},
- [&]() -> uint32_t {
- auto result = result_op();
- ops[kOpsResultIdx] = result;
- push_type(spv::Op::OpConstantComposite, std::move(ops));
- return std::get<uint32_t>(result);
- });
- };
- auto gen_matrix = [&](const sem::Matrix* m) -> uint32_t {
- auto mat_type_id = GenerateTypeIfNeeded(m);
- if (!mat_type_id) {
- return 0;
- }
+ static constexpr size_t kOpsResultIdx = 1; // operand index of the result
std::vector<Operand> ops;
- ops.reserve(m->columns() + 2);
- ops.emplace_back(mat_type_id);
+ ops.reserve(el_count + 2);
+ ops.emplace_back(type_id);
ops.push_back(Operand(0u)); // Placeholder for the result ID
- for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
- size_t start = m->rows() * column_idx;
- size_t end = m->rows() * (column_idx + 1);
- auto column_id = gen_vector(m->ColumnType(), start, end);
- if (!column_id) {
+ for (size_t i = 0; i < el_count; i++) {
+ auto id = GenerateConstantIfNeeded(constant->Index(i));
+ if (!id) {
return 0;
}
- ops.emplace_back(column_id);
+ ops.emplace_back(id);
}
+ auto& global_scope = scope_stack_[0];
return utils::GetOrCreate(global_scope.type_ctor_to_id_, OperandListKey{ops},
[&]() -> uint32_t {
auto result = result_op();
@@ -1779,15 +1746,33 @@ uint32_t Builder::GenerateConstantIfNeeded(const sem::Constant& constant) {
};
return Switch(
- constant.Type(), //
- [&](const sem::Bool*) { return gen_bool(0); }, //
- [&](const sem::F32*) { return gen_f32(0); }, //
- [&](const sem::I32*) { return gen_i32(0); }, //
- [&](const sem::U32*) { return gen_u32(0); }, //
- [&](const sem::Vector* v) { return gen_vector(v, 0, constant.ElementCount()); }, //
- [&](const sem::Matrix* m) { return gen_matrix(m); }, //
+ ty, //
+ [&](const sem::Bool*) {
+ bool val = constant->As<bool>();
+ return GenerateConstantIfNeeded(ScalarConstant::Bool(val));
+ },
+ [&](const sem::F32*) {
+ auto val = constant->As<f32>();
+ return GenerateConstantIfNeeded(ScalarConstant::F32(val.value));
+ },
+ [&](const sem::F16*) {
+ auto val = constant->As<f16>();
+ return GenerateConstantIfNeeded(ScalarConstant::F16(val.value));
+ },
+ [&](const sem::I32*) {
+ auto val = constant->As<i32>();
+ return GenerateConstantIfNeeded(ScalarConstant::I32(val.value));
+ },
+ [&](const sem::U32*) {
+ auto val = constant->As<u32>();
+ return GenerateConstantIfNeeded(ScalarConstant::U32(val.value));
+ },
+ [&](const sem::Vector* v) { return composite(v->Width()); },
+ [&](const sem::Matrix* m) { return composite(m->columns()); },
+ [&](const sem::Array* a) { return composite(a->Count()); },
+ [&](const sem::Struct* s) { return composite(s->Members().size()); },
[&](Default) {
- error_ = "unhandled constant type: " + builder_.FriendlyName(constant.Type());
+ error_ = "unhandled constant type: " + builder_.FriendlyName(ty);
return false;
});
}
@@ -1813,6 +1798,10 @@ uint32_t Builder::GenerateConstantIfNeeded(const ScalarConstant& constant) {
type_id = GenerateTypeIfNeeded(builder_.create<sem::F32>());
break;
}
+ case ScalarConstant::Kind::kF16: {
+ type_id = GenerateTypeIfNeeded(builder_.create<sem::F16>());
+ break;
+ }
case ScalarConstant::Kind::kBool: {
type_id = GenerateTypeIfNeeded(builder_.create<sem::Bool>());
break;
@@ -1847,6 +1836,12 @@ uint32_t Builder::GenerateConstantIfNeeded(const ScalarConstant& constant) {
{Operand(type_id), result, Operand(constant.value.f32)});
break;
}
+ case ScalarConstant::Kind::kF16: {
+ push_type(
+ constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
+ {Operand(type_id), result, U32Operand(constant.value.f16.bits_representation)});
+ break;
+ }
case ScalarConstant::Kind::kBool: {
if (constant.value.b) {
push_type(
@@ -2469,7 +2464,7 @@ uint32_t Builder::GenerateBuiltinCall(const sem::Call* call, const sem::Builtin*
}
// Runtime array must be the last member in the structure
params.push_back(
- Operand(uint32_t(type->As<sem::Struct>()->Declaration()->members.size() - 1)));
+ Operand(uint32_t(type->As<sem::Struct>()->Declaration()->members.Length() - 1)));
if (!push_function_inst(spv::Op::OpArrayLength, params)) {
return 0;
@@ -2672,7 +2667,7 @@ uint32_t Builder::GenerateBuiltinCall(const sem::Call* call, const sem::Builtin*
return 0;
}
- for (size_t i = 0; i < call->Arguments().size(); i++) {
+ for (size_t i = 0; i < call->Arguments().Length(); i++) {
if (auto val_id = get_arg_as_value_id(i)) {
params.emplace_back(Operand(val_id));
} else {
@@ -2705,7 +2700,7 @@ bool Builder::GenerateTextureBuiltin(const sem::Call* call,
// Returns the argument with the given usage
auto arg = [&](Usage usage) {
int idx = signature.IndexOf(usage);
- return (idx >= 0) ? arguments[idx] : nullptr;
+ return (idx >= 0) ? arguments[static_cast<size_t>(idx)] : nullptr;
};
// Generates the argument with the given usage, returning the operand ID
@@ -3177,8 +3172,8 @@ bool Builder::GenerateAtomicBuiltin(const sem::Call* call,
}
uint32_t value_id = 0;
- if (call->Arguments().size() > 1) {
- value_id = GenerateExpressionWithLoadIfNeeded(call->Arguments().back());
+ if (call->Arguments().Length() > 1) {
+ value_id = GenerateExpressionWithLoadIfNeeded(call->Arguments().Back());
if (value_id == 0) {
return false;
}
@@ -3280,7 +3275,8 @@ bool Builder::GenerateAtomicBuiltin(const sem::Call* call,
value,
});
case sem::BuiltinType::kAtomicCompareExchangeWeak: {
- auto comparator = GenerateExpression(call->Arguments()[1]->Declaration());
+ auto comparator =
+ GenerateExpressionWithLoadIfNeeded(call->Arguments()[1]->Declaration());
if (comparator == 0) {
return false;
}
@@ -3490,7 +3486,7 @@ bool Builder::GenerateIfStatement(const ast::IfStatement* stmt) {
// if (cond) {} else {break;}
// }
auto is_just_a_break = [](const ast::BlockStatement* block) {
- return block && (block->statements.size() == 1) &&
+ return block && (block->statements.Length() == 1) &&
block->Last()->Is<ast::BreakStatement>();
};
if (is_just_a_break(stmt->body) && stmt->else_statement == nullptr) {
@@ -3580,7 +3576,7 @@ bool Builder::GenerateSwitchStatement(const ast::SwitchStatement* stmt) {
// source. Each fallthrough goes to the next case entry, so is a forward
// branch, otherwise the branch is to the merge block which comes after
// the switch statement.
- for (uint32_t i = 0; i < body.size(); i++) {
+ for (uint32_t i = 0; i < body.Length(); i++) {
auto* item = body[i];
if (item->IsDefault()) {
@@ -3595,7 +3591,7 @@ bool Builder::GenerateSwitchStatement(const ast::SwitchStatement* stmt) {
}
if (LastIsFallthrough(item->body)) {
- if (i == (body.size() - 1)) {
+ if (i == (body.Length() - 1)) {
// This case is caught by Resolver validation
TINT_UNREACHABLE(Writer, builder_.Diagnostics());
return false;
@@ -3727,12 +3723,8 @@ bool Builder::GenerateLoopStatement(const ast::LoopStatement* stmt) {
bool Builder::GenerateStatement(const ast::Statement* stmt) {
return Switch(
stmt, [&](const ast::AssignmentStatement* a) { return GenerateAssignStatement(a); },
- [&](const ast::BlockStatement* b) { //
- return GenerateBlockStatement(b);
- },
- [&](const ast::BreakStatement* b) { //
- return GenerateBreakStatement(b);
- },
+ [&](const ast::BlockStatement* b) { return GenerateBlockStatement(b); },
+ [&](const ast::BreakStatement* b) { return GenerateBreakStatement(b); },
[&](const ast::CallStatement* c) { return GenerateCallExpression(c->expr) != 0; },
[&](const ast::ContinueStatement* c) { return GenerateContinueStatement(c); },
[&](const ast::DiscardStatement* d) { return GenerateDiscardStatement(d); },
@@ -3740,19 +3732,14 @@ bool Builder::GenerateStatement(const ast::Statement* stmt) {
// Do nothing here, the fallthrough gets handled by the switch code.
return true;
},
- [&](const ast::IfStatement* i) { //
- return GenerateIfStatement(i);
- },
- [&](const ast::LoopStatement* l) { //
- return GenerateLoopStatement(l);
- },
- [&](const ast::ReturnStatement* r) { //
- return GenerateReturnStatement(r);
- },
- [&](const ast::SwitchStatement* s) { //
- return GenerateSwitchStatement(s);
- },
+ [&](const ast::IfStatement* i) { return GenerateIfStatement(i); },
+ [&](const ast::LoopStatement* l) { return GenerateLoopStatement(l); },
+ [&](const ast::ReturnStatement* r) { return GenerateReturnStatement(r); },
+ [&](const ast::SwitchStatement* s) { return GenerateSwitchStatement(s); },
[&](const ast::VariableDeclStatement* v) { return GenerateVariableDeclStatement(v); },
+ [&](const ast::StaticAssert*) {
+ return true; // Not emitted
+ },
[&](Default) {
error_ = "Unknown statement: " + std::string(stmt->TypeInfo().name);
return false;
@@ -3819,9 +3806,8 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
return true;
},
[&](const sem::F16*) {
- // Should be `push_type(spv::Op::OpTypeFloat, {result, Operand(16u)});`
- error_ = "Type f16 is not completely implemented yet.";
- return false;
+ push_type(spv::Op::OpTypeFloat, {result, Operand(16u)});
+ return true;
},
[&](const sem::I32*) {
push_type(spv::Op::OpTypeInt, {result, Operand(32u), Operand(1u)});
@@ -4118,14 +4104,16 @@ SpvStorageClass Builder::ConvertStorageClass(ast::StorageClass klass) const {
switch (klass) {
case ast::StorageClass::kInvalid:
return SpvStorageClassMax;
- case ast::StorageClass::kInput:
+ case ast::StorageClass::kIn:
return SpvStorageClassInput;
- case ast::StorageClass::kOutput:
+ case ast::StorageClass::kOut:
return SpvStorageClassOutput;
case ast::StorageClass::kUniform:
return SpvStorageClassUniform;
case ast::StorageClass::kWorkgroup:
return SpvStorageClassWorkgroup;
+ case ast::StorageClass::kPushConstant:
+ return SpvStorageClassPushConstant;
case ast::StorageClass::kHandle:
return SpvStorageClassUniformConstant;
case ast::StorageClass::kStorage:
@@ -4140,43 +4128,43 @@ SpvStorageClass Builder::ConvertStorageClass(ast::StorageClass klass) const {
return SpvStorageClassMax;
}
-SpvBuiltIn Builder::ConvertBuiltin(ast::Builtin builtin, ast::StorageClass storage) {
+SpvBuiltIn Builder::ConvertBuiltin(ast::BuiltinValue builtin, ast::StorageClass storage) {
switch (builtin) {
- case ast::Builtin::kPosition:
- if (storage == ast::StorageClass::kInput) {
+ case ast::BuiltinValue::kPosition:
+ if (storage == ast::StorageClass::kIn) {
return SpvBuiltInFragCoord;
- } else if (storage == ast::StorageClass::kOutput) {
+ } else if (storage == ast::StorageClass::kOut) {
return SpvBuiltInPosition;
} else {
TINT_ICE(Writer, builder_.Diagnostics()) << "invalid storage class for builtin";
break;
}
- case ast::Builtin::kVertexIndex:
+ case ast::BuiltinValue::kVertexIndex:
return SpvBuiltInVertexIndex;
- case ast::Builtin::kInstanceIndex:
+ case ast::BuiltinValue::kInstanceIndex:
return SpvBuiltInInstanceIndex;
- case ast::Builtin::kFrontFacing:
+ case ast::BuiltinValue::kFrontFacing:
return SpvBuiltInFrontFacing;
- case ast::Builtin::kFragDepth:
+ case ast::BuiltinValue::kFragDepth:
return SpvBuiltInFragDepth;
- case ast::Builtin::kLocalInvocationId:
+ case ast::BuiltinValue::kLocalInvocationId:
return SpvBuiltInLocalInvocationId;
- case ast::Builtin::kLocalInvocationIndex:
+ case ast::BuiltinValue::kLocalInvocationIndex:
return SpvBuiltInLocalInvocationIndex;
- case ast::Builtin::kGlobalInvocationId:
+ case ast::BuiltinValue::kGlobalInvocationId:
return SpvBuiltInGlobalInvocationId;
- case ast::Builtin::kPointSize:
+ case ast::BuiltinValue::kPointSize:
return SpvBuiltInPointSize;
- case ast::Builtin::kWorkgroupId:
+ case ast::BuiltinValue::kWorkgroupId:
return SpvBuiltInWorkgroupId;
- case ast::Builtin::kNumWorkgroups:
+ case ast::BuiltinValue::kNumWorkgroups:
return SpvBuiltInNumWorkgroups;
- case ast::Builtin::kSampleIndex:
+ case ast::BuiltinValue::kSampleIndex:
push_capability(SpvCapabilitySampleRateShading);
return SpvBuiltInSampleId;
- case ast::Builtin::kSampleMask:
+ case ast::BuiltinValue::kSampleMask:
return SpvBuiltInSampleMask;
- case ast::Builtin::kNone:
+ case ast::BuiltinValue::kInvalid:
break;
}
return SpvBuiltInMax;
@@ -4246,7 +4234,7 @@ SpvImageFormat Builder::convert_texel_format_to_spv(const ast::TexelFormat forma
return SpvImageFormatRgba32i;
case ast::TexelFormat::kRgba32Float:
return SpvImageFormatRgba32f;
- case ast::TexelFormat::kNone:
+ case ast::TexelFormat::kInvalid:
return SpvImageFormatUnknown;
}
return SpvImageFormatUnknown;
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder.h b/chromium/third_party/dawn/src/tint/writer/spirv/builder.h
index 9866328a59b..a0eff107bcf 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder.h
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder.h
@@ -211,7 +211,7 @@ class Builder {
/// @param builtin the builtin to convert
/// @param storage the storage class that this builtin is being used with
/// @returns the SPIR-V builtin or SpvBuiltInMax on error.
- SpvBuiltIn ConvertBuiltin(ast::Builtin builtin, ast::StorageClass storage);
+ SpvBuiltIn ConvertBuiltin(ast::BuiltinValue builtin, ast::StorageClass storage);
/// Converts an interpolate attribute to SPIR-V decorations and pushes a
/// capability if needed.
@@ -554,7 +554,7 @@ class Builder {
/// Generates a constant value if needed
/// @param constant the constant to generate.
/// @returns the ID on success or 0 on failure
- uint32_t GenerateConstantIfNeeded(const sem::Constant& constant);
+ uint32_t GenerateConstantIfNeeded(const sem::Constant* constant);
/// Generates a scalar constant if needed
/// @param constant the constant to generate.
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_accessor_expression_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_accessor_expression_test.cc
index 2df1b6585ff..0c0dc3f124f 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_accessor_expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_accessor_expression_test.cc
@@ -22,193 +22,874 @@ namespace {
using BuilderTest = TestHelper;
-TEST_F(BuilderTest, IndexAccessor_VectorRef_Literal) {
- // var ary : vec3<f32>;
- // ary[1] -> ref<f32>
+TEST_F(BuilderTest, Let_IndexAccessor_Vector) {
+ // let ary = vec3<i32>(1, 2, 3);
+ // var x = ary[1i];
- auto* var = Var("ary", ty.vec3<f32>());
+ auto* ary = Let("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
+ auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
+ WrapInFunction(ary, x);
- auto* ary = Expr("ary");
- auto* idx_expr = Expr(1_i);
+ spirv::Builder& b = SanitizeAndBuild();
- auto* expr = IndexAccessor(ary, idx_expr);
- WrapInFunction(var, expr);
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 1
+%8 = OpConstant %6 2
+%9 = OpConstant %6 3
+%10 = OpConstantComposite %5 %7 %8 %9
+%13 = OpTypePointer Function %6
+%14 = OpConstantNull %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%12 = OpVariable %13 Function %14
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%11 = OpCompositeExtract %6 %10 1
+OpStore %12 %11
+OpReturn
+)");
+
+ Validate(b);
+}
- spirv::Builder& b = Build();
+TEST_F(BuilderTest, Const_IndexAccessor_Vector) {
+ // const ary = vec3<i32>(1, 2, 3);
+ // var x = ary[1i];
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ auto* ary = Const("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
+ auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
+ WrapInFunction(ary, x);
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeInt 32 1
-%7 = OpConstant %6 1
-%8 = OpTypePointer Function %4
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeInt 32 1
+%6 = OpConstant %5 2
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%7 = OpVariable %8 Function %9
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpAccessChain %8 %1 %7
+ R"(OpStore %7 %6
+OpReturn
)");
+
+ Validate(b);
}
-TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic) {
+TEST_F(BuilderTest, Runtime_IndexAccessor_Vector) {
+ // var ary : vec3<u32>;
+ // var x = ary[1i];
+
+ auto* ary = Var("ary", ty.vec3<u32>());
+ auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
+ WrapInFunction(ary, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 1
+%11 = OpConstant %10 1
+%12 = OpTypePointer Function %8
+%16 = OpConstantNull %8
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%15 = OpVariable %12 Function %16
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
+%14 = OpLoad %8 %13
+OpStore %15 %14
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Vector) {
// var ary : vec3<f32>;
// var idx : i32;
- // ary[idx] -> ref<f32>
+ // var x = ary[idx];
- auto* var = Var("ary", ty.vec3<f32>());
+ auto* ary = Var("ary", ty.vec3<f32>());
auto* idx = Var("idx", ty.i32());
+ auto* x = Var("x", nullptr, IndexAccessor(ary, idx));
+ WrapInFunction(ary, idx, x);
- auto* ary = Expr("ary");
- auto* idx_expr = Expr("idx");
+ spirv::Builder& b = SanitizeAndBuild();
- auto* expr = IndexAccessor(ary, idx_expr);
- WrapInFunction(var, idx, expr);
+ ASSERT_TRUE(b.Build()) << b.error();
- spirv::Builder& b = Build();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypeInt 32 1
+%11 = OpTypePointer Function %12
+%13 = OpConstantNull %12
+%15 = OpTypePointer Function %8
+%19 = OpConstantNull %8
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%10 = OpVariable %11 Function %13
+%18 = OpVariable %15 Function %19
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%14 = OpLoad %12 %10
+%16 = OpAccessChain %15 %5 %14
+%17 = OpLoad %8 %16
+OpStore %18 %17
+OpReturn
+)");
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
+ Validate(b);
+}
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 12u);
+TEST_F(BuilderTest, Const_IndexAccessor_Vector2) {
+ // let ary : vec3<i32>(1, 2, 3);
+ // var x = ary[1i + 1i];
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%8 = OpTypeInt 32 1
-%7 = OpTypePointer Function %8
-%9 = OpConstantNull %8
-%11 = OpTypePointer Function %4
+ auto* ary = Let("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
+ auto* x = Var("x", nullptr, IndexAccessor(ary, Add(1_i, 1_i)));
+ WrapInFunction(ary, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 1
+%8 = OpConstant %6 2
+%9 = OpConstant %6 3
+%10 = OpConstantComposite %5 %7 %8 %9
+%13 = OpTypePointer Function %6
+%14 = OpConstantNull %6
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
-%6 = OpVariable %7 Function %9
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%12 = OpVariable %13 Function %14
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%10 = OpLoad %8 %6
-%12 = OpAccessChain %11 %1 %10
+ R"(%11 = OpCompositeExtract %6 %10 2
+OpStore %12 %11
+OpReturn
)");
+
+ Validate(b);
}
-TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic2) {
+TEST_F(BuilderTest, Runtime_IndexAccessor_Vector2) {
// var ary : vec3<f32>;
- // ary[1 + 2] -> ref<f32>
+ // var x = ary[1i + 1i];
- auto* var = Var("ary", ty.vec3<f32>());
+ auto* ary = Var("ary", ty.vec3<f32>());
+ auto* x = Var("x", nullptr, IndexAccessor(ary, Add(1_i, 1_i)));
+ WrapInFunction(ary, x);
- auto* ary = Expr("ary");
+ spirv::Builder& b = SanitizeAndBuild();
- auto* expr = IndexAccessor(ary, Add(1_i, 2_i));
- WrapInFunction(var, expr);
+ ASSERT_TRUE(b.Build()) << b.error();
- spirv::Builder& b = Build();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 1
+%11 = OpConstant %10 2
+%12 = OpTypePointer Function %8
+%16 = OpConstantNull %8
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%15 = OpVariable %12 Function %16
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
+%14 = OpLoad %8 %13
+OpStore %15 %14
+OpReturn
+)");
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ Validate(b);
+}
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Vector2) {
+ // var ary : vec3<f32>;
+ // var one = 1i;
+ // var x = ary[one + 2i];
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeInt 32 1
-%7 = OpConstant %6 1
-%8 = OpConstant %6 2
-%10 = OpTypePointer Function %4
+ auto* ary = Var("ary", ty.vec3<f32>());
+ auto* one = Var("one", nullptr, Expr(1_i));
+ auto* x = Var("x", nullptr, IndexAccessor(ary, Add(one, 2_i)));
+ WrapInFunction(ary, one, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 1
+%11 = OpConstant %10 1
+%13 = OpTypePointer Function %10
+%14 = OpConstantNull %10
+%16 = OpConstant %10 2
+%18 = OpTypePointer Function %8
+%22 = OpConstantNull %8
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%12 = OpVariable %13 Function %14
+%21 = OpVariable %18 Function %22
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %12 %11
+%15 = OpLoad %10 %12
+%17 = OpIAdd %10 %15 %16
+%19 = OpAccessChain %18 %5 %17
+%20 = OpLoad %8 %19
+OpStore %21 %20
+OpReturn
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Let_IndexAccessor_Array_MultiLevel) {
+ // let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
+ // var x = ary[1i][2i];
+
+ auto* ary =
+ Let("ary", nullptr,
+ array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
+ WrapInFunction(ary, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 3
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 2
+%5 = OpTypeArray %6 %9
+%10 = OpConstant %7 1
+%11 = OpConstant %7 2
+%12 = OpConstant %7 3
+%13 = OpConstantComposite %6 %10 %11 %12
+%14 = OpConstant %7 4
+%15 = OpConstant %7 5
+%16 = OpConstant %7 6
+%17 = OpConstantComposite %6 %14 %15 %16
+%18 = OpConstantComposite %5 %13 %17
+%19 = OpTypeInt 32 1
+%20 = OpConstant %19 1
+%22 = OpConstant %19 2
+%25 = OpTypePointer Function %7
+%26 = OpConstantNull %7
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%24 = OpVariable %25 Function %26
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpIAdd %6 %7 %8
-%11 = OpAccessChain %10 %1 %9
+ R"(%21 = OpCompositeExtract %6 %18 1
+%23 = OpCompositeExtract %7 %21 2
+OpStore %24 %23
+OpReturn
)");
+
+ Validate(b);
}
-TEST_F(BuilderTest, IndexAccessor_ArrayRef_MultiLevel) {
- auto* ary4 = ty.array(ty.vec3<f32>(), 4_u);
+TEST_F(BuilderTest, Const_IndexAccessor_Array_MultiLevel) {
+ // const ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
+ // var x = ary[1i][2i];
- // var ary : array<vec3<f32>, 4u>
- // ary[3i][2i];
+ auto* ary =
+ Const("ary", nullptr,
+ array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
+ WrapInFunction(ary, x);
- auto* var = Var("ary", ary4);
+ spirv::Builder& b = SanitizeAndBuild();
- auto* expr = IndexAccessor(IndexAccessor("ary", 3_i), 2_i);
- WrapInFunction(var, expr);
+ ASSERT_TRUE(b.Build()) << b.error();
- spirv::Builder& b = Build();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 6
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%7 = OpVariable %8 Function %9
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %7 %6
+OpReturn
+)");
+
+ Validate(b);
+}
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+TEST_F(BuilderTest, Runtime_IndexAccessor_Array_MultiLevel) {
+ // var ary : array<vec3<f32>, 4u>;
+ // var x = ary[1i][2i];
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 13u);
+ auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
+ WrapInFunction(ary, x);
- EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeVector %5 3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 4
-%3 = OpTypeArray %4 %7
-%2 = OpTypePointer Function %3
-%8 = OpConstantNull %3
-%9 = OpTypeInt 32 1
-%10 = OpConstant %9 3
-%11 = OpConstant %9 2
-%12 = OpTypePointer Function %5
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 1
+%15 = OpConstant %13 2
+%16 = OpTypePointer Function %9
+%20 = OpConstantNull %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %8
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%19 = OpVariable %16 Function %20
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%13 = OpAccessChain %12 %1 %10 %11
+ R"(%17 = OpAccessChain %16 %5 %14 %15
+%18 = OpLoad %9 %17
+OpStore %19 %18
+OpReturn
)");
+
+ Validate(b);
}
-TEST_F(BuilderTest, IndexAccessor_ArrayRef_ArrayWithSwizzle) {
- auto* ary4 = ty.array(ty.vec3<f32>(), 4_u);
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Array_MultiLevel) {
+ // var ary : array<vec3<f32>, 4u>;
+ // var one = 1i;
+ // var x = ary[one][2i];
- // var a : array<vec3<f32>, 4u>;
- // a[2i].xy;
+ auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+ auto* one = Var("one", nullptr, Expr(3_i));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, one), 2_i));
+ WrapInFunction(ary, one, x);
- auto* var = Var("ary", ary4);
+ spirv::Builder& b = SanitizeAndBuild();
- auto* expr = MemberAccessor(IndexAccessor("ary", 2_i), "xy");
- WrapInFunction(var, expr);
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 3
+%16 = OpTypePointer Function %13
+%17 = OpConstantNull %13
+%19 = OpConstant %13 2
+%20 = OpTypePointer Function %9
+%24 = OpConstantNull %9
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%15 = OpVariable %16 Function %17
+%23 = OpVariable %20 Function %24
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %14
+%18 = OpLoad %13 %15
+%21 = OpAccessChain %20 %5 %18 %19
+%22 = OpLoad %9 %21
+OpStore %23 %22
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Array_ArrayWithSwizzle) {
+ // let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
+ // var x = a[1i].xy;
+
+ auto* ary =
+ Let("ary", nullptr,
+ array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
+ auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
+ WrapInFunction(ary, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 3
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 2
+%5 = OpTypeArray %6 %9
+%10 = OpConstant %7 1
+%11 = OpConstant %7 2
+%12 = OpConstant %7 3
+%13 = OpConstantComposite %6 %10 %11 %12
+%14 = OpConstant %7 4
+%15 = OpConstant %7 5
+%16 = OpConstant %7 6
+%17 = OpConstantComposite %6 %14 %15 %16
+%18 = OpConstantComposite %5 %13 %17
+%19 = OpTypeInt 32 1
+%20 = OpConstant %19 1
+%22 = OpTypeVector %7 2
+%25 = OpTypePointer Function %22
+%26 = OpConstantNull %22
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%24 = OpVariable %25 Function %26
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%21 = OpCompositeExtract %6 %18 1
+%23 = OpVectorShuffle %22 %21 %21 0 1
+OpStore %24 %23
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Array_ArrayWithSwizzle) {
+ // var ary : array<vec3<f32>, 4u>;
+ // var x = ary[1i].xy;
+
+ auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+ auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
+ WrapInFunction(ary, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 1
+%15 = OpTypePointer Function %8
+%17 = OpTypeVector %9 2
+%21 = OpTypePointer Function %17
+%22 = OpConstantNull %17
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%20 = OpVariable %21 Function %22
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%16 = OpAccessChain %15 %5 %14
+%18 = OpLoad %8 %16
+%19 = OpVectorShuffle %17 %18 %18 0 1
+OpStore %20 %19
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Array_ArrayWithSwizzle) {
+ // var ary : array<vec3<f32>, 4u>;
+ // var one = 1i;
+ // var x = ary[one].xy;
+
+ auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+ auto* one = Var("one", nullptr, Expr(1_i));
+ auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", one), "xy"));
+ WrapInFunction(ary, one, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 1
+%16 = OpTypePointer Function %13
+%17 = OpConstantNull %13
+%19 = OpTypePointer Function %8
+%21 = OpTypeVector %9 2
+%25 = OpTypePointer Function %21
+%26 = OpConstantNull %21
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%15 = OpVariable %16 Function %17
+%24 = OpVariable %25 Function %26
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %14
+%18 = OpLoad %13 %15
+%20 = OpAccessChain %19 %5 %18
+%22 = OpLoad %8 %20
+%23 = OpVectorShuffle %21 %22 %22 0 1
+OpStore %24 %23
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Let_IndexAccessor_Nested_Array_f32) {
+ // let pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
+ // array<f32, 2>(0.0, 0.5),
+ // array<f32, 2>(-0.5, -0.5),
+ // array<f32, 2>(0.5, -0.5));
+ // var x = pos[1u][0u];
+
+ auto* pos = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
+ Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
+ vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 0_u));
+ WrapInFunction(pos, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 2
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 3
+%5 = OpTypeArray %6 %9
+%10 = OpConstantNull %7
+%11 = OpConstant %7 0.5
+%12 = OpConstantComposite %6 %10 %11
+%13 = OpConstant %7 -0.5
+%14 = OpConstantComposite %6 %13 %13
+%15 = OpConstantComposite %6 %11 %13
+%16 = OpConstantComposite %5 %12 %14 %15
+%17 = OpConstant %8 1
+%19 = OpConstantNull %8
+%22 = OpTypePointer Function %7
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%21 = OpVariable %22 Function %10
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%18 = OpCompositeExtract %6 %16 1
+%20 = OpCompositeExtract %7 %18 0
+OpStore %21 %20
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Nested_Array_f32) {
+ // const pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
+ // array<f32, 2>(0.0, 0.5),
+ // array<f32, 2>(-0.5, -0.5),
+ // array<f32, 2>(0.5, -0.5));
+ // var x = pos[1u][0u];
+
+ auto* pos = Const("pos", ty.array(ty.vec2<f32>(), 3_u),
+ Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
+ vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 0_u));
+ WrapInFunction(pos, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 -0.5
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%7 = OpVariable %8 Function %9
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %7 %6
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Nested_Array_f32) {
+ // var pos : array<array<f32, 2>, 3u>;
+ // var x = pos[1u][2u];
+
+ auto* pos = Var("pos", ty.array(ty.vec2<f32>(), 3_u));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 2_u));
+ WrapInFunction(pos, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 3
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpConstant %10 1
+%14 = OpConstant %10 2
+%15 = OpTypePointer Function %9
+%19 = OpConstantNull %9
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%18 = OpVariable %15 Function %19
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%16 = OpAccessChain %15 %5 %13 %14
+%17 = OpLoad %9 %16
+OpStore %18 %17
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Nested_Array_f32) {
+ // var pos : array<array<f32, 2>, 3u>;
+ // var one = 1u;
+ // var x = pos[one][2u];
+
+ auto* pos = Var("pos", ty.array(ty.vec2<f32>(), 3_u));
+ auto* one = Var("one", nullptr, Expr(2_u));
+ auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, "one"), 2_u));
+ WrapInFunction(pos, one, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 3
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpConstant %10 2
+%15 = OpTypePointer Function %10
+%16 = OpConstantNull %10
+%18 = OpTypePointer Function %9
+%22 = OpConstantNull %9
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%14 = OpVariable %15 Function %16
+%21 = OpVariable %18 Function %22
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %14 %13
+%17 = OpLoad %10 %14
+%19 = OpAccessChain %18 %5 %17 %13
+%20 = OpLoad %9 %19
+OpStore %21 %20
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Let_IndexAccessor_Matrix) {
+ // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
+ // var x = a[1i]
+
+ auto* a = Let("a", ty.mat2x2<f32>(),
+ Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1_f, 2_f),
+ Construct(ty.vec2<f32>(), 3_f, 4_f)));
+ auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
+ WrapInFunction(a, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 2
+%5 = OpTypeMatrix %6 2
+%8 = OpConstant %7 1
+%9 = OpConstant %7 2
+%10 = OpConstantComposite %6 %8 %9
+%11 = OpConstant %7 3
+%12 = OpConstant %7 4
+%13 = OpConstantComposite %6 %11 %12
+%14 = OpConstantComposite %5 %10 %13
+%15 = OpTypeInt 32 1
+%16 = OpConstant %15 1
+%19 = OpTypePointer Function %6
+%20 = OpConstantNull %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%18 = OpVariable %19 Function %20
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%17 = OpCompositeExtract %6 %14 1
+OpStore %18 %17
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Matrix) {
+ // const a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
+ // var x = a[1i]
+
+ auto* a = Const("a", ty.mat2x2<f32>(),
+ Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1_f, 2_f),
+ Construct(ty.vec2<f32>(), 3_f, 4_f)));
+ auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
+ WrapInFunction(a, x);
- spirv::Builder& b = Build();
+ spirv::Builder& b = SanitizeAndBuild();
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 15u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeVector %5 3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 4
-%3 = OpTypeArray %4 %7
-%2 = OpTypePointer Function %3
-%8 = OpConstantNull %3
-%9 = OpTypeInt 32 1
-%10 = OpConstant %9 2
-%11 = OpTypePointer Function %4
-%13 = OpTypeVector %5 2
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 3
+%8 = OpConstant %6 4
+%9 = OpConstantComposite %5 %7 %8
+%11 = OpTypePointer Function %5
+%12 = OpConstantNull %5
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %8
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%10 = OpVariable %11 Function %12
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%12 = OpAccessChain %11 %1 %10
-%14 = OpLoad %4 %12
-%15 = OpVectorShuffle %13 %14 %14 0 1
+ R"(OpStore %10 %9
+OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Matrix) {
+ // var a : mat2x2<f32>;
+ // var x = a[1i]
+
+ auto* a = Var("a", ty.mat2x2<f32>());
+ auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
+ WrapInFunction(a, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%7 = OpTypeMatrix %8 2
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 1
+%12 = OpConstant %11 1
+%13 = OpTypePointer Function %8
+%17 = OpConstantNull %8
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
+%16 = OpVariable %13 Function %17
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%14 = OpAccessChain %13 %5 %12
+%15 = OpLoad %8 %14
+OpStore %16 %15
+OpReturn
)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Matrix) {
+ // var a : mat2x2<f32>;
+ // var idx : i32
+ // var x = a[idx]
+
+ auto* a = Var("a", ty.mat2x2<f32>());
+ auto* idx = Var("idx", ty.i32());
+ auto* x = Var("x", nullptr, IndexAccessor("a", idx));
+ WrapInFunction(a, idx, x);
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%7 = OpTypeMatrix %8 2
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%12 = OpTypePointer Function %13
+%14 = OpConstantNull %13
+%16 = OpTypePointer Function %8
+%20 = OpConstantNull %8
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
+%11 = OpVariable %12 Function %14
+%19 = OpVariable %16 Function %20
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%15 = OpLoad %13 %11
+%17 = OpAccessChain %16 %5 %15
+%18 = OpLoad %8 %17
+OpStore %19 %18
+OpReturn
+)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor) {
@@ -219,7 +900,7 @@ TEST_F(BuilderTest, MemberAccessor) {
// var ident : my_struct
// ident.b
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
@@ -229,27 +910,28 @@ TEST_F(BuilderTest, MemberAccessor) {
auto* expr = MemberAccessor("ident", "b");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeStruct %4 %4
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 1
-%8 = OpTypePointer Function %4
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeStruct %8 %8
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 1
+%12 = OpTypePointer Function %8
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpAccessChain %8 %1 %7
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
+%14 = OpLoad %8 %13
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Nested) {
@@ -263,40 +945,42 @@ TEST_F(BuilderTest, MemberAccessor_Nested) {
//
// var ident : my_struct
// ident.inner.a
- auto* inner_struct = Structure("Inner", {
+ auto* inner_struct = Structure("Inner", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
- auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+ auto* s_type = Structure("my_struct", utils::Vector{Member("inner", ty.Of(inner_struct))});
auto* var = Var("ident", ty.Of(s_type));
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%9 = OpConstant %7 1
-%10 = OpTypePointer Function %5
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 0
+%12 = OpConstant %11 0
+%13 = OpConstant %11 1
+%14 = OpTypePointer Function %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %6
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%11 = OpAccessChain %10 %1 %8 %9
+ R"(%15 = OpAccessChain %14 %5 %12 %13
+%16 = OpLoad %9 %15
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_NonPointer) {
@@ -307,7 +991,7 @@ TEST_F(BuilderTest, MemberAccessor_NonPointer) {
// let ident : my_struct = my_struct();
// ident.b
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
@@ -317,21 +1001,22 @@ TEST_F(BuilderTest, MemberAccessor_NonPointer) {
auto* expr = MemberAccessor("ident", "b");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 5u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeStruct %2 %2
-%3 = OpConstantNull %2
-%4 = OpConstantComposite %1 %3 %3
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeStruct %6 %6
+%7 = OpConstantNull %5
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%5 = OpCompositeExtract %2 %4 1
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%8 = OpCompositeExtract %6 %7 1
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
@@ -345,36 +1030,37 @@ TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
//
// let ident : my_struct = my_struct();
// ident.inner.a
- auto* inner_struct = Structure("Inner", {
+ auto* inner_struct = Structure("Inner", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
- auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+ auto* s_type = Structure("my_struct", utils::Vector{Member("inner", ty.Of(inner_struct))});
auto* var = Let("ident", ty.Of(s_type),
Construct(ty.Of(s_type), Construct(ty.Of(inner_struct), 0_f, 0_f)));
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
-%2 = OpTypeStruct %3 %3
-%1 = OpTypeStruct %2
-%4 = OpConstantNull %3
-%5 = OpConstantComposite %2 %4 %4
-%6 = OpConstantComposite %1 %5
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeStruct %7 %7
+%5 = OpTypeStruct %6
+%8 = OpConstantNull %5
)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%7 = OpCompositeExtract %2 %6 0
-%8 = OpCompositeExtract %3 %7 1
+ R"(%9 = OpCompositeExtract %6 %8 0
+%10 = OpCompositeExtract %7 %9 1
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
@@ -389,40 +1075,42 @@ TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
//
// var ident : my_struct
// ident.inner.a
- auto* inner_struct = Structure("Inner", {
+ auto* inner_struct = Structure("Inner", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
auto* alias = Alias("Alias", ty.Of(inner_struct));
- auto* s_type = Structure("Outer", {Member("inner", ty.Of(alias))});
+ auto* s_type = Structure("Outer", utils::Vector{Member("inner", ty.Of(alias))});
auto* var = Var("ident", ty.Of(s_type));
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%9 = OpTypePointer Function %5
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 0
+%12 = OpConstant %11 0
+%13 = OpTypePointer Function %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %6
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%10 = OpAccessChain %9 %1 %8 %8
+ R"(%14 = OpAccessChain %13 %5 %12 %12
+%15 = OpLoad %9 %14
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
@@ -435,41 +1123,42 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
//
// var ident : my_struct
// ident.inner.a = 2.0f;
- auto* inner_struct = Structure("Inner", {
+ auto* inner_struct = Structure("Inner", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
- auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+ auto* s_type = Structure("my_struct", utils::Vector{Member("inner", ty.Of(inner_struct))});
auto* var = Var("ident", ty.Of(s_type));
auto* expr = Assign(MemberAccessor(MemberAccessor("ident", "inner"), "a"), Expr(2_f));
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%9 = OpTypePointer Function %5
-%11 = OpConstant %5 2
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 0
+%12 = OpConstant %11 0
+%13 = OpTypePointer Function %9
+%15 = OpConstant %9 2
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %6
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%10 = OpAccessChain %9 %1 %8 %8
-OpStore %10 %11
+ R"(%14 = OpAccessChain %13 %5 %12 %12
+OpStore %14 %15
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
@@ -483,12 +1172,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
// var ident : my_struct
// var store : f32 = ident.inner.a
- auto* inner_struct = Structure("Inner", {
+ auto* inner_struct = Structure("Inner", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
- auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+ auto* s_type = Structure("my_struct", utils::Vector{Member("inner", ty.Of(inner_struct))});
auto* var = Var("ident", ty.Of(s_type));
auto* store = Var("store", ty.f32());
@@ -497,33 +1186,33 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
auto* expr = Assign("store", rhs);
WrapInFunction(var, store, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunctionVariable(store)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%8 = OpTypePointer Function %5
-%9 = OpConstantNull %5
-%10 = OpTypeInt 32 0
-%11 = OpConstant %10 0
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%12 = OpTypePointer Function %9
+%13 = OpConstantNull %9
+%14 = OpTypeInt 32 0
+%15 = OpConstant %14 0
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %6
-%7 = OpVariable %8 Function %9
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
+%11 = OpVariable %12 Function %13
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%12 = OpAccessChain %8 %1 %11 %11
-%13 = OpLoad %5 %12
-OpStore %7 %13
+ R"(%16 = OpAccessChain %12 %5 %15 %15
+%17 = OpLoad %9 %16
+OpStore %11 %17
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Swizzle_Single) {
@@ -534,27 +1223,28 @@ TEST_F(BuilderTest, MemberAccessor_Swizzle_Single) {
auto* expr = MemberAccessor("ident", "y");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 1
-%8 = OpTypePointer Function %4
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 1
+%12 = OpTypePointer Function %8
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpAccessChain %8 %1 %7
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
+%14 = OpLoad %8 %13
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Swizzle_MultipleNames) {
@@ -565,26 +1255,26 @@ TEST_F(BuilderTest, MemberAccessor_Swizzle_MultipleNames) {
auto* expr = MemberAccessor("ident", "yx");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeVector %4 2
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeVector %8 2
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%7 = OpLoad %3 %1
-%8 = OpVectorShuffle %6 %7 %7 1 0
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%11 = OpLoad %7 %5
+%12 = OpVectorShuffle %10 %11 %11 1 0
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Swizzle_of_Swizzle) {
@@ -595,27 +1285,27 @@ TEST_F(BuilderTest, MemberAccessor_Swizzle_of_Swizzle) {
auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "xz");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%8 = OpTypeVector %4 2
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypeVector %8 2
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%6 = OpLoad %3 %1
-%7 = OpVectorShuffle %3 %6 %6 1 0 2
-%9 = OpVectorShuffle %8 %7 %7 0 2
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
+%11 = OpVectorShuffle %7 %10 %10 1 0 2
+%13 = OpVectorShuffle %12 %11 %11 0 2
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Member_of_Swizzle) {
@@ -626,26 +1316,26 @@ TEST_F(BuilderTest, MemberAccessor_Member_of_Swizzle) {
auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "x");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%6 = OpLoad %3 %1
-%7 = OpVectorShuffle %3 %6 %6 1 0 2
-%8 = OpCompositeExtract %4 %7 0
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
+%11 = OpVectorShuffle %7 %10 %10 1 0 2
+%12 = OpCompositeExtract %8 %11 0
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, MemberAccessor_Array_of_Swizzle) {
@@ -656,28 +1346,28 @@ TEST_F(BuilderTest, MemberAccessor_Array_of_Swizzle) {
auto* expr = IndexAccessor(MemberAccessor("ident", "yxz"), 1_i);
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%8 = OpTypeInt 32 1
-%9 = OpConstant %8 1
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%6 = OpLoad %3 %1
-%7 = OpVectorShuffle %3 %6 %6 1 0 2
-%10 = OpCompositeExtract %4 %7 1
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypeInt 32 1
+%13 = OpConstant %12 1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
+%11 = OpVectorShuffle %7 %10 %10 1 0 2
+%14 = OpCompositeExtract %8 %11 1
+OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, IndexAccessor_Mixed_ArrayAndMember) {
@@ -693,11 +1383,11 @@ TEST_F(BuilderTest, IndexAccessor_Mixed_ArrayAndMember) {
// var index : array<A, 2u>
// index[0i].foo[2i].bar.baz.yx
- auto* c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
+ auto* c_type = Structure("C", utils::Vector{Member("baz", ty.vec3<f32>())});
- auto* b_type = Structure("B", {Member("bar", ty.Of(c_type))});
+ auto* b_type = Structure("B", utils::Vector{Member("bar", ty.Of(c_type))});
auto* b_ary_type = ty.array(ty.Of(b_type), 3_u);
- auto* a_type = Structure("A", {Member("foo", b_ary_type)});
+ auto* a_type = Structure("A", utils::Vector{Member("foo", b_ary_type)});
auto* a_ary_type = ty.array(ty.Of(a_type), 2_u);
auto* var = Var("index", a_ary_type);
@@ -709,323 +1399,37 @@ TEST_F(BuilderTest, IndexAccessor_Mixed_ArrayAndMember) {
"yx");
WrapInFunction(var, expr);
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 22u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeFloat 32
-%8 = OpTypeVector %9 3
-%7 = OpTypeStruct %8
-%6 = OpTypeStruct %7
-%10 = OpTypeInt 32 0
-%11 = OpConstant %10 3
-%5 = OpTypeArray %6 %11
-%4 = OpTypeStruct %5
-%12 = OpConstant %10 2
-%3 = OpTypeArray %4 %12
-%2 = OpTypePointer Function %3
-%13 = OpConstantNull %3
-%14 = OpTypeInt 32 1
-%15 = OpConstantNull %14
-%16 = OpConstant %10 0
-%17 = OpConstant %14 2
-%18 = OpTypePointer Function %8
-%20 = OpTypeVector %9 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %13
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%19 = OpAccessChain %18 %1 %15 %16 %17 %16 %16
-%21 = OpLoad %8 %19
-%22 = OpVectorShuffle %20 %21 %21 1 0
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_Of_Vec) {
- // let pos : array<vec2<f32>, 3u> = array<vec2<f32>, 3u>(
- // vec2<f32>(0.0, 0.5),
- // vec2<f32>(-0.5, -0.5),
- // vec2<f32>(0.5, -0.5));
- // pos[1u]
-
- auto* var = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
- Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
- vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
-
- auto* expr = IndexAccessor("pos", 1_u);
- WrapInFunction(var, expr);
-
spirv::Builder& b = SanitizeAndBuild();
- ASSERT_TRUE(b.Build());
+ ASSERT_TRUE(b.Build()) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%8 = OpTypeInt 32 0
-%9 = OpConstant %8 3
-%5 = OpTypeArray %6 %9
-%10 = OpConstant %7 0
-%11 = OpConstant %7 0.5
-%12 = OpConstantComposite %6 %10 %11
-%13 = OpConstant %7 -0.5
-%14 = OpConstantComposite %6 %13 %13
-%15 = OpConstantComposite %6 %11 %13
-%16 = OpConstantComposite %5 %12 %14 %15
-%17 = OpConstant %8 1
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%18 = OpCompositeExtract %6 %16 1
-OpReturn
-)");
-
- Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Of_Array_Of_f32) {
- // let pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
- // array<f32, 2>(0.0, 0.5),
- // array<f32, 2>(-0.5, -0.5),
- // array<f32, 2>(0.5, -0.5));
- // pos[2u][1u]
-
- auto* var = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
- Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
- vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
-
- auto* expr = IndexAccessor(IndexAccessor("pos", 2_u), 1_u);
- WrapInFunction(var, expr);
-
- spirv::Builder& b = SanitizeAndBuild();
-
- ASSERT_TRUE(b.Build());
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%8 = OpTypeInt 32 0
-%9 = OpConstant %8 3
-%5 = OpTypeArray %6 %9
-%10 = OpConstant %7 0
-%11 = OpConstant %7 0.5
-%12 = OpConstantComposite %6 %10 %11
-%13 = OpConstant %7 -0.5
-%14 = OpConstantComposite %6 %13 %13
-%15 = OpConstantComposite %6 %11 %13
-%16 = OpConstantComposite %5 %12 %14 %15
-%17 = OpConstant %8 2
-%19 = OpConstant %8 1
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%18 = OpCompositeExtract %6 %16 2
-%20 = OpCompositeExtract %7 %18 1
-OpReturn
-)");
-
- Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Vec_Literal) {
- // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
- // pos[1]
-
- auto* var = Let("pos", ty.vec2<f32>(), vec2<f32>(0_f, 0.5_f));
-
- auto* expr = IndexAccessor("pos", 1_u);
- WrapInFunction(var, expr);
-
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstant %2 0
-%4 = OpConstant %2 0.5
-%5 = OpConstantComposite %1 %3 %4
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 1
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%8 = OpCompositeExtract %2 %5 1
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_Vec_Dynamic) {
- // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
- // idx : i32
- // pos[idx]
-
- auto* var = Let("pos", ty.vec2<f32>(), vec2<f32>(0_f, 0.5_f));
- auto* idx = Var("idx", ty.i32());
- auto* expr = IndexAccessor("pos", idx);
-
- WrapInFunction(var, idx, expr);
-
- spirv::Builder& b = Build();
-
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstant %2 0
-%4 = OpConstant %2 0.5
-%5 = OpConstantComposite %1 %3 %4
-%8 = OpTypeInt 32 1
-%7 = OpTypePointer Function %8
-%9 = OpConstantNull %8
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%6 = OpVariable %7 Function %9
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%10 = OpLoad %8 %6
-%11 = OpVectorExtractDynamic %2 %5 %10
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_Array_Literal) {
- // let a : array<f32, 3u>;
- // a[2i]
-
- auto* var = Let("a", ty.array<f32, 3>(), Construct(ty.array<f32, 3>(), 0_f, 0.5_f, 1_f));
- auto* expr = IndexAccessor("a", 2_i);
- WrapInFunction(var, expr);
-
- spirv::Builder& b = SanitizeAndBuild();
-
- ASSERT_TRUE(b.Build());
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%6 = OpTypeFloat 32
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 3
-%5 = OpTypeArray %6 %8
-%9 = OpConstantNull %6
-%10 = OpConstant %6 0.5
-%11 = OpConstant %6 1
-%12 = OpConstantComposite %5 %9 %10 %11
-%13 = OpTypeInt 32 1
-%14 = OpConstant %13 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%15 = OpCompositeExtract %6 %12 2
-OpReturn
-)");
-
- Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Array_Dynamic) {
- // let a : array<f32, 3>;
- // idx : i32
- // a[idx]
-
- auto* var = Let("a", ty.array<f32, 3>(), Construct(ty.array<f32, 3>(), 0_f, 0.5_f, 1_f));
-
- auto* idx = Var("idx", ty.i32());
- auto* expr = IndexAccessor("a", idx);
-
- WrapInFunction(var, idx, expr);
-
- spirv::Builder& b = SanitizeAndBuild();
-
- ASSERT_TRUE(b.Build());
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%6 = OpTypeFloat 32
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 3
-%5 = OpTypeArray %6 %8
-%9 = OpConstantNull %6
-%10 = OpConstant %6 0.5
-%11 = OpConstant %6 1
-%12 = OpConstantComposite %5 %9 %10 %11
-%15 = OpTypeInt 32 1
-%14 = OpTypePointer Function %15
-%16 = OpConstantNull %15
-%18 = OpTypePointer Function %5
-%19 = OpConstantNull %5
-%21 = OpTypePointer Function %6
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%13 = OpVariable %14 Function %16
-%17 = OpVariable %18 Function %19
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(OpStore %17 %12
-%20 = OpLoad %15 %13
-%22 = OpAccessChain %21 %17 %20
-%23 = OpLoad %6 %22
-OpReturn
-)");
-
- Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Matrix_Dynamic) {
- // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
- // idx : i32
- // a[idx]
-
- auto* var = Let("a", ty.mat2x2<f32>(),
- Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1_f, 2_f),
- Construct(ty.vec2<f32>(), 3_f, 4_f)));
-
- auto* idx = Var("idx", ty.i32());
- auto* expr = IndexAccessor("a", idx);
-
- WrapInFunction(var, idx, expr);
-
- spirv::Builder& b = SanitizeAndBuild();
-
- ASSERT_TRUE(b.Build());
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%5 = OpTypeMatrix %6 2
-%8 = OpConstant %7 1
-%9 = OpConstant %7 2
-%10 = OpConstantComposite %6 %8 %9
-%11 = OpConstant %7 3
-%12 = OpConstant %7 4
-%13 = OpConstantComposite %6 %11 %12
-%14 = OpConstantComposite %5 %10 %13
-%17 = OpTypeInt 32 1
-%16 = OpTypePointer Function %17
-%18 = OpConstantNull %17
-%20 = OpTypePointer Function %5
-%21 = OpConstantNull %5
-%23 = OpTypePointer Function %6
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%15 = OpVariable %16 Function %18
-%19 = OpVariable %20 Function %21
+%13 = OpTypeFloat 32
+%12 = OpTypeVector %13 3
+%11 = OpTypeStruct %12
+%10 = OpTypeStruct %11
+%14 = OpTypeInt 32 0
+%15 = OpConstant %14 3
+%9 = OpTypeArray %10 %15
+%8 = OpTypeStruct %9
+%16 = OpConstant %14 2
+%7 = OpTypeArray %8 %16
+%6 = OpTypePointer Function %7
+%17 = OpConstantNull %7
+%18 = OpTypeInt 32 1
+%19 = OpConstantNull %18
+%20 = OpConstant %14 0
+%21 = OpConstant %18 2
+%22 = OpTypePointer Function %12
+%24 = OpTypeVector %13 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %17
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(OpStore %19 %14
-%22 = OpLoad %17 %15
-%24 = OpAccessChain %23 %19 %22
-%25 = OpLoad %6 %24
+ R"(%23 = OpAccessChain %22 %5 %19 %20 %21 %20 %20
+%25 = OpLoad %12 %23
+%26 = OpVectorShuffle %24 %25 %25 1 0
OpReturn
)");
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_assign_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_assign_test.cc
index 71c958c50dd..be30dc76c3c 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_assign_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_assign_test.cc
@@ -23,7 +23,7 @@ namespace {
using BuilderTest = TestHelper;
TEST_F(BuilderTest, Assign_Var) {
- auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", 1_f);
@@ -51,7 +51,7 @@ TEST_F(BuilderTest, Assign_Var) {
}
TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) {
- auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", Expr(1_f));
@@ -70,7 +70,7 @@ TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) {
}
TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
- auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* val = vec3<f32>();
auto* assign = Assign("var", val);
@@ -101,7 +101,7 @@ TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
TEST_F(BuilderTest, Assign_Var_Complex_ConstructorNestedVector) {
auto* init = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
- auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", init);
@@ -134,7 +134,7 @@ TEST_F(BuilderTest, Assign_Var_Complex_ConstructorNestedVector) {
TEST_F(BuilderTest, Assign_Var_Complex_Constructor) {
auto* init = vec3<f32>(1_f, 2_f, 3_f);
- auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", init);
@@ -172,7 +172,7 @@ TEST_F(BuilderTest, Assign_StructMember) {
// var ident : my_struct
// ident.b = 4.0;
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.f32()),
});
@@ -209,7 +209,7 @@ OpStore %8 %9
}
TEST_F(BuilderTest, Assign_Vector) {
- auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* val = vec3<f32>(1_f, 1_f, 3_f);
auto* assign = Assign("var", val);
@@ -243,7 +243,7 @@ TEST_F(BuilderTest, Assign_Vector) {
TEST_F(BuilderTest, Assign_Vector_MemberByName) {
// var.y = 1
- auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign(MemberAccessor("var", "y"), Expr(1_f));
@@ -278,7 +278,7 @@ OpStore %9 %10
TEST_F(BuilderTest, Assign_Vector_MemberByIndex) {
// var[1] = 1
- auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign(IndexAccessor("var", 1_i), Expr(1_f));
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_binary_expression_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_binary_expression_test.cc
index abaee2e2041..922473eb430 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_binary_expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_binary_expression_test.cc
@@ -191,8 +191,8 @@ INSTANTIATE_TEST_SUITE_P(
BinaryData{ast::BinaryOp::kSubtract, "OpISub"},
BinaryData{ast::BinaryOp::kXor, "OpBitwiseXor"}));
-using BinaryArithFloatTest = TestParamHelper<BinaryData>;
-TEST_P(BinaryArithFloatTest, Scalar) {
+using BinaryArithF32Test = TestParamHelper<BinaryData>;
+TEST_P(BinaryArithF32Test, Scalar) {
auto param = GetParam();
auto* lhs = Expr(3.2_f);
@@ -215,7 +215,7 @@ TEST_P(BinaryArithFloatTest, Scalar) {
"%4 = " + param.name + " %1 %2 %3\n");
}
-TEST_P(BinaryArithFloatTest, Vector) {
+TEST_P(BinaryArithF32Test, Vector) {
auto param = GetParam();
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -239,7 +239,66 @@ TEST_P(BinaryArithFloatTest, Vector) {
"%5 = " + param.name + " %1 %4 %4\n");
}
INSTANTIATE_TEST_SUITE_P(BuilderTest,
- BinaryArithFloatTest,
+ BinaryArithF32Test,
+ testing::Values(BinaryData{ast::BinaryOp::kAdd, "OpFAdd"},
+ BinaryData{ast::BinaryOp::kDivide, "OpFDiv"},
+ BinaryData{ast::BinaryOp::kModulo, "OpFRem"},
+ BinaryData{ast::BinaryOp::kMultiply, "OpFMul"},
+ BinaryData{ast::BinaryOp::kSubtract, "OpFSub"}));
+
+using BinaryArithF16Test = TestParamHelper<BinaryData>;
+TEST_P(BinaryArithF16Test, Scalar) {
+ Enable(ast::Extension::kF16);
+
+ auto param = GetParam();
+
+ auto* lhs = Expr(3.2_h);
+ auto* rhs = Expr(4.5_h);
+
+ auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.998p+1
+%3 = OpConstant %1 0x1.2p+2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ "%4 = " + param.name + " %1 %2 %3\n");
+}
+
+TEST_P(BinaryArithF16Test, Vector) {
+ Enable(ast::Extension::kF16);
+
+ auto param = GetParam();
+
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ "%5 = " + param.name + " %1 %4 %4\n");
+}
+INSTANTIATE_TEST_SUITE_P(BuilderTest,
+ BinaryArithF16Test,
testing::Values(BinaryData{ast::BinaryOp::kAdd, "OpFAdd"},
BinaryData{ast::BinaryOp::kDivide, "OpFDiv"},
BinaryData{ast::BinaryOp::kModulo, "OpFRem"},
@@ -287,7 +346,7 @@ TEST_P(BinaryOperatorBoolTest, Vector) {
EXPECT_EQ(b.GenerateBinaryExpression(expr), 7u) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
%1 = OpTypeVector %2 3
-%3 = OpConstantFalse %2
+%3 = OpConstantNull %2
%4 = OpConstantTrue %2
%5 = OpConstantComposite %1 %3 %4 %3
%6 = OpConstantComposite %1 %4 %3 %4
@@ -422,8 +481,8 @@ INSTANTIATE_TEST_SUITE_P(
BinaryData{ast::BinaryOp::kLessThanEqual, "OpSLessThanEqual"},
BinaryData{ast::BinaryOp::kNotEqual, "OpINotEqual"}));
-using BinaryCompareFloatTest = TestParamHelper<BinaryData>;
-TEST_P(BinaryCompareFloatTest, Scalar) {
+using BinaryCompareF32Test = TestParamHelper<BinaryData>;
+TEST_P(BinaryCompareF32Test, Scalar) {
auto param = GetParam();
auto* lhs = Expr(3.2_f);
@@ -447,7 +506,7 @@ TEST_P(BinaryCompareFloatTest, Scalar) {
"%4 = " + param.name + " %5 %2 %3\n");
}
-TEST_P(BinaryCompareFloatTest, Vector) {
+TEST_P(BinaryCompareF32Test, Vector) {
auto param = GetParam();
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -474,7 +533,7 @@ TEST_P(BinaryCompareFloatTest, Vector) {
}
INSTANTIATE_TEST_SUITE_P(
BuilderTest,
- BinaryCompareFloatTest,
+ BinaryCompareF32Test,
testing::Values(BinaryData{ast::BinaryOp::kEqual, "OpFOrdEqual"},
BinaryData{ast::BinaryOp::kGreaterThan, "OpFOrdGreaterThan"},
BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpFOrdGreaterThanEqual"},
@@ -482,7 +541,71 @@ INSTANTIATE_TEST_SUITE_P(
BinaryData{ast::BinaryOp::kLessThanEqual, "OpFOrdLessThanEqual"},
BinaryData{ast::BinaryOp::kNotEqual, "OpFOrdNotEqual"}));
-TEST_F(BuilderTest, Binary_Multiply_VectorScalar) {
+using BinaryCompareF16Test = TestParamHelper<BinaryData>;
+TEST_P(BinaryCompareF16Test, Scalar) {
+ Enable(ast::Extension::kF16);
+
+ auto param = GetParam();
+
+ auto* lhs = Expr(3.2_h);
+ auto* rhs = Expr(4.5_h);
+
+ auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.998p+1
+%3 = OpConstant %1 0x1.2p+2
+%5 = OpTypeBool
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ "%4 = " + param.name + " %5 %2 %3\n");
+}
+
+TEST_P(BinaryCompareF16Test, Vector) {
+ Enable(ast::Extension::kF16);
+
+ auto param = GetParam();
+
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstantComposite %1 %3 %3 %3
+%7 = OpTypeBool
+%6 = OpTypeVector %7 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ "%5 = " + param.name + " %6 %4 %4\n");
+}
+INSTANTIATE_TEST_SUITE_P(
+ BuilderTest,
+ BinaryCompareF16Test,
+ testing::Values(BinaryData{ast::BinaryOp::kEqual, "OpFOrdEqual"},
+ BinaryData{ast::BinaryOp::kGreaterThan, "OpFOrdGreaterThan"},
+ BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpFOrdGreaterThanEqual"},
+ BinaryData{ast::BinaryOp::kLessThan, "OpFOrdLessThan"},
+ BinaryData{ast::BinaryOp::kLessThanEqual, "OpFOrdLessThanEqual"},
+ BinaryData{ast::BinaryOp::kNotEqual, "OpFOrdNotEqual"}));
+
+TEST_F(BuilderTest, Binary_Multiply_VectorScalar_F32) {
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
auto* rhs = Expr(1_f);
@@ -505,7 +628,32 @@ TEST_F(BuilderTest, Binary_Multiply_VectorScalar) {
"%5 = OpVectorTimesScalar %1 %4 %3\n");
}
-TEST_F(BuilderTest, Binary_Multiply_ScalarVector) {
+TEST_F(BuilderTest, Binary_Multiply_VectorScalar_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+ auto* rhs = Expr(1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()),
+ R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ "%5 = OpVectorTimesScalar %1 %4 %3\n");
+}
+
+TEST_F(BuilderTest, Binary_Multiply_ScalarVector_F32) {
auto* lhs = Expr(1_f);
auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -528,7 +676,32 @@ TEST_F(BuilderTest, Binary_Multiply_ScalarVector) {
"%5 = OpVectorTimesScalar %3 %4 %2\n");
}
-TEST_F(BuilderTest, Binary_Multiply_MatrixScalar) {
+TEST_F(BuilderTest, Binary_Multiply_ScalarVector_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* lhs = Expr(1_h);
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+
+ WrapInFunction(expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()),
+ R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+0
+%3 = OpTypeVector %1 3
+%4 = OpConstantComposite %3 %2 %2 %2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ "%5 = OpVectorTimesScalar %3 %4 %2\n");
+}
+
+TEST_F(BuilderTest, Binary_Multiply_MatrixScalar_F32) {
auto* var = Var("mat", ty.mat3x3<f32>());
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr(1_f));
@@ -555,7 +728,36 @@ TEST_F(BuilderTest, Binary_Multiply_MatrixScalar) {
)");
}
-TEST_F(BuilderTest, Binary_Multiply_ScalarMatrix) {
+TEST_F(BuilderTest, Binary_Multiply_MatrixScalar_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("mat", ty.mat3x3<f16>());
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr(1_h));
+
+ WrapInFunction(var, expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()),
+ R"(%5 = OpTypeFloat 16
+%4 = OpTypeVector %5 3
+%3 = OpTypeMatrix %4 3
+%2 = OpTypePointer Function %3
+%1 = OpVariable %2 Function
+%7 = OpConstant %5 0x1p+0
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpLoad %3 %1
+%8 = OpMatrixTimesScalar %3 %6 %7
+)");
+}
+
+TEST_F(BuilderTest, Binary_Multiply_ScalarMatrix_F32) {
auto* var = Var("mat", ty.mat3x3<f32>());
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr(1_f), Expr("mat"));
@@ -582,7 +784,36 @@ TEST_F(BuilderTest, Binary_Multiply_ScalarMatrix) {
)");
}
-TEST_F(BuilderTest, Binary_Multiply_MatrixVector) {
+TEST_F(BuilderTest, Binary_Multiply_ScalarMatrix_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("mat", ty.mat3x3<f16>());
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr(1_h), Expr("mat"));
+
+ WrapInFunction(var, expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()),
+ R"(%5 = OpTypeFloat 16
+%4 = OpTypeVector %5 3
+%3 = OpTypeMatrix %4 3
+%2 = OpTypePointer Function %3
+%1 = OpVariable %2 Function
+%6 = OpConstant %5 0x1p+0
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%7 = OpLoad %3 %1
+%8 = OpMatrixTimesScalar %3 %7 %6
+)");
+}
+
+TEST_F(BuilderTest, Binary_Multiply_MatrixVector_F32) {
auto* var = Var("mat", ty.mat3x3<f32>());
auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -611,7 +842,38 @@ TEST_F(BuilderTest, Binary_Multiply_MatrixVector) {
)");
}
-TEST_F(BuilderTest, Binary_Multiply_VectorMatrix) {
+TEST_F(BuilderTest, Binary_Multiply_MatrixVector_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("mat", ty.mat3x3<f16>());
+ auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), rhs);
+
+ WrapInFunction(var, expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 9u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()),
+ R"(%5 = OpTypeFloat 16
+%4 = OpTypeVector %5 3
+%3 = OpTypeMatrix %4 3
+%2 = OpTypePointer Function %3
+%1 = OpVariable %2 Function
+%7 = OpConstant %5 0x1p+0
+%8 = OpConstantComposite %4 %7 %7 %7
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpLoad %3 %1
+%9 = OpMatrixTimesVector %4 %6 %8
+)");
+}
+
+TEST_F(BuilderTest, Binary_Multiply_VectorMatrix_F32) {
auto* var = Var("mat", ty.mat3x3<f32>());
auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
@@ -640,7 +902,38 @@ TEST_F(BuilderTest, Binary_Multiply_VectorMatrix) {
)");
}
-TEST_F(BuilderTest, Binary_Multiply_MatrixMatrix) {
+TEST_F(BuilderTest, Binary_Multiply_VectorMatrix_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("mat", ty.mat3x3<f16>());
+ auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, Expr("mat"));
+
+ WrapInFunction(var, expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 9u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()),
+ R"(%5 = OpTypeFloat 16
+%4 = OpTypeVector %5 3
+%3 = OpTypeMatrix %4 3
+%2 = OpTypePointer Function %3
+%1 = OpVariable %2 Function
+%6 = OpConstant %5 0x1p+0
+%7 = OpConstantComposite %4 %6 %6 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%8 = OpLoad %3 %1
+%9 = OpVectorTimesMatrix %4 %7 %8
+)");
+}
+
+TEST_F(BuilderTest, Binary_Multiply_MatrixMatrix_F32) {
auto* var = Var("mat", ty.mat3x3<f32>());
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr("mat"));
@@ -667,6 +960,35 @@ TEST_F(BuilderTest, Binary_Multiply_MatrixMatrix) {
)");
}
+TEST_F(BuilderTest, Binary_Multiply_MatrixMatrix_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Var("mat", ty.mat3x3<f16>());
+
+ auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr("mat"));
+
+ WrapInFunction(var, expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+
+ EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()),
+ R"(%5 = OpTypeFloat 16
+%4 = OpTypeVector %5 3
+%3 = OpTypeMatrix %4 3
+%2 = OpTypePointer Function %3
+%1 = OpVariable %2 Function
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpLoad %3 %1
+%7 = OpLoad %3 %1
+%8 = OpMatrixTimesMatrix %3 %6 %7
+)");
+}
+
TEST_F(BuilderTest, Binary_LogicalAnd) {
auto* lhs = create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(1_i), Expr(2_i));
@@ -704,8 +1026,8 @@ OpBranch %7
}
TEST_F(BuilderTest, Binary_LogicalAnd_WithLoads) {
- auto* a_var = Global("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
- auto* b_var = Global("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
+ auto* a_var = GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
+ auto* b_var = GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
@@ -857,8 +1179,8 @@ OpBranch %7
}
TEST_F(BuilderTest, Binary_LogicalOr_WithLoads) {
- auto* a_var = Global("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
- auto* b_var = Global("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
+ auto* a_var = GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
+ auto* b_var = GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
@@ -895,33 +1217,57 @@ OpBranch %9
namespace BinaryArithVectorScalar {
-enum class Type { f32, i32, u32 };
+enum class Type { f32, f16, i32, u32 };
static const ast::Expression* MakeVectorExpr(ProgramBuilder* builder, Type type) {
+ auto name = builder->Symbols().New();
switch (type) {
case Type::f32:
- return builder->vec3<f32>(1_f, 1_f, 1_f);
+ builder->GlobalVar(name, builder->ty.vec3<f32>(), builder->vec3<f32>(1_f, 1_f, 1_f),
+ ast::StorageClass::kPrivate);
+ break;
+ case Type::f16:
+ builder->GlobalVar(name, builder->ty.vec3<f16>(), builder->vec3<f16>(1_h, 1_h, 1_h),
+ ast::StorageClass::kPrivate);
+ break;
case Type::i32:
- return builder->vec3<i32>(1_i, 1_i, 1_i);
+ builder->GlobalVar(name, builder->ty.vec3<i32>(), builder->vec3<i32>(1_i, 1_i, 1_i),
+ ast::StorageClass::kPrivate);
+ break;
case Type::u32:
- return builder->vec3<u32>(1_u, 1_u, 1_u);
+ builder->GlobalVar(name, builder->ty.vec3<u32>(), builder->vec3<u32>(1_u, 1_u, 1_u),
+ ast::StorageClass::kPrivate);
+ break;
}
- return nullptr;
+ return builder->Expr(name);
}
static const ast::Expression* MakeScalarExpr(ProgramBuilder* builder, Type type) {
+ auto name = builder->Symbols().New();
switch (type) {
case Type::f32:
- return builder->Expr(1_f);
+ builder->GlobalVar(name, builder->ty.f32(), builder->Expr(1_f),
+ ast::StorageClass::kPrivate);
+ break;
+ case Type::f16:
+ builder->GlobalVar(name, builder->ty.f16(), builder->Expr(1_h),
+ ast::StorageClass::kPrivate);
+ break;
case Type::i32:
- return builder->Expr(1_i);
+ builder->GlobalVar(name, builder->ty.i32(), builder->Expr(1_i),
+ ast::StorageClass::kPrivate);
+ break;
case Type::u32:
- return builder->Expr(1_u);
+ builder->GlobalVar(name, builder->ty.u32(), builder->Expr(1_u),
+ ast::StorageClass::kPrivate);
+ break;
}
- return nullptr;
+ return builder->Expr(name);
}
static std::string OpTypeDecl(Type type) {
switch (type) {
case Type::f32:
return "OpTypeFloat 32";
+ case Type::f16:
+ return "OpTypeFloat 16";
case Type::i32:
return "OpTypeInt 32 1";
case Type::u32:
@@ -929,6 +1275,32 @@ static std::string OpTypeDecl(Type type) {
}
return {};
}
+static std::string ConstantValue(Type type) {
+ switch (type) {
+ case Type::f32:
+ case Type::i32:
+ case Type::u32:
+ return "1";
+ case Type::f16:
+ return "0x1p+0";
+ }
+ return {};
+}
+static std::string CapabilityDecl(Type type) {
+ switch (type) {
+ case Type::f32:
+ case Type::i32:
+ case Type::u32:
+ return "OpCapability Shader";
+ case Type::f16:
+ return R"(OpCapability Shader
+OpCapability Float16
+OpCapability UniformAndStorageBuffer16BitAccess
+OpCapability StorageBuffer16BitAccess
+OpCapability StorageInputOutput16)";
+ }
+ return {};
+}
struct Param {
Type type;
@@ -940,9 +1312,15 @@ using BinaryArithVectorScalarTest = TestParamHelper<Param>;
TEST_P(BinaryArithVectorScalarTest, VectorScalar) {
auto& param = GetParam();
+ if (param.type == Type::f16) {
+ Enable(ast::Extension::kF16);
+ }
+
const ast::Expression* lhs = MakeVectorExpr(this, param.type);
const ast::Expression* rhs = MakeScalarExpr(this, param.type);
std::string op_type_decl = OpTypeDecl(param.type);
+ std::string constant_value = ConstantValue(param.type);
+ std::string capability_decl = CapabilityDecl(param.type);
auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
@@ -950,25 +1328,33 @@ TEST_P(BinaryArithVectorScalarTest, VectorScalar) {
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
-
- EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+ EXPECT_EQ(DumpBuilder(b), capability_decl + R"(
OpMemoryModel Logical GLSL450
-OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%6 = )" + op_type_decl + R"(
-%5 = OpTypeVector %6 3
-%7 = OpConstant %6 1
-%8 = OpConstantComposite %5 %7 %7 %7
-%11 = OpTypePointer Function %5
-%12 = OpConstantNull %5
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%10 = OpVariable %11 Function %12
-%13 = OpCompositeConstruct %5 %7 %7 %7
-%9 = )" + param.name + R"( %5 %8 %13
+OpEntryPoint GLCompute %11 "test_function"
+OpExecutionMode %11 LocalSize 1 1 1
+OpName %5 "tint_symbol"
+OpName %7 "tint_symbol_1"
+OpName %11 "test_function"
+%2 = )" + op_type_decl + R"(
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 )" + constant_value +
+ R"(
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypePointer Private %2
+%7 = OpVariable %8 Private %3
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+%17 = OpTypePointer Function %1
+%18 = OpConstantNull %1
+%11 = OpFunction %10 None %9
+%12 = OpLabel
+%16 = OpVariable %17 Function %18
+%13 = OpLoad %1 %5
+%14 = OpLoad %2 %7
+%19 = OpCompositeConstruct %1 %14 %14 %14
+%15 = )" + param.name + R"( %1 %13 %19
OpReturn
OpFunctionEnd
)");
@@ -978,9 +1364,15 @@ OpFunctionEnd
TEST_P(BinaryArithVectorScalarTest, ScalarVector) {
auto& param = GetParam();
+ if (param.type == Type::f16) {
+ Enable(ast::Extension::kF16);
+ }
+
const ast::Expression* lhs = MakeScalarExpr(this, param.type);
const ast::Expression* rhs = MakeVectorExpr(this, param.type);
std::string op_type_decl = OpTypeDecl(param.type);
+ std::string constant_value = ConstantValue(param.type);
+ std::string capability_decl = CapabilityDecl(param.type);
auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
@@ -988,25 +1380,33 @@ TEST_P(BinaryArithVectorScalarTest, ScalarVector) {
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
-
- EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+ EXPECT_EQ(DumpBuilder(b), capability_decl + R"(
OpMemoryModel Logical GLSL450
-OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%5 = )" + op_type_decl + R"(
-%6 = OpConstant %5 1
-%7 = OpTypeVector %5 3
-%8 = OpConstantComposite %7 %6 %6 %6
-%11 = OpTypePointer Function %7
-%12 = OpConstantNull %7
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%10 = OpVariable %11 Function %12
-%13 = OpCompositeConstruct %7 %6 %6 %6
-%9 = )" + param.name + R"( %7 %13 %8
+OpEntryPoint GLCompute %11 "test_function"
+OpExecutionMode %11 LocalSize 1 1 1
+OpName %3 "tint_symbol"
+OpName %7 "tint_symbol_1"
+OpName %11 "test_function"
+%1 = )" + op_type_decl + R"(
+%2 = OpConstant %1 )" + constant_value +
+ R"(
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%5 = OpTypeVector %1 3
+%6 = OpConstantComposite %5 %2 %2 %2
+%8 = OpTypePointer Private %5
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+%17 = OpTypePointer Function %5
+%18 = OpConstantNull %5
+%11 = OpFunction %10 None %9
+%12 = OpLabel
+%16 = OpVariable %17 Function %18
+%13 = OpLoad %1 %3
+%14 = OpLoad %5 %7
+%19 = OpCompositeConstruct %5 %13 %13 %13
+%15 = )" + param.name + R"( %5 %19 %14
OpReturn
OpFunctionEnd
)");
@@ -1024,6 +1424,10 @@ INSTANTIATE_TEST_SUITE_P(BuilderTest,
// Param{Type::i32, ast::BinaryOp::kMultiply, "OpIMul"},
Param{Type::f32, ast::BinaryOp::kSubtract, "OpFSub"},
+ Param{Type::f16, ast::BinaryOp::kAdd, "OpFAdd"},
+ Param{Type::f16, ast::BinaryOp::kDivide, "OpFDiv"},
+ Param{Type::f16, ast::BinaryOp::kSubtract, "OpFSub"},
+
Param{Type::i32, ast::BinaryOp::kAdd, "OpIAdd"},
Param{Type::i32, ast::BinaryOp::kDivide, "OpSDiv"},
Param{Type::i32, ast::BinaryOp::kModulo, "OpSMod"},
@@ -1040,9 +1444,15 @@ using BinaryArithVectorScalarMultiplyTest = TestParamHelper<Param>;
TEST_P(BinaryArithVectorScalarMultiplyTest, VectorScalar) {
auto& param = GetParam();
+ if (param.type == Type::f16) {
+ Enable(ast::Extension::kF16);
+ }
+
const ast::Expression* lhs = MakeVectorExpr(this, param.type);
const ast::Expression* rhs = MakeScalarExpr(this, param.type);
std::string op_type_decl = OpTypeDecl(param.type);
+ std::string constant_value = ConstantValue(param.type);
+ std::string capability_decl = CapabilityDecl(param.type);
auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
@@ -1050,21 +1460,29 @@ TEST_P(BinaryArithVectorScalarMultiplyTest, VectorScalar) {
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
-
- EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+ EXPECT_EQ(DumpBuilder(b), capability_decl + R"(
OpMemoryModel Logical GLSL450
-OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%6 = )" + op_type_decl + R"(
-%5 = OpTypeVector %6 3
-%7 = OpConstant %6 1
-%8 = OpConstantComposite %5 %7 %7 %7
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%9 = OpVectorTimesScalar %5 %8 %7
+OpEntryPoint GLCompute %11 "test_function"
+OpExecutionMode %11 LocalSize 1 1 1
+OpName %5 "tint_symbol"
+OpName %7 "tint_symbol_1"
+OpName %11 "test_function"
+%2 = )" + op_type_decl + R"(
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 )" + constant_value +
+ R"(
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypePointer Private %2
+%7 = OpVariable %8 Private %3
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+%11 = OpFunction %10 None %9
+%12 = OpLabel
+%13 = OpLoad %1 %5
+%14 = OpLoad %2 %7
+%15 = OpVectorTimesScalar %1 %13 %14
OpReturn
OpFunctionEnd
)");
@@ -1074,9 +1492,15 @@ OpFunctionEnd
TEST_P(BinaryArithVectorScalarMultiplyTest, ScalarVector) {
auto& param = GetParam();
+ if (param.type == Type::f16) {
+ Enable(ast::Extension::kF16);
+ }
+
const ast::Expression* lhs = MakeScalarExpr(this, param.type);
const ast::Expression* rhs = MakeVectorExpr(this, param.type);
std::string op_type_decl = OpTypeDecl(param.type);
+ std::string constant_value = ConstantValue(param.type);
+ std::string capability_decl = CapabilityDecl(param.type);
auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
@@ -1084,21 +1508,29 @@ TEST_P(BinaryArithVectorScalarMultiplyTest, ScalarVector) {
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
-
- EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+ EXPECT_EQ(DumpBuilder(b), capability_decl + R"(
OpMemoryModel Logical GLSL450
-OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%5 = )" + op_type_decl + R"(
-%6 = OpConstant %5 1
-%7 = OpTypeVector %5 3
-%8 = OpConstantComposite %7 %6 %6 %6
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%9 = OpVectorTimesScalar %7 %8 %6
+OpEntryPoint GLCompute %11 "test_function"
+OpExecutionMode %11 LocalSize 1 1 1
+OpName %3 "tint_symbol"
+OpName %7 "tint_symbol_1"
+OpName %11 "test_function"
+%1 = )" + op_type_decl + R"(
+%2 = OpConstant %1 )" + constant_value +
+ R"(
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%5 = OpTypeVector %1 3
+%6 = OpConstantComposite %5 %2 %2 %2
+%8 = OpTypePointer Private %5
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+%11 = OpFunction %10 None %9
+%12 = OpLabel
+%13 = OpLoad %1 %3
+%14 = OpLoad %5 %7
+%15 = OpVectorTimesScalar %5 %14 %13
OpReturn
OpFunctionEnd
)");
@@ -1107,13 +1539,66 @@ OpFunctionEnd
}
INSTANTIATE_TEST_SUITE_P(BuilderTest,
BinaryArithVectorScalarMultiplyTest,
- testing::Values(Param{Type::f32, ast::BinaryOp::kMultiply, "OpFMul"}));
+ testing::Values(Param{Type::f32, ast::BinaryOp::kMultiply, "OpFMul"},
+ Param{Type::f16, ast::BinaryOp::kMultiply, "OpFMul"}));
} // namespace BinaryArithVectorScalar
namespace BinaryArithMatrixMatrix {
+enum class Type { f32, f16 };
+static const ast::Expression* MakeMat3x4Expr(ProgramBuilder* builder, Type type) {
+ auto name = builder->Symbols().New();
+ switch (type) {
+ case Type::f32:
+ builder->GlobalVar(name, builder->ty.mat3x4<f32>(), builder->mat3x4<f32>(),
+ ast::StorageClass::kPrivate);
+ break;
+ case Type::f16:
+ builder->GlobalVar(name, builder->ty.mat3x4<f16>(), builder->mat3x4<f16>(),
+ ast::StorageClass::kPrivate);
+ break;
+ }
+ return builder->Expr(name);
+}
+static const ast::Expression* MakeMat4x3Expr(ProgramBuilder* builder, Type type) {
+ auto name = builder->Symbols().New();
+ switch (type) {
+ case Type::f32:
+ builder->GlobalVar(name, builder->ty.mat4x3<f32>(), builder->mat4x3<f32>(),
+ ast::StorageClass::kPrivate);
+ break;
+ case Type::f16:
+ builder->GlobalVar(name, builder->ty.mat4x3<f16>(), builder->mat4x3<f16>(),
+ ast::StorageClass::kPrivate);
+ }
+ return builder->Expr(name);
+}
+static std::string OpTypeDecl(Type type) {
+ switch (type) {
+ case Type::f32:
+ return "OpTypeFloat 32";
+ case Type::f16:
+ return "OpTypeFloat 16";
+ }
+ return {};
+}
+static std::string CapabilityDecl(Type type) {
+ switch (type) {
+ case Type::f32:
+ return "OpCapability Shader";
+ case Type::f16:
+ return R"(OpCapability Shader
+OpCapability Float16
+OpCapability UniformAndStorageBuffer16BitAccess
+OpCapability StorageBuffer16BitAccess
+OpCapability StorageInputOutput16)";
+ }
+ return {};
+}
+
struct Param {
+ Type type;
ast::BinaryOp op;
std::string name;
};
@@ -1122,8 +1607,14 @@ using BinaryArithMatrixMatrix = TestParamHelper<Param>;
TEST_P(BinaryArithMatrixMatrix, AddOrSubtract) {
auto& param = GetParam();
- const ast::Expression* lhs = mat3x4<f32>();
- const ast::Expression* rhs = mat3x4<f32>();
+ if (param.type == Type::f16) {
+ Enable(ast::Extension::kF16);
+ }
+
+ const ast::Expression* lhs = MakeMat3x4Expr(this, param.type);
+ const ast::Expression* rhs = MakeMat3x4Expr(this, param.type);
+ std::string op_type_decl = OpTypeDecl(param.type);
+ std::string capability_decl = CapabilityDecl(param.type);
auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
@@ -1131,30 +1622,36 @@ TEST_P(BinaryArithMatrixMatrix, AddOrSubtract) {
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
-
- EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+ EXPECT_EQ(DumpBuilder(b), capability_decl + R"(
OpMemoryModel Logical GLSL450
-OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 4
-%5 = OpTypeMatrix %6 3
-%8 = OpConstantNull %5
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%10 = OpCompositeExtract %6 %8 0
-%11 = OpCompositeExtract %6 %8 0
-%12 = )" + param.name + R"( %6 %10 %11
-%13 = OpCompositeExtract %6 %8 1
-%14 = OpCompositeExtract %6 %8 1
-%15 = )" + param.name + R"( %6 %13 %14
-%16 = OpCompositeExtract %6 %8 2
-%17 = OpCompositeExtract %6 %8 2
-%18 = )" + param.name + R"( %6 %16 %17
-%19 = OpCompositeConstruct %5 %12 %15 %18
+OpEntryPoint GLCompute %10 "test_function"
+OpExecutionMode %10 LocalSize 1 1 1
+OpName %5 "tint_symbol"
+OpName %7 "tint_symbol_1"
+OpName %10 "test_function"
+%3 = )" + op_type_decl + R"(
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 3
+%4 = OpConstantNull %1
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%7 = OpVariable %6 Private %4
+%9 = OpTypeVoid
+%8 = OpTypeFunction %9
+%10 = OpFunction %9 None %8
+%11 = OpLabel
+%12 = OpLoad %1 %5
+%13 = OpLoad %1 %7
+%15 = OpCompositeExtract %2 %12 0
+%16 = OpCompositeExtract %2 %13 0
+%17 = )" + param.name + R"( %2 %15 %16
+%18 = OpCompositeExtract %2 %12 1
+%19 = OpCompositeExtract %2 %13 1
+%20 = )" + param.name + R"( %2 %18 %19
+%21 = OpCompositeExtract %2 %12 2
+%22 = OpCompositeExtract %2 %13 2
+%23 = )" + param.name + R"( %2 %21 %22
+%24 = OpCompositeConstruct %1 %17 %20 %23
OpReturn
OpFunctionEnd
)");
@@ -1164,15 +1661,23 @@ OpFunctionEnd
INSTANTIATE_TEST_SUITE_P( //
BuilderTest,
BinaryArithMatrixMatrix,
- testing::Values(Param{ast::BinaryOp::kAdd, "OpFAdd"},
- Param{ast::BinaryOp::kSubtract, "OpFSub"}));
+ testing::Values(Param{Type::f32, ast::BinaryOp::kAdd, "OpFAdd"},
+ Param{Type::f32, ast::BinaryOp::kSubtract, "OpFSub"},
+ Param{Type::f16, ast::BinaryOp::kAdd, "OpFAdd"},
+ Param{Type::f16, ast::BinaryOp::kSubtract, "OpFSub"}));
using BinaryArithMatrixMatrixMultiply = TestParamHelper<Param>;
TEST_P(BinaryArithMatrixMatrixMultiply, Multiply) {
auto& param = GetParam();
- const ast::Expression* lhs = mat3x4<f32>();
- const ast::Expression* rhs = mat4x3<f32>();
+ if (param.type == Type::f16) {
+ Enable(ast::Extension::kF16);
+ }
+
+ const ast::Expression* lhs = MakeMat3x4Expr(this, param.type);
+ const ast::Expression* rhs = MakeMat4x3Expr(this, param.type);
+ std::string op_type_decl = OpTypeDecl(param.type);
+ std::string capability_decl = CapabilityDecl(param.type);
auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
@@ -1180,25 +1685,32 @@ TEST_P(BinaryArithMatrixMatrixMultiply, Multiply) {
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
-
- EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+ EXPECT_EQ(DumpBuilder(b), capability_decl + R"(
OpMemoryModel Logical GLSL450
-OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 4
-%5 = OpTypeMatrix %6 3
-%8 = OpConstantNull %5
-%10 = OpTypeVector %7 3
-%9 = OpTypeMatrix %10 4
-%11 = OpConstantNull %9
-%13 = OpTypeMatrix %6 4
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%12 = OpMatrixTimesMatrix %13 %8 %11
+OpEntryPoint GLCompute %14 "test_function"
+OpExecutionMode %14 LocalSize 1 1 1
+OpName %5 "tint_symbol"
+OpName %10 "tint_symbol_1"
+OpName %14 "test_function"
+%3 = )" + op_type_decl + R"(
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 3
+%4 = OpConstantNull %1
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVector %3 3
+%7 = OpTypeMatrix %8 4
+%9 = OpConstantNull %7
+%11 = OpTypePointer Private %7
+%10 = OpVariable %11 Private %9
+%13 = OpTypeVoid
+%12 = OpTypeFunction %13
+%19 = OpTypeMatrix %2 4
+%14 = OpFunction %13 None %12
+%15 = OpLabel
+%16 = OpLoad %1 %5
+%17 = OpLoad %7 %10
+%18 = OpMatrixTimesMatrix %19 %16 %17
OpReturn
OpFunctionEnd
)");
@@ -1208,7 +1720,8 @@ OpFunctionEnd
INSTANTIATE_TEST_SUITE_P( //
BuilderTest,
BinaryArithMatrixMatrixMultiply,
- testing::Values(Param{ast::BinaryOp::kMultiply, "OpFMul"}));
+ testing::Values(Param{Type::f32, ast::BinaryOp::kMultiply, ""},
+ Param{Type::f16, ast::BinaryOp::kMultiply, ""}));
} // namespace BinaryArithMatrixMatrix
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_test.cc
index 4f6dca8c980..52254d2d400 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_test.cc
@@ -38,74 +38,78 @@ inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
return out;
}
-using BuiltinBoolTest = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(BuiltinBoolTest, Call_Bool_Scalar) {
- auto param = GetParam();
- auto* var = Global("v", ty.bool_(), ast::StorageClass::kPrivate);
- auto* expr = Call(param.name, "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
- Assign(Phony(), expr),
- });
+// This tests that we do not push OpTypeSampledImage and float_0 type twice.
+TEST_F(BuiltinBuilderTest, Call_TextureSampleCompare_Twice) {
+ auto* s = ty.sampler(ast::SamplerKind::kComparisonSampler);
+ auto* t = ty.depth_texture(ast::TextureDimension::k2d);
- spirv::Builder& b = Build();
+ auto* tex = GlobalVar("texture", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+ auto* sampler = GlobalVar("sampler", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
- EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool
-%2 = OpTypePointer Private %3
-%4 = OpConstantNull %3
-%1 = OpVariable %2 Private %4
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
-)");
-
- // both any and all are 'passthrough' for scalar booleans
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), "%10 = OpLoad %3 %1\nOpReturn\n");
-}
+ auto* expr1 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1_f, 2_f), 2_f);
+ auto* expr2 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1_f, 2_f), 2_f);
-TEST_P(BuiltinBoolTest, Call_Bool_Vector) {
- auto param = GetParam();
- auto* var = Global("v", ty.vec3<bool>(), ast::StorageClass::kPrivate);
- auto* expr = Call(param.name, "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
- Assign(Phony(), expr),
- });
+ Func("f1", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(expr1),
+ },
+ utils::Empty);
+ Func("f2", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(expr2),
+ },
+ utils::Empty);
spirv::Builder& b = Build();
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+ b.push_function(Function{});
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeBool
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%7 = OpTypeVoid
-%6 = OpTypeFunction %7
+ ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
+ ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
+
+ EXPECT_EQ(b.GenerateExpression(expr1), 8u) << b.error();
+ EXPECT_EQ(b.GenerateExpression(expr2), 17u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer UniformConstant %3
+%1 = OpVariable %2 UniformConstant
+%7 = OpTypeSampler
+%6 = OpTypePointer UniformConstant %7
+%5 = OpVariable %6 UniformConstant
+%11 = OpTypeSampledImage %3
+%13 = OpTypeVector %4 2
+%14 = OpConstant %4 1
+%15 = OpConstant %4 2
+%16 = OpConstantComposite %13 %14 %15
)");
- auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
-%10 = ${op} %4 %11
-OpReturn
-)",
- "${op}", param.op);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %7 %5
+%10 = OpLoad %3 %1
+%12 = OpSampledImage %11 %10 %9
+%8 = OpImageSampleDrefImplicitLod %4 %12 %16 %15
+%18 = OpLoad %7 %5
+%19 = OpLoad %3 %1
+%20 = OpSampledImage %11 %19 %18
+%17 = OpImageSampleDrefImplicitLod %4 %20 %16 %15
+)");
}
-INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- BuiltinBoolTest,
- testing::Values(BuiltinData{"any", "OpAny"}, BuiltinData{"all", "OpAll"}));
-using BuiltinIntTest = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(BuiltinIntTest, Call_SInt_Scalar) {
- auto param = GetParam();
- auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
- auto* expr = Call(param.name, "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad_f32) {
+ auto* var = GlobalVar("ident", ty.f32(), ast::StorageClass::kPrivate);
+ auto* expr = Call("round", "ident");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Phony(), expr),
});
@@ -114,28 +118,34 @@ TEST_P(BuiltinIntTest, Call_SInt_Scalar) {
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+ auto got = DumpBuilder(b);
+ auto expect =
+ R"(%10 = OpExtInstImport "GLSL.std.450"
+OpName %1 "ident"
+OpName %7 "a_func"
+%3 = OpTypeFloat 32
%2 = OpTypePointer Private %3
%4 = OpConstantNull %3
%1 = OpVariable %2 Private %4
%6 = OpTypeVoid
%5 = OpTypeFunction %6
-)");
-
- auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
-%9 = ${op} %3 %10
+%7 = OpFunction %6 None %5
+%8 = OpLabel
+%11 = OpLoad %3 %1
+%9 = OpExtInst %3 %10 RoundEven %11
OpReturn
-)",
- "${op}", param.op);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
}
-TEST_P(BuiltinIntTest, Call_SInt_Vector) {
- auto param = GetParam();
- auto* var = Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
- auto* expr = Call(param.name, "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("ident", ty.f16(), ast::StorageClass::kPrivate);
+ auto* expr = Call("round", "ident");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Phony(), expr),
});
@@ -144,29 +154,37 @@ TEST_P(BuiltinIntTest, Call_SInt_Vector) {
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
-%3 = OpTypeVector %4 3
+ auto got = DumpBuilder(b);
+ auto expect =
+ R"(%10 = OpExtInstImport "GLSL.std.450"
+OpName %1 "ident"
+OpName %7 "a_func"
+%3 = OpTypeFloat 16
%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%7 = OpTypeVoid
-%6 = OpTypeFunction %7
-)");
-
- auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
-%10 = ${op} %3 %11
+%4 = OpConstantNull %3
+%1 = OpVariable %2 Private %4
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+%7 = OpFunction %6 None %5
+%8 = OpLabel
+%11 = OpLoad %3 %1
+%9 = OpExtInst %3 %10 RoundEven %11
OpReturn
-)",
- "${op}", param.op);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
}
-TEST_P(BuiltinIntTest, Call_UInt_Scalar) {
+// Tests for Logical builtins
+namespace logical_builtin_tests {
+
+using BuiltinBoolTest = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(BuiltinBoolTest, Call_Bool_Scalar) {
auto param = GetParam();
- auto* var = Global("v", ty.u32(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.bool_(), ast::StorageClass::kPrivate);
auto* expr = Call(param.name, "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Phony(), expr),
});
@@ -175,7 +193,7 @@ TEST_P(BuiltinIntTest, Call_UInt_Scalar) {
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 0
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool
%2 = OpTypePointer Private %3
%4 = OpConstantNull %3
%1 = OpVariable %2 Private %4
@@ -183,20 +201,16 @@ TEST_P(BuiltinIntTest, Call_UInt_Scalar) {
%5 = OpTypeFunction %6
)");
- auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
-%9 = ${op} %3 %10
-OpReturn
-)",
- "${op}", param.op);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+ // both any and all are 'passthrough' for scalar booleans
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), "%10 = OpLoad %3 %1\nOpReturn\n");
}
-TEST_P(BuiltinIntTest, Call_UInt_Vector) {
+TEST_P(BuiltinBoolTest, Call_Bool_Vector) {
auto param = GetParam();
- auto* var = Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.vec3<bool>(), ast::StorageClass::kPrivate);
auto* expr = Call(param.name, "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Phony(), expr),
});
@@ -205,7 +219,7 @@ TEST_P(BuiltinIntTest, Call_UInt_Vector) {
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeBool
%3 = OpTypeVector %4 3
%2 = OpTypePointer Private %3
%5 = OpConstantNull %3
@@ -215,28 +229,30 @@ TEST_P(BuiltinIntTest, Call_UInt_Vector) {
)");
auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
-%10 = ${op} %3 %11
+%10 = ${op} %4 %11
OpReturn
)",
"${op}", param.op);
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- BuiltinIntTest,
- testing::Values(BuiltinData{"countOneBits", "OpBitCount"},
- BuiltinData{"reverseBits", "OpBitReverse"}));
+ BuiltinBoolTest,
+ testing::Values(BuiltinData{"any", "OpAny"}, BuiltinData{"all", "OpAll"}));
-TEST_F(BuiltinBuilderTest, Call_Dot_F32) {
- auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- auto* expr = Call("dot", "v", "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Select) {
+ auto* v3 = GlobalVar("v3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+
+ auto* bool_v3 = GlobalVar("bool_v3", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+ auto* expr = Call("select", "v3", "v3", "bool_v3");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateGlobalVariable(v3)) << b.error();
+ ASSERT_TRUE(b.GenerateGlobalVariable(bool_v3)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
@@ -244,307 +260,331 @@ TEST_F(BuiltinBuilderTest, Call_Dot_F32) {
%2 = OpTypePointer Private %3
%5 = OpConstantNull %3
%1 = OpVariable %2 Private %5
-%7 = OpTypeVoid
-%6 = OpTypeFunction %7
+%9 = OpTypeBool
+%8 = OpTypeVector %9 3
+%7 = OpTypePointer Private %8
+%10 = OpConstantNull %8
+%6 = OpVariable %7 Private %10
+%12 = OpTypeVoid
+%11 = OpTypeFunction %12
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%11 = OpLoad %3 %1
-%12 = OpLoad %3 %1
-%10 = OpDot %4 %11 %12
+ R"(%16 = OpLoad %8 %6
+%17 = OpLoad %3 %1
+%18 = OpLoad %3 %1
+%15 = OpSelect %3 %16 %17 %18
OpReturn
)");
}
-TEST_F(BuiltinBuilderTest, Call_Dot_U32) {
- auto* var = Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
- auto* expr = Call("dot", "v", "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
- Assign(Phony(), expr),
- });
+} // namespace logical_builtin_tests
- spirv::Builder& b = Build();
+// Tests for Array builtins
+namespace array_builtin_tests {
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+TEST_F(BuiltinBuilderTest, Call_ArrayLength) {
+ auto* s = Structure("my_struct", utils::Vector{
+ Member("a", ty.array<f32>(4)),
+ });
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+ auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%7 = OpTypeVoid
-%6 = OpTypeFunction %7
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%11 = OpLoad %3 %1
-%12 = OpLoad %3 %1
-%13 = OpCompositeExtract %4 %11 0
-%14 = OpCompositeExtract %4 %12 0
-%15 = OpIMul %4 %13 %14
-%16 = OpCompositeExtract %4 %11 1
-%17 = OpCompositeExtract %4 %12 1
-%18 = OpIMul %4 %16 %17
-%19 = OpIAdd %4 %15 %18
-%20 = OpCompositeExtract %4 %11 2
-%21 = OpCompositeExtract %4 %12 2
-%22 = OpIMul %4 %20 %21
-%10 = OpIAdd %4 %19 %22
-OpReturn
-)");
-}
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
-TEST_F(BuiltinBuilderTest, Call_Dot_I32) {
- auto* var = Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
- auto* expr = Call("dot", "v", "v");
- auto* func = Func("a_func", {}, ty.void_(),
- {
- Assign(Phony(), expr),
- });
+ spirv::Builder& b = SanitizeAndBuild();
- spirv::Builder& b = Build();
+ ASSERT_TRUE(b.Build()) << b.error();
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+ ASSERT_EQ(b.functions().size(), 1_u);
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
+ auto* expected_types = R"(%5 = OpTypeFloat 32
+%4 = OpTypeRuntimeArray %5
+%3 = OpTypeStruct %4
+%2 = OpTypePointer StorageBuffer %3
+%1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid
%6 = OpTypeFunction %7
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%11 = OpLoad %3 %1
-%12 = OpLoad %3 %1
-%13 = OpCompositeExtract %4 %11 0
-%14 = OpCompositeExtract %4 %12 0
-%15 = OpIMul %4 %13 %14
-%16 = OpCompositeExtract %4 %11 1
-%17 = OpCompositeExtract %4 %12 1
-%18 = OpIMul %4 %16 %17
-%19 = OpIAdd %4 %15 %18
-%20 = OpCompositeExtract %4 %11 2
-%21 = OpCompositeExtract %4 %12 2
-%22 = OpIMul %4 %20 %21
-%10 = OpIAdd %4 %19 %22
+%11 = OpTypeInt 32 0
+)";
+ auto got_types = DumpInstructions(b.types());
+ EXPECT_EQ(expected_types, got_types);
+
+ auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
OpReturn
-)");
+)";
+ auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+ EXPECT_EQ(expected_instructions, got_instructions);
+
+ Validate(b);
}
-using BuiltinDeriveTest = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(BuiltinDeriveTest, Call_Derivative_Scalar) {
- auto param = GetParam();
- auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
- auto* expr = Call(param.name, "v");
- auto* func =
- Func("func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
+TEST_F(BuiltinBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
+ auto* s = Structure("my_struct", utils::Vector{
+ Member("z", ty.f32()),
+ Member(4, "a", ty.array<f32>(4)),
+ });
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+ auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
- spirv::Builder& b = Build();
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
-%2 = OpTypePointer Private %3
-%4 = OpConstantNull %3
-%1 = OpVariable %2 Private %4
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
-)");
+ ASSERT_TRUE(b.Build()) << b.error();
- auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
-%9 = ${op} %3 %10
+ ASSERT_EQ(b.functions().size(), 1_u);
+
+ auto* expected_types = R"(%4 = OpTypeFloat 32
+%5 = OpTypeRuntimeArray %4
+%3 = OpTypeStruct %4 %5
+%2 = OpTypePointer StorageBuffer %3
+%1 = OpVariable %2 StorageBuffer
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+%11 = OpTypeInt 32 0
+)";
+ auto got_types = DumpInstructions(b.types());
+ EXPECT_EQ(expected_types, got_types);
+
+ auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1
OpReturn
-)",
- "${op}", param.op);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+)";
+ auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+ EXPECT_EQ(expected_instructions, got_instructions);
+
+ Validate(b);
}
-TEST_P(BuiltinDeriveTest, Call_Derivative_Vector) {
- auto param = GetParam();
- auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
- auto* expr = Call(param.name, "v");
- auto* func =
- Func("func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
+TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets) {
+ auto* s = Structure("my_struct", utils::Vector{
+ Member("a", ty.array<f32>(4)),
+ });
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- spirv::Builder& b = Build();
+ auto* p = Let("p", nullptr, AddressOf("b"));
+ auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+ auto* expr = Call("arrayLength", p2);
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(p),
+ Decl(p2),
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
- if (param.name != "dpdx" && param.name != "dpdy" && param.name != "fwidth") {
- EXPECT_EQ(DumpInstructions(b.capabilities()),
- R"(OpCapability DerivativeControl
-)");
- }
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ ASSERT_EQ(b.functions().size(), 1_u);
+
+ auto* expected_types = R"(%5 = OpTypeFloat 32
+%4 = OpTypeRuntimeArray %5
+%3 = OpTypeStruct %4
+%2 = OpTypePointer StorageBuffer %3
+%1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid
%6 = OpTypeFunction %7
-)");
+%11 = OpTypeInt 32 0
+)";
+ auto got_types = DumpInstructions(b.types());
+ EXPECT_EQ(expected_types, got_types);
- auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
-%10 = ${op} %3 %11
+ auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
OpReturn
-)",
- "${op}", param.op);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
-}
-INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- BuiltinDeriveTest,
- testing::Values(BuiltinData{"dpdx", "OpDPdx"},
- BuiltinData{"dpdxFine", "OpDPdxFine"},
- BuiltinData{"dpdxCoarse", "OpDPdxCoarse"},
- BuiltinData{"dpdy", "OpDPdy"},
- BuiltinData{"dpdyFine", "OpDPdyFine"},
- BuiltinData{"dpdyCoarse", "OpDPdyCoarse"},
- BuiltinData{"fwidth", "OpFwidth"},
- BuiltinData{"fwidthFine", "OpFwidthFine"},
- BuiltinData{"fwidthCoarse", "OpFwidthCoarse"}));
+)";
+ auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+ EXPECT_EQ(expected_instructions, got_instructions);
-TEST_F(BuiltinBuilderTest, Call_Select) {
- auto* v3 = Global("v3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ Validate(b);
+}
- auto* bool_v3 = Global("bool_v3", ty.vec3<bool>(), ast::StorageClass::kPrivate);
- auto* expr = Call("select", "v3", "v3", "bool_v3");
- auto* func = Func("a_func", {}, ty.void_(),
- {
- Assign(Phony(), expr),
- });
+TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
+ // struct my_struct {
+ // a : array<f32>;
+ // };
+ // @binding(1) @group(2) var<storage, read> b : my_struct;
+ //
+ // fn a_func() {
+ // let p = &*&b;
+ // let p2 = &*p;
+ // let p3 = &((*p).a);
+ // arrayLength(&*p3);
+ // }
+ auto* s = Structure("my_struct", utils::Vector{
+ Member("a", ty.array<f32>(4)),
+ });
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
- spirv::Builder& b = Build();
+ auto* p = Let("p", nullptr, AddressOf(Deref(AddressOf("b"))));
+ auto* p2 = Let("p2", nullptr, AddressOf(Deref(p)));
+ auto* p3 = Let("p3", nullptr, AddressOf(MemberAccessor(Deref(p2), "a")));
+ auto* expr = Call("arrayLength", AddressOf(Deref(p3)));
- ASSERT_TRUE(b.GenerateGlobalVariable(v3)) << b.error();
- ASSERT_TRUE(b.GenerateGlobalVariable(bool_v3)) << b.error();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(p),
+ Decl(p2),
+ Decl(p3),
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%9 = OpTypeBool
-%8 = OpTypeVector %9 3
-%7 = OpTypePointer Private %8
-%10 = OpConstantNull %8
-%6 = OpVariable %7 Private %10
-%12 = OpTypeVoid
-%11 = OpTypeFunction %12
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%16 = OpLoad %8 %6
-%17 = OpLoad %3 %1
-%18 = OpLoad %3 %1
-%15 = OpSelect %3 %16 %17 %18
-OpReturn
-)");
-}
+ spirv::Builder& b = SanitizeAndBuild();
-// This tests that we do not push OpTypeSampledImage and float_0 type twice.
-TEST_F(BuiltinBuilderTest, Call_TextureSampleCompare_Twice) {
- auto* s = ty.sampler(ast::SamplerKind::kComparisonSampler);
- auto* t = ty.depth_texture(ast::TextureDimension::k2d);
+ ASSERT_TRUE(b.Build()) << b.error();
- auto* tex = Global("texture", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ ASSERT_EQ(b.functions().size(), 1_u);
- auto* sampler = Global("sampler", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
+ auto* expected_types = R"(%5 = OpTypeFloat 32
+%4 = OpTypeRuntimeArray %5
+%3 = OpTypeStruct %4
+%2 = OpTypePointer StorageBuffer %3
+%1 = OpVariable %2 StorageBuffer
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+%11 = OpTypeInt 32 0
+)";
+ auto got_types = DumpInstructions(b.types());
+ EXPECT_EQ(expected_types, got_types);
- auto* expr1 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1_f, 2_f), 2_f);
- auto* expr2 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1_f, 2_f), 2_f);
+ auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+OpReturn
+)";
+ auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+ EXPECT_EQ(expected_instructions, got_instructions);
- Func("f1", {}, ty.void_(), {CallStmt(expr1)}, {});
- Func("f2", {}, ty.void_(), {CallStmt(expr2)}, {});
+ Validate(b);
+}
- spirv::Builder& b = Build();
+} // namespace array_builtin_tests
- b.push_function(Function{});
+// Tests for Numeric builtins with float parameter
+namespace float_builtin_tests {
- ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
- ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
+using Builtin_Builder_SingleParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Scalar_f32) {
+ auto param = GetParam();
+ // Use a variable to prevent the function being evaluated as constant.
+ auto* scalar = Var("a", nullptr, Expr(1_f));
+ auto* expr = Call(param.name, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
+ Assign(Phony(), expr),
+ });
- EXPECT_EQ(b.GenerateExpression(expr1), 8u) << b.error();
- EXPECT_EQ(b.GenerateExpression(expr2), 17u) << b.error();
+ spirv::Builder& b = Build();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
-%2 = OpTypePointer UniformConstant %3
-%1 = OpVariable %2 UniformConstant
-%7 = OpTypeSampler
-%6 = OpTypePointer UniformConstant %7
-%5 = OpVariable %6 UniformConstant
-%11 = OpTypeSampledImage %3
-%13 = OpTypeVector %4 2
-%14 = OpConstant %4 1
-%15 = OpConstant %4 2
-%16 = OpConstantComposite %13 %14 %15
-)");
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpLoad %7 %5
-%10 = OpLoad %3 %1
-%12 = OpSampledImage %11 %10 %9
-%8 = OpImageSampleDrefImplicitLod %4 %12 %16 %15
-%18 = OpLoad %7 %5
-%19 = OpLoad %3 %1
-%20 = OpSampledImage %11 %19 %18
-%17 = OpImageSampleDrefImplicitLod %4 %20 %16 %15
-)");
+ auto got = DumpBuilder(b);
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %7 "a"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
+ param.op +
+ R"( %12
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad) {
- auto* var = Global("ident", ty.f32(), ast::StorageClass::kPrivate);
- auto* expr = Call("round", "ident");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto param = GetParam();
+ // Use a variable to prevent the function being evaluated as constant.
+ auto* scalar = Var("a", nullptr, Expr(1_h));
+ auto* expr = Call(param.name, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect =
- R"(%10 = OpExtInstImport "GLSL.std.450"
-OpName %1 "ident"
-OpName %7 "a_func"
-%3 = OpTypeFloat 32
-%2 = OpTypePointer Private %3
-%4 = OpConstantNull %3
-%1 = OpVariable %2 Private %4
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
-%7 = OpFunction %6 None %5
-%8 = OpLabel
-%11 = OpLoad %3 %1
-%9 = OpExtInst %3 %10 RoundEven %11
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %7 "a"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 16
+%6 = OpConstant %5 0x1p+0
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
+ param.op +
+ R"( %12
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-using Builtin_Builtin_SingleParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_SingleParam_Float_Test, Call_Scalar) {
+TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Vector_f32) {
auto param = GetParam();
- auto* expr = Call(param.name, 1_f);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+
+ // Use a variable to prevent the function being evaluated as constant.
+ auto* vec = Var("a", nullptr, vec2<f32>(1_f, 1_f));
+ auto* expr = Call(param.name, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -553,28 +593,42 @@ TEST_P(Builtin_Builtin_SingleParam_Float_Test, Call_Scalar) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "a"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%6 = OpTypeFloat 32
-%8 = OpConstant %6 1
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
param.op +
- R"( %8
+ R"( %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_SingleParam_Float_Test, Call_Vector) {
+TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
auto param = GetParam();
- auto* expr = Call(param.name, vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+
+ // Use a variable to prevent the function being evaluated as constant.
+ auto* vec = Var("a", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call(param.name, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -583,26 +637,33 @@ TEST_P(Builtin_Builtin_SingleParam_Float_Test, Call_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "a"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
param.op +
- R"( %10
+ R"( %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
+
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_SingleParam_Float_Test,
+ Builtin_Builder_SingleParam_Float_Test,
testing::Values(BuiltinData{"abs", "FAbs"},
BuiltinData{"acos", "Acos"},
BuiltinData{"asin", "Asin"},
@@ -628,10 +689,49 @@ INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
BuiltinData{"tanh", "Tanh"},
BuiltinData{"trunc", "Trunc"}));
-TEST_F(BuiltinBuilderTest, Call_Length_Scalar) {
- auto* expr = Call("length", 1_f);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Length_Scalar_f32) {
+ auto* scalar = Var("a", nullptr, Expr(1_f));
+ auto* expr = Call("length", scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %7 "a"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 Length %12
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Length_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* scalar = Var("a", nullptr, Expr(1_h));
+ auto* expr = Call("length", scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -640,25 +740,109 @@ TEST_F(BuiltinBuilderTest, Call_Length_Scalar) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %7 "a"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 16
+%6 = OpConstant %5 0x1p+0
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 Length %12
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Length_Vector_f32) {
+ auto* vec = Var("a", nullptr, vec2<f32>(1_f, 1_f));
+ auto* expr = Call("length", vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "a"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%6 = OpTypeFloat 32
-%8 = OpConstant %6 1
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %6 %13 Length %14
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Length_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("a", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call("length", vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "a"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 Length %8
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %6 %13 Length %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Length_Vector) {
- auto* expr = Call("length", vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Normalize_f32) {
+ auto* vec = Var("a", nullptr, vec2<f32>(1_f, 1_f));
+ auto* expr = Call("normalize", vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -667,27 +851,37 @@ TEST_F(BuiltinBuilderTest, Call_Length_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "a"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%6 = OpTypeFloat 32
-%8 = OpTypeVector %6 2
-%9 = OpConstant %6 1
-%10 = OpConstantComposite %8 %9 %9
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 Length %10
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 Normalize %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Normalize) {
- auto* expr = Call("normalize", vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Normalize_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("a", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call("normalize", vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -696,30 +890,36 @@ TEST_F(BuiltinBuilderTest, Call_Normalize) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "a"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 Normalize %10
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 Normalize %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-using Builtin_Builtin_DualParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_DualParam_Float_Test, Call_Scalar) {
+using Builtin_Builder_DualParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Scalar_f32) {
auto param = GetParam();
auto* scalar = Var("scalar", nullptr, Expr(1_f));
auto* expr = Call(param.name, scalar, scalar);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(scalar),
Assign(Phony(), expr),
});
@@ -753,12 +953,53 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_DualParam_Float_Test, Call_Vector) {
+TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto param = GetParam();
+ auto* scalar = Var("scalar", nullptr, Expr(1_h));
+ auto* expr = Call(param.name, scalar, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %7 "scalar"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 16
+%6 = OpConstant %5 0x1p+0
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%13 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
+ param.op +
+ R"( %12 %13
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Vector_f32) {
auto param = GetParam();
auto* vec = Var("vec", nullptr, vec2<f32>(1_f, 1_f));
auto* expr = Call(param.name, vec, vec);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(vec),
Assign(Phony(), expr),
});
@@ -793,18 +1034,104 @@ OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
+
+TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto param = GetParam();
+ auto* vec = Var("vec", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call(param.name, vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "vec"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
+ param.op +
+ R"( %14 %15
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_DualParam_Float_Test,
+ Builtin_Builder_DualParam_Float_Test,
testing::Values(BuiltinData{"atan2", "Atan2"},
BuiltinData{"max", "NMax"},
BuiltinData{"min", "NMin"},
BuiltinData{"pow", "Pow"},
BuiltinData{"step", "Step"}));
-TEST_F(BuiltinBuilderTest, Call_Reflect_Vector) {
- auto* expr = Call("reflect", vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Reflect_Vector_f32) {
+ auto* vec = Var("vec", nullptr, vec2<f32>(1_f, 1_f));
+ auto* expr = Call("reflect", vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "vec"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 Reflect %14 %15
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Reflect_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("vec", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call("reflect", vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -813,27 +1140,36 @@ TEST_F(BuiltinBuilderTest, Call_Reflect_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 Reflect %10 %10
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 Reflect %14 %15
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Distance_Scalar) {
- auto* expr = Call("distance", 1_f, 1_f);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Distance_Scalar_f32) {
+ auto* scalar = Var("scalar", nullptr, Expr(1_f));
+ auto* expr = Call("distance", scalar, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -842,25 +1178,150 @@ TEST_F(BuiltinBuilderTest, Call_Distance_Scalar) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %7 "scalar"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%13 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 Distance %12 %13
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Distance_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* scalar = Var("scalar", nullptr, Expr(1_h));
+ auto* expr = Call("distance", scalar, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %7 "scalar"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 16
+%6 = OpConstant %5 0x1p+0
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%13 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 Distance %12 %13
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Distance_Vector_f32) {
+ auto* vec = Var("vec", nullptr, vec2<f32>(1_f, 1_f));
+ auto* expr = Call("distance", vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%6 = OpTypeFloat 32
-%8 = OpConstant %6 1
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 Distance %8 %8
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%12 = OpExtInst %6 %13 Distance %14 %15
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Distance_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("vec", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call("distance", vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "vec"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%12 = OpExtInst %6 %13 Distance %14 %15
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Distance_Vector) {
- auto* expr = Call("distance", vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Cross_f32) {
+ auto* vec = Var("vec", nullptr, vec3<f32>(1_f, 1_f, 1_f));
+ auto* expr = Call("cross", vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -869,27 +1330,38 @@ TEST_F(BuiltinBuilderTest, Call_Distance_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%6 = OpTypeFloat 32
-%8 = OpTypeVector %6 2
-%9 = OpConstant %6 1
-%10 = OpConstantComposite %8 %9 %9
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 Distance %10 %10
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 Cross %14 %15
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Cross) {
- auto* expr = Call("cross", vec3<f32>(1_f, 1_f, 1_f), vec3<f32>(1_f, 1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_Cross_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("vec", nullptr, vec3<f16>(1_h, 1_h, 1_h));
+ auto* expr = Call("cross", vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -898,29 +1370,80 @@ TEST_F(BuiltinBuilderTest, Call_Cross) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 3
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9 %9
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 Cross %14 %15
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+using Builtin_Builder_ThreeParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Scalar_f32) {
+ auto param = GetParam();
+ auto* scalar = Var("scalar", nullptr, Expr(1_f));
+ auto* expr = Call(param.name, scalar, scalar, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %7 "scalar"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 Cross %10 %10
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%13 = OpLoad %5 %7
+%14 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
+ param.op +
+ R"( %12 %13 %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-using Builtin_Builtin_ThreeParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_ThreeParam_Float_Test, Call_Scalar) {
+TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Scalar_f16) {
+ Enable(ast::Extension::kF16);
+
auto param = GetParam();
- auto* expr = Call(param.name, 1_f, 1_f, 1_f);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* scalar = Var("scalar", nullptr, Expr(1_h));
+ auto* expr = Call(param.name, scalar, scalar, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -929,28 +1452,82 @@ TEST_P(Builtin_Builtin_ThreeParam_Float_Test, Call_Scalar) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %7 "scalar"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 16
+%6 = OpConstant %5 0x1p+0
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%13 = OpLoad %5 %7
+%14 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
+ param.op +
+ R"( %12 %13 %14
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Vector_f32) {
+ auto param = GetParam();
+ auto* vec = Var("vec", nullptr, vec2<f32>(1_f, 1_f));
+ auto* expr = Call(param.name, vec, vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%6 = OpTypeFloat 32
-%8 = OpConstant %6 1
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%16 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
param.op +
- R"( %8 %8 %8
+ R"( %14 %15 %16
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_ThreeParam_Float_Test, Call_Vector) {
+TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
auto param = GetParam();
- auto* expr = Call(param.name, vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* vec = Var("vec", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call(param.name, vec, vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -959,36 +1536,47 @@ TEST_P(Builtin_Builtin_ThreeParam_Float_Test, Call_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%16 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
param.op +
- R"( %10 %10 %10
+ R"( %14 %15 %16
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
+
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_ThreeParam_Float_Test,
+ Builtin_Builder_ThreeParam_Float_Test,
testing::Values(BuiltinData{"clamp", "NClamp"},
BuiltinData{"fma", "Fma"},
BuiltinData{"mix", "FMix"},
BuiltinData{"smoothstep", "SmoothStep"}));
-TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector) {
- auto* expr = Call("faceForward", vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector_f32) {
+ auto* vec = Var("vec", nullptr, vec2<f32>(1_f, 1_f));
+ auto* expr = Call("faceForward", vec, vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -997,29 +1585,436 @@ TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 FaceForward %10 %10 %10
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%16 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 FaceForward %14 %15 %16
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-using Builtin_Builtin_SingleParam_Sint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_SingleParam_Sint_Test, Call_Scalar) {
+TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("vec", nullptr, vec2<f16>(1_h, 1_h));
+ auto* expr = Call("faceForward", vec, vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
+OpName %3 "a_func"
+OpName %9 "vec"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%16 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 FaceForward %14 %15 %16
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Modf_f32) {
+ auto* vec = Var("vec", nullptr, vec2<f32>(1_f, 2_f));
+ auto* expr = Call("modf", vec);
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+ auto got = DumpBuilder(b);
+ auto* expect = R"(OpCapability Shader
+%15 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %3 "a_func"
+OpExecutionMode %3 OriginUpperLeft
+OpName %3 "a_func"
+OpName %10 "vec"
+OpName %14 "__modf_result_vec2"
+OpMemberName %14 0 "fract"
+OpMemberName %14 1 "whole"
+OpMemberDecorate %14 0 Offset 0
+OpMemberDecorate %14 1 Offset 8
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstant %6 2
+%9 = OpConstantComposite %5 %7 %8
+%11 = OpTypePointer Function %5
+%12 = OpConstantNull %5
+%14 = OpTypeStruct %5 %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%10 = OpVariable %11 Function %12
+OpStore %10 %9
+%16 = OpLoad %5 %10
+%13 = OpExtInst %14 %15 ModfStruct %16
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(expect, got);
+
+ Validate(b);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Modf_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("vec", nullptr, vec2<f16>(1_h, 2_h));
+ auto* expr = Call("modf", vec);
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+ auto got = DumpBuilder(b);
+ auto* expect = R"(OpCapability Shader
+OpCapability Float16
+OpCapability UniformAndStorageBuffer16BitAccess
+OpCapability StorageBuffer16BitAccess
+OpCapability StorageInputOutput16
+%15 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %3 "a_func"
+OpExecutionMode %3 OriginUpperLeft
+OpName %3 "a_func"
+OpName %10 "vec"
+OpName %14 "__modf_result_vec2_f16"
+OpMemberName %14 0 "fract"
+OpMemberName %14 1 "whole"
+OpMemberDecorate %14 0 Offset 0
+OpMemberDecorate %14 1 Offset 4
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstant %6 0x1p+1
+%9 = OpConstantComposite %5 %7 %8
+%11 = OpTypePointer Function %5
+%12 = OpConstantNull %5
+%14 = OpTypeStruct %5 %5
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%10 = OpVariable %11 Function %12
+OpStore %10 %9
+%16 = OpLoad %5 %10
+%13 = OpExtInst %14 %15 ModfStruct %16
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(expect, got);
+
+ Validate(b);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Frexp_f32) {
+ auto* vec = Var("vec", nullptr, vec2<f32>(1_f, 2_f));
+ auto* expr = Call("frexp", vec);
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+ auto got = DumpBuilder(b);
+ auto* expect = R"(OpCapability Shader
+%17 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %3 "a_func"
+OpExecutionMode %3 OriginUpperLeft
+OpName %3 "a_func"
+OpName %10 "vec"
+OpName %14 "__frexp_result_vec2"
+OpMemberName %14 0 "sig"
+OpMemberName %14 1 "exp"
+OpMemberDecorate %14 0 Offset 0
+OpMemberDecorate %14 1 Offset 8
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstant %6 2
+%9 = OpConstantComposite %5 %7 %8
+%11 = OpTypePointer Function %5
+%12 = OpConstantNull %5
+%16 = OpTypeInt 32 1
+%15 = OpTypeVector %16 2
+%14 = OpTypeStruct %5 %15
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%10 = OpVariable %11 Function %12
+OpStore %10 %9
+%18 = OpLoad %5 %10
+%13 = OpExtInst %14 %17 FrexpStruct %18
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(expect, got);
+
+ Validate(b);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Frexp_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec = Var("vec", nullptr, vec2<f16>(1_h, 2_h));
+ auto* expr = Call("frexp", vec);
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+ auto got = DumpBuilder(b);
+ auto* expect = R"(OpCapability Shader
+OpCapability Float16
+OpCapability UniformAndStorageBuffer16BitAccess
+OpCapability StorageBuffer16BitAccess
+OpCapability StorageInputOutput16
+%17 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %3 "a_func"
+OpExecutionMode %3 OriginUpperLeft
+OpName %3 "a_func"
+OpName %10 "vec"
+OpName %14 "__frexp_result_vec2_f16"
+OpMemberName %14 0 "sig"
+OpMemberName %14 1 "exp"
+OpMemberDecorate %14 0 Offset 0
+OpMemberDecorate %14 1 Offset 8
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+0
+%8 = OpConstant %6 0x1p+1
+%9 = OpConstantComposite %5 %7 %8
+%11 = OpTypePointer Function %5
+%12 = OpConstantNull %5
+%16 = OpTypeInt 32 1
+%15 = OpTypeVector %16 2
+%14 = OpTypeStruct %5 %15
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%10 = OpVariable %11 Function %12
+OpStore %10 %9
+%18 = OpLoad %5 %10
+%13 = OpExtInst %14 %17 FrexpStruct %18
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(expect, got);
+
+ Validate(b);
+}
+
+} // namespace float_builtin_tests
+
+// Tests for Numeric builtins with all integer parameter
+namespace integer_builtin_tests {
+
+using BuiltinIntTest = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(BuiltinIntTest, Call_SInt_Scalar) {
+ auto param = GetParam();
+ auto* var = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* expr = Call(param.name, "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+%2 = OpTypePointer Private %3
+%4 = OpConstantNull %3
+%1 = OpVariable %2 Private %4
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+
+ auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
+%9 = ${op} %3 %10
+OpReturn
+)",
+ "${op}", param.op);
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+}
+
+TEST_P(BuiltinIntTest, Call_SInt_Vector) {
+ auto param = GetParam();
+ auto* var = GlobalVar("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+ auto* expr = Call(param.name, "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+)");
+
+ auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
+%10 = ${op} %3 %11
+OpReturn
+)",
+ "${op}", param.op);
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+}
+
+TEST_P(BuiltinIntTest, Call_UInt_Scalar) {
+ auto param = GetParam();
+ auto* var = GlobalVar("v", ty.u32(), ast::StorageClass::kPrivate);
+ auto* expr = Call(param.name, "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 0
+%2 = OpTypePointer Private %3
+%4 = OpConstantNull %3
+%1 = OpVariable %2 Private %4
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+
+ auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
+%9 = ${op} %3 %10
+OpReturn
+)",
+ "${op}", param.op);
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+}
+
+TEST_P(BuiltinIntTest, Call_UInt_Vector) {
auto param = GetParam();
- auto* expr = Call(param.name, 1_i);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* var = GlobalVar("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+ auto* expr = Call(param.name, "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+)");
+
+ auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
+%10 = ${op} %3 %11
+OpReturn
+)",
+ "${op}", param.op);
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+}
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+ BuiltinIntTest,
+ testing::Values(BuiltinData{"countOneBits", "OpBitCount"},
+ BuiltinData{"reverseBits", "OpBitReverse"}));
+
+using Builtin_Builder_SingleParam_Sint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_SingleParam_Sint_Test, Call_Scalar) {
+ auto param = GetParam();
+ auto* scalar = Var("scalar", nullptr, Expr(1_i));
+ auto* expr = Call(param.name, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -1028,28 +2023,36 @@ TEST_P(Builtin_Builtin_SingleParam_Sint_Test, Call_Scalar) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %7 "scalar"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%6 = OpTypeInt 32 1
-%8 = OpConstant %6 1
+%5 = OpTypeInt 32 1
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
param.op +
- R"( %8
+ R"( %12
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_SingleParam_Sint_Test, Call_Vector) {
+TEST_P(Builtin_Builder_SingleParam_Sint_Test, Call_Vector) {
auto param = GetParam();
- auto* expr = Call(param.name, vec2<i32>(1_i, 1_i));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* vec = Var("vec", nullptr, vec2<i32>(1_i, 1_i));
+ auto* expr = Call(param.name, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -1058,34 +2061,42 @@ TEST_P(Builtin_Builtin_SingleParam_Sint_Test, Call_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 1
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeInt 32 1
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
param.op +
- R"( %10
+ R"( %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_SingleParam_Sint_Test,
+ Builtin_Builder_SingleParam_Sint_Test,
testing::Values(BuiltinData{"abs", "SAbs"}));
// Calling abs() on an unsigned integer scalar / vector is a no-op.
-using Builtin_Builtin_Abs_Uint_Test = BuiltinBuilderTest;
-TEST_F(Builtin_Builtin_Abs_Uint_Test, Call_Scalar) {
- auto* expr = Call("abs", Expr(1_u));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+using Builtin_Builder_Abs_Uint_Test = BuiltinBuilderTest;
+TEST_F(Builtin_Builder_Abs_Uint_Test, Call_Scalar) {
+ auto* scalar = Var("scalar", nullptr, Expr(1_u));
+ auto* expr = Call("abs", scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -1095,22 +2106,30 @@ TEST_F(Builtin_Builtin_Abs_Uint_Test, Call_Scalar) {
auto got = DumpBuilder(b);
auto expect = R"(OpName %3 "a_func"
+OpName %7 "scalar"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 1
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%11 = OpLoad %5 %7
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_F(Builtin_Builtin_Abs_Uint_Test, Call_Vector) {
- auto* expr = Call("abs", vec2<u32>(1_u, 1_u));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+TEST_F(Builtin_Builder_Abs_Uint_Test, Call_Vector) {
+ auto* scalar = Var("scalar", nullptr, vec2<u32>(1_u, 1_u));
+ auto* expr = Call("abs", scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -1120,27 +2139,33 @@ TEST_F(Builtin_Builtin_Abs_Uint_Test, Call_Vector) {
auto got = DumpBuilder(b);
auto expect = R"(OpName %3 "a_func"
+OpName %9 "scalar"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 0
-%6 = OpTypeVector %7 2
-%8 = OpConstant %7 1
-%9 = OpConstantComposite %6 %8 %8
+%6 = OpTypeInt 32 0
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%13 = OpLoad %5 %9
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-using Builtin_Builtin_DualParam_SInt_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_DualParam_SInt_Test, Call_Scalar) {
+using Builtin_Builder_DualParam_SInt_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_DualParam_SInt_Test, Call_Scalar) {
auto param = GetParam();
auto* scalar = Var("scalar", nullptr, Expr(1_i));
auto* expr = Call(param.name, scalar, scalar);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(scalar),
Assign(Phony(), expr),
});
@@ -1174,12 +2199,12 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_DualParam_SInt_Test, Call_Vector) {
+TEST_P(Builtin_Builder_DualParam_SInt_Test, Call_Vector) {
auto param = GetParam();
auto* vec = Var("vec", nullptr, vec2<i32>(1_i, 1_i));
auto* expr = Call(param.name, vec, vec);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(vec),
Assign(Phony(), expr),
});
@@ -1215,16 +2240,16 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_DualParam_SInt_Test,
+ Builtin_Builder_DualParam_SInt_Test,
testing::Values(BuiltinData{"max", "SMax"}, BuiltinData{"min", "SMin"}));
-using Builtin_Builtin_DualParam_UInt_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_DualParam_UInt_Test, Call_Scalar) {
+using Builtin_Builder_DualParam_UInt_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_DualParam_UInt_Test, Call_Scalar) {
auto param = GetParam();
auto* scalar = Var("scalar", nullptr, Expr(1_u));
auto* expr = Call(param.name, scalar, scalar);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(scalar),
Assign(Phony(), expr),
});
@@ -1258,12 +2283,12 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_DualParam_UInt_Test, Call_Vector) {
+TEST_P(Builtin_Builder_DualParam_UInt_Test, Call_Vector) {
auto param = GetParam();
auto* vec = Var("vec", nullptr, vec2<u32>(1_u, 1_u));
auto* expr = Call(param.name, vec, vec);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(vec),
Assign(Phony(), expr),
});
@@ -1299,15 +2324,17 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_DualParam_UInt_Test,
+ Builtin_Builder_DualParam_UInt_Test,
testing::Values(BuiltinData{"max", "UMax"}, BuiltinData{"min", "UMin"}));
-using Builtin_Builtin_ThreeParam_Sint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_ThreeParam_Sint_Test, Call_Scalar) {
+using Builtin_Builder_ThreeParam_Sint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_ThreeParam_Sint_Test, Call_Scalar) {
auto param = GetParam();
- auto* expr = Call(param.name, 1_i, 1_i, 1_i);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* scalar = Var("scalar", nullptr, Expr(1_i));
+ auto* expr = Call(param.name, scalar, scalar, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -1316,28 +2343,38 @@ TEST_P(Builtin_Builtin_ThreeParam_Sint_Test, Call_Scalar) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %7 "scalar"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%6 = OpTypeInt 32 1
-%8 = OpConstant %6 1
+%5 = OpTypeInt 32 1
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%13 = OpLoad %5 %7
+%14 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
param.op +
- R"( %8 %8 %8
+ R"( %12 %13 %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_ThreeParam_Sint_Test, Call_Vector) {
+TEST_P(Builtin_Builder_ThreeParam_Sint_Test, Call_Vector) {
auto param = GetParam();
- auto* expr = Call(param.name, vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* vec = Var("vec", nullptr, vec2<i32>(1_i, 1_i));
+ auto* expr = Call(param.name, vec, vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -1346,34 +2383,44 @@ TEST_P(Builtin_Builtin_ThreeParam_Sint_Test, Call_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 1
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeInt 32 1
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%16 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
param.op +
- R"( %10 %10 %10
+ R"( %14 %15 %16
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_ThreeParam_Sint_Test,
+ Builtin_Builder_ThreeParam_Sint_Test,
testing::Values(BuiltinData{"clamp", "SClamp"}));
-using Builtin_Builtin_ThreeParam_Uint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_ThreeParam_Uint_Test, Call_Scalar) {
+using Builtin_Builder_ThreeParam_Uint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_ThreeParam_Uint_Test, Call_Scalar) {
auto param = GetParam();
- auto* expr = Call(param.name, 1_u, 1_u, 1_u);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* scalar = Var("scalar", nullptr, Expr(1_u));
+ auto* expr = Call(param.name, scalar, scalar, scalar);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(scalar),
Assign(Phony(), expr),
});
@@ -1382,28 +2429,38 @@ TEST_P(Builtin_Builtin_ThreeParam_Uint_Test, Call_Scalar) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %7 "scalar"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%6 = OpTypeInt 32 0
-%8 = OpConstant %6 1
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%13 = OpLoad %5 %7
+%14 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
param.op +
- R"( %8 %8 %8
+ R"( %12 %13 %14
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
-TEST_P(Builtin_Builtin_ThreeParam_Uint_Test, Call_Vector) {
+TEST_P(Builtin_Builder_ThreeParam_Uint_Test, Call_Vector) {
auto param = GetParam();
- auto* expr = Call(param.name, vec2<u32>(1_u, 1_u), vec2<u32>(1_u, 1_u), vec2<u32>(1_u, 1_u));
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* vec = Var("vec", nullptr, vec2<u32>(1_u, 1_u));
+ auto* expr = Call(param.name, vec, vec, vec);
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(vec),
Assign(Phony(), expr),
});
@@ -1412,111 +2469,386 @@ TEST_P(Builtin_Builtin_ThreeParam_Uint_Test, Call_Vector) {
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
- auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+ auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
+OpName %9 "vec"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 0
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeInt 32 0
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%15 = OpLoad %5 %9
+%16 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
param.op +
- R"( %10 %10 %10
+ R"( %14 %15 %16
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(got, expect);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_ThreeParam_Uint_Test,
+ Builtin_Builder_ThreeParam_Uint_Test,
testing::Values(BuiltinData{"clamp", "UClamp"}));
-TEST_F(BuiltinBuilderTest, Call_Modf) {
- auto* expr = Call("modf", vec2<f32>(1_f, 2_f));
- Func("a_func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
+TEST_F(BuiltinBuilderTest, Call_ExtractBits_i32) {
+ auto* v = Var("v", ty.i32());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("extractBits", v, offset, count);
+ auto* func = WrapInFunction(v, offset, count, call);
spirv::Builder& b = Build();
- ASSERT_TRUE(b.Build()) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
auto got = DumpBuilder(b);
- auto* expect = R"(OpCapability Shader
-%9 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %3 "a_func"
-OpExecutionMode %3 OriginUpperLeft
-OpName %3 "a_func"
-OpName %6 "__modf_result_vec2"
-OpMemberName %6 0 "fract"
-OpMemberName %6 1 "whole"
-OpMemberDecorate %6 0 Offset 0
-OpMemberDecorate %6 1 Offset 8
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %9 "offset"
+OpName %13 "count"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%8 = OpTypeFloat 32
-%7 = OpTypeVector %8 2
-%6 = OpTypeStruct %7 %7
-%10 = OpConstant %8 1
-%11 = OpConstant %8 2
-%12 = OpConstantComposite %7 %10 %11
+%7 = OpTypeInt 32 1
+%6 = OpTypePointer Function %7
+%8 = OpConstantNull %7
+%11 = OpTypeInt 32 0
+%10 = OpTypePointer Function %11
+%12 = OpConstantNull %11
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %9 ModfStruct %12
+%5 = OpVariable %6 Function %8
+%9 = OpVariable %10 Function %12
+%13 = OpVariable %10 Function %12
+%15 = OpLoad %7 %5
+%16 = OpLoad %11 %9
+%17 = OpLoad %11 %13
+%14 = OpBitFieldSExtract %7 %15 %16 %17
OpReturn
OpFunctionEnd
)";
- EXPECT_EQ(expect, got);
+ EXPECT_EQ(got, expect);
+}
- Validate(b);
+TEST_F(BuiltinBuilderTest, Call_ExtractBits_u32) {
+ auto* v = Var("v", ty.u32());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("extractBits", v, offset, count);
+ auto* func = WrapInFunction(v, offset, count, call);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %9 "offset"
+OpName %10 "count"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeInt 32 0
+%6 = OpTypePointer Function %7
+%8 = OpConstantNull %7
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%5 = OpVariable %6 Function %8
+%9 = OpVariable %6 Function %8
+%10 = OpVariable %6 Function %8
+%12 = OpLoad %7 %5
+%13 = OpLoad %7 %9
+%14 = OpLoad %7 %10
+%11 = OpBitFieldUExtract %7 %12 %13 %14
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Frexp) {
- auto* expr = Call("frexp", vec2<f32>(1_f, 2_f));
- Func("a_func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
+TEST_F(BuiltinBuilderTest, Call_ExtractBits_vec3_i32) {
+ auto* v = Var("v", ty.vec3<i32>());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("extractBits", v, offset, count);
+ auto* func = WrapInFunction(v, offset, count, call);
spirv::Builder& b = Build();
- ASSERT_TRUE(b.Build()) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
auto got = DumpBuilder(b);
- auto* expect = R"(OpCapability Shader
-%11 = OpExtInstImport "GLSL.std.450"
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %3 "a_func"
-OpExecutionMode %3 OriginUpperLeft
-OpName %3 "a_func"
-OpName %6 "__frexp_result_vec2"
-OpMemberName %6 0 "sig"
-OpMemberName %6 1 "exp"
-OpMemberDecorate %6 0 Offset 0
-OpMemberDecorate %6 1 Offset 8
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %10 "offset"
+OpName %14 "count"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeInt 32 1
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypeInt 32 0
+%11 = OpTypePointer Function %12
+%13 = OpConstantNull %12
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%5 = OpVariable %6 Function %9
+%10 = OpVariable %11 Function %13
+%14 = OpVariable %11 Function %13
+%16 = OpLoad %7 %5
+%17 = OpLoad %12 %10
+%18 = OpLoad %12 %14
+%15 = OpBitFieldSExtract %7 %16 %17 %18
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_ExtractBits_vec3_u32) {
+ auto* v = Var("v", ty.vec3<u32>());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("extractBits", v, offset, count);
+ auto* func = WrapInFunction(v, offset, count, call);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %10 "offset"
+OpName %13 "count"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
-%8 = OpTypeFloat 32
-%7 = OpTypeVector %8 2
-%10 = OpTypeInt 32 1
-%9 = OpTypeVector %10 2
-%6 = OpTypeStruct %7 %9
-%12 = OpConstant %8 1
-%13 = OpConstant %8 2
-%14 = OpConstantComposite %7 %12 %13
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%11 = OpTypePointer Function %8
+%12 = OpConstantNull %8
%3 = OpFunction %2 None %1
%4 = OpLabel
-%5 = OpExtInst %6 %11 FrexpStruct %14
+%5 = OpVariable %6 Function %9
+%10 = OpVariable %11 Function %12
+%13 = OpVariable %11 Function %12
+%15 = OpLoad %7 %5
+%16 = OpLoad %8 %10
+%17 = OpLoad %8 %13
+%14 = OpBitFieldUExtract %7 %15 %16 %17
OpReturn
OpFunctionEnd
)";
- EXPECT_EQ(expect, got);
+ EXPECT_EQ(got, expect);
+}
- Validate(b);
+TEST_F(BuiltinBuilderTest, Call_InsertBits_i32) {
+ auto* v = Var("v", ty.i32());
+ auto* n = Var("n", ty.i32());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("insertBits", v, n, offset, count);
+ auto* func = WrapInFunction(v, n, offset, count, call);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %9 "n"
+OpName %10 "offset"
+OpName %14 "count"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeInt 32 1
+%6 = OpTypePointer Function %7
+%8 = OpConstantNull %7
+%12 = OpTypeInt 32 0
+%11 = OpTypePointer Function %12
+%13 = OpConstantNull %12
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%5 = OpVariable %6 Function %8
+%9 = OpVariable %6 Function %8
+%10 = OpVariable %11 Function %13
+%14 = OpVariable %11 Function %13
+%16 = OpLoad %7 %5
+%17 = OpLoad %7 %9
+%18 = OpLoad %12 %10
+%19 = OpLoad %12 %14
+%15 = OpBitFieldInsert %7 %16 %17 %18 %19
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_InsertBits_u32) {
+ auto* v = Var("v", ty.u32());
+ auto* n = Var("n", ty.u32());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("insertBits", v, n, offset, count);
+ auto* func = WrapInFunction(v, n, offset, count, call);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %9 "n"
+OpName %10 "offset"
+OpName %11 "count"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeInt 32 0
+%6 = OpTypePointer Function %7
+%8 = OpConstantNull %7
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%5 = OpVariable %6 Function %8
+%9 = OpVariable %6 Function %8
+%10 = OpVariable %6 Function %8
+%11 = OpVariable %6 Function %8
+%13 = OpLoad %7 %5
+%14 = OpLoad %7 %9
+%15 = OpLoad %7 %10
+%16 = OpLoad %7 %11
+%12 = OpBitFieldInsert %7 %13 %14 %15 %16
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_InsertBits_vec3_i32) {
+ auto* v = Var("v", ty.vec3<i32>());
+ auto* n = Var("n", ty.vec3<i32>());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("insertBits", v, n, offset, count);
+ auto* func = WrapInFunction(v, n, offset, count, call);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %10 "n"
+OpName %11 "offset"
+OpName %15 "count"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeInt 32 1
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%13 = OpTypeInt 32 0
+%12 = OpTypePointer Function %13
+%14 = OpConstantNull %13
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%5 = OpVariable %6 Function %9
+%10 = OpVariable %6 Function %9
+%11 = OpVariable %12 Function %14
+%15 = OpVariable %12 Function %14
+%17 = OpLoad %7 %5
+%18 = OpLoad %7 %10
+%19 = OpLoad %13 %11
+%20 = OpLoad %13 %15
+%16 = OpBitFieldInsert %7 %17 %18 %19 %20
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_InsertBits_vec3_u32) {
+ auto* v = Var("v", ty.vec3<u32>());
+ auto* n = Var("n", ty.vec3<u32>());
+ auto* offset = Var("offset", ty.u32());
+ auto* count = Var("count", ty.u32());
+ auto* call = Call("insertBits", v, n, offset, count);
+ auto* func = WrapInFunction(v, n, offset, count, call);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %5 "v"
+OpName %10 "n"
+OpName %11 "offset"
+OpName %14 "count"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypePointer Function %8
+%13 = OpConstantNull %8
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%5 = OpVariable %6 Function %9
+%10 = OpVariable %6 Function %9
+%11 = OpVariable %12 Function %13
+%14 = OpVariable %12 Function %13
+%16 = OpLoad %7 %5
+%17 = OpLoad %7 %10
+%18 = OpLoad %8 %11
+%19 = OpLoad %8 %14
+%15 = OpBitFieldInsert %7 %16 %17 %18 %19
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Determinant) {
- auto* var = Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+} // namespace integer_builtin_tests
+
+// Tests for Numeric builtins with matrix parameter, i.e. "determinant" and "transpose"
+namespace matrix_builtin_tests {
+
+TEST_F(BuiltinBuilderTest, Call_Determinant_f32) {
+ auto* var = GlobalVar("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("determinant", "var");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Phony(), expr),
});
@@ -1547,11 +2879,48 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_Transpose) {
- auto* var = Global("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+TEST_F(BuiltinBuilderTest, Call_Determinant_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("var", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
+ auto* expr = Call("determinant", "var");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ auto got = DumpBuilder(b);
+ auto expect = R"(%12 = OpExtInstImport "GLSL.std.450"
+OpName %1 "var"
+OpName %9 "a_func"
+%5 = OpTypeFloat 16
+%4 = OpTypeVector %5 3
+%3 = OpTypeMatrix %4 3
+%2 = OpTypePointer Private %3
+%6 = OpConstantNull %3
+%1 = OpVariable %2 Private %6
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+%9 = OpFunction %8 None %7
+%10 = OpLabel
+%13 = OpLoad %3 %1
+%11 = OpExtInst %5 %12 Determinant %13
+OpReturn
+OpFunctionEnd
+)";
+ EXPECT_EQ(got, expect);
+}
+
+TEST_F(BuiltinBuilderTest, Call_Transpose_f32) {
+ auto* var = GlobalVar("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("transpose", "var");
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Assign(Phony(), expr),
});
@@ -1583,207 +2952,281 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_ArrayLength) {
- auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
- auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
-
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
- CallStmt(expr),
- },
- ast::AttributeList{
- Stage(ast::PipelineStage::kFragment),
- });
+TEST_F(BuiltinBuilderTest, Call_Transpose_f16) {
+ Enable(ast::Extension::kF16);
- spirv::Builder& b = SanitizeAndBuild();
-
- ASSERT_TRUE(b.Build()) << b.error();
+ auto* var = GlobalVar("var", ty.mat2x3<f16>(), ast::StorageClass::kPrivate);
+ auto* expr = Call("transpose", "var");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
- ASSERT_EQ(b.functions().size(), 1_u);
+ spirv::Builder& b = Build();
- auto* expected_types = R"(%5 = OpTypeFloat 32
-%4 = OpTypeRuntimeArray %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer StorageBuffer %3
-%1 = OpVariable %2 StorageBuffer
-%7 = OpTypeVoid
-%6 = OpTypeFunction %7
-%11 = OpTypeInt 32 0
-)";
- auto got_types = DumpInstructions(b.types());
- EXPECT_EQ(expected_types, got_types);
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+ auto got = DumpBuilder(b);
+ auto expect = R"(OpName %1 "var"
+OpName %9 "a_func"
+%5 = OpTypeFloat 16
+%4 = OpTypeVector %5 3
+%3 = OpTypeMatrix %4 2
+%2 = OpTypePointer Private %3
+%6 = OpConstantNull %3
+%1 = OpVariable %2 Private %6
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+%13 = OpTypeVector %5 2
+%12 = OpTypeMatrix %13 3
+%9 = OpFunction %8 None %7
+%10 = OpLabel
+%14 = OpLoad %3 %1
+%11 = OpTranspose %12 %14
OpReturn
+OpFunctionEnd
)";
- auto got_instructions = DumpInstructions(b.functions()[0].instructions());
- EXPECT_EQ(expected_instructions, got_instructions);
-
- Validate(b);
+ EXPECT_EQ(got, expect);
}
-TEST_F(BuiltinBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
- auto* s = Structure("my_struct", {
- Member("z", ty.f32()),
- Member(4, "a", ty.array<f32>(4)),
- });
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
- auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
+} // namespace matrix_builtin_tests
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
- CallStmt(expr),
- },
- ast::AttributeList{
- Stage(ast::PipelineStage::kFragment),
- });
+// Tests for Numeric builtins with float and integer vector parameter, i.e. "dot"
+namespace vector_builtin_tests {
- spirv::Builder& b = SanitizeAndBuild();
+TEST_F(BuiltinBuilderTest, Call_Dot_F32) {
+ auto* var = GlobalVar("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* expr = Call("dot", "v", "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
- ASSERT_TRUE(b.Build()) << b.error();
+ spirv::Builder& b = Build();
- ASSERT_EQ(b.functions().size(), 1_u);
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- auto* expected_types = R"(%4 = OpTypeFloat 32
-%5 = OpTypeRuntimeArray %4
-%3 = OpTypeStruct %4 %5
-%2 = OpTypePointer StorageBuffer %3
-%1 = OpVariable %2 StorageBuffer
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
%7 = OpTypeVoid
%6 = OpTypeFunction %7
-%11 = OpTypeInt 32 0
-)";
- auto got_types = DumpInstructions(b.types());
- EXPECT_EQ(expected_types, got_types);
-
- auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%11 = OpLoad %3 %1
+%12 = OpLoad %3 %1
+%10 = OpDot %4 %11 %12
OpReturn
-)";
- auto got_instructions = DumpInstructions(b.functions()[0].instructions());
- EXPECT_EQ(expected_instructions, got_instructions);
-
- Validate(b);
+)");
}
-TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets) {
- auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+TEST_F(BuiltinBuilderTest, Call_Dot_F16) {
+ Enable(ast::Extension::kF16);
- auto* p = Let("p", nullptr, AddressOf("b"));
- auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
- auto* expr = Call("arrayLength", p2);
+ auto* var = GlobalVar("v", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+ auto* expr = Call("dot", "v", "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
- Decl(p),
- Decl(p2),
- CallStmt(expr),
- },
- ast::AttributeList{
- Stage(ast::PipelineStage::kFragment),
- });
+ spirv::Builder& b = Build();
- spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- ASSERT_TRUE(b.Build()) << b.error();
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 16
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%11 = OpLoad %3 %1
+%12 = OpLoad %3 %1
+%10 = OpDot %4 %11 %12
+OpReturn
+)");
+}
- ASSERT_EQ(b.functions().size(), 1_u);
+TEST_F(BuiltinBuilderTest, Call_Dot_U32) {
+ auto* var = GlobalVar("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+ auto* expr = Call("dot", "v", "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
- auto* expected_types = R"(%5 = OpTypeFloat 32
-%4 = OpTypeRuntimeArray %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer StorageBuffer %3
-%1 = OpVariable %2 StorageBuffer
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
%7 = OpTypeVoid
%6 = OpTypeFunction %7
-%11 = OpTypeInt 32 0
-)";
- auto got_types = DumpInstructions(b.types());
- EXPECT_EQ(expected_types, got_types);
-
- auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%11 = OpLoad %3 %1
+%12 = OpLoad %3 %1
+%13 = OpCompositeExtract %4 %11 0
+%14 = OpCompositeExtract %4 %12 0
+%15 = OpIMul %4 %13 %14
+%16 = OpCompositeExtract %4 %11 1
+%17 = OpCompositeExtract %4 %12 1
+%18 = OpIMul %4 %16 %17
+%19 = OpIAdd %4 %15 %18
+%20 = OpCompositeExtract %4 %11 2
+%21 = OpCompositeExtract %4 %12 2
+%22 = OpIMul %4 %20 %21
+%10 = OpIAdd %4 %19 %22
OpReturn
-)";
- auto got_instructions = DumpInstructions(b.functions()[0].instructions());
- EXPECT_EQ(expected_instructions, got_instructions);
+)");
+}
- Validate(b);
+TEST_F(BuiltinBuilderTest, Call_Dot_I32) {
+ auto* var = GlobalVar("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+ auto* expr = Call("dot", "v", "v");
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Assign(Phony(), expr),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%11 = OpLoad %3 %1
+%12 = OpLoad %3 %1
+%13 = OpCompositeExtract %4 %11 0
+%14 = OpCompositeExtract %4 %12 0
+%15 = OpIMul %4 %13 %14
+%16 = OpCompositeExtract %4 %11 1
+%17 = OpCompositeExtract %4 %12 1
+%18 = OpIMul %4 %16 %17
+%19 = OpIAdd %4 %15 %18
+%20 = OpCompositeExtract %4 %11 2
+%21 = OpCompositeExtract %4 %12 2
+%22 = OpIMul %4 %20 %21
+%10 = OpIAdd %4 %19 %22
+OpReturn
+)");
}
-TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
- // struct my_struct {
- // a : array<f32>;
- // };
- // @binding(1) @group(2) var<storage, read> b : my_struct;
- //
- // fn a_func() {
- // let p = &*&b;
- // let p2 = &*p;
- // let p3 = &((*p).a);
- // arrayLength(&*p3);
- // }
- auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+} // namespace vector_builtin_tests
- auto* p = Let("p", nullptr, AddressOf(Deref(AddressOf("b"))));
- auto* p2 = Let("p2", nullptr, AddressOf(Deref(p)));
- auto* p3 = Let("p3", nullptr, AddressOf(MemberAccessor(Deref(p2), "a")));
- auto* expr = Call("arrayLength", AddressOf(Deref(p3)));
+// Tests for Derivative builtins
+namespace derivative_builtin_tests {
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
- Decl(p),
- Decl(p2),
- Decl(p3),
- CallStmt(expr),
- },
- ast::AttributeList{
- Stage(ast::PipelineStage::kFragment),
- });
+using BuiltinDeriveTest = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(BuiltinDeriveTest, Call_Derivative_Scalar) {
+ auto param = GetParam();
+ auto* var = GlobalVar("v", ty.f32(), ast::StorageClass::kPrivate);
+ auto* expr = Call(param.name, "v");
+ auto* func = Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
- spirv::Builder& b = SanitizeAndBuild();
+ spirv::Builder& b = Build();
- ASSERT_TRUE(b.Build()) << b.error();
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- ASSERT_EQ(b.functions().size(), 1_u);
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+%2 = OpTypePointer Private %3
+%4 = OpConstantNull %3
+%1 = OpVariable %2 Private %4
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
- auto* expected_types = R"(%5 = OpTypeFloat 32
-%4 = OpTypeRuntimeArray %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer StorageBuffer %3
-%1 = OpVariable %2 StorageBuffer
+ auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
+%9 = ${op} %3 %10
+OpReturn
+)",
+ "${op}", param.op);
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+}
+
+TEST_P(BuiltinDeriveTest, Call_Derivative_Vector) {
+ auto param = GetParam();
+ auto* var = GlobalVar("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* expr = Call(param.name, "v");
+ auto* func = Func("func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(expr),
+ },
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+
+ if (param.name != "dpdx" && param.name != "dpdy" && param.name != "fwidth") {
+ EXPECT_EQ(DumpInstructions(b.capabilities()),
+ R"(OpCapability DerivativeControl
+)");
+ }
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
%7 = OpTypeVoid
%6 = OpTypeFunction %7
-%11 = OpTypeInt 32 0
-)";
- auto got_types = DumpInstructions(b.types());
- EXPECT_EQ(expected_types, got_types);
+)");
- auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+ auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
+%10 = ${op} %3 %11
OpReturn
-)";
- auto got_instructions = DumpInstructions(b.functions()[0].instructions());
- EXPECT_EQ(expected_instructions, got_instructions);
-
- Validate(b);
+)",
+ "${op}", param.op);
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
}
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+ BuiltinDeriveTest,
+ testing::Values(BuiltinData{"dpdx", "OpDPdx"},
+ BuiltinData{"dpdxFine", "OpDPdxFine"},
+ BuiltinData{"dpdxCoarse", "OpDPdxCoarse"},
+ BuiltinData{"dpdy", "OpDPdy"},
+ BuiltinData{"dpdyFine", "OpDPdyFine"},
+ BuiltinData{"dpdyCoarse", "OpDPdyCoarse"},
+ BuiltinData{"fwidth", "OpFwidth"},
+ BuiltinData{"fwidthFine", "OpFwidthFine"},
+ BuiltinData{"fwidthCoarse", "OpFwidthCoarse"}));
+
+} // namespace derivative_builtin_tests
+
+// Tests for Atomic builtins
+namespace atomic_builtin_tests {
TEST_F(BuiltinBuilderTest, Call_AtomicLoad) {
// struct S {
@@ -1797,22 +3240,24 @@ TEST_F(BuiltinBuilderTest, Call_AtomicLoad) {
// let u : u32 = atomicLoad(&b.u);
// let i : i32 = atomicLoad(&b.i);
// }
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("u", ty.atomic<u32>()),
Member("i", ty.atomic<i32>()),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("u", ty.u32(), Call("atomicLoad", AddressOf(MemberAccessor("b", "u"))))),
Decl(Let("i", ty.i32(), Call("atomicLoad", AddressOf(MemberAccessor("b", "i"))))),
},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -1861,24 +3306,26 @@ TEST_F(BuiltinBuilderTest, Call_AtomicStore) {
// atomicStore(&b.u, u);
// atomicStore(&b.i, i);
// }
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("u", ty.atomic<u32>()),
Member("i", ty.atomic<i32>()),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("u", nullptr, Expr(1_u))),
Decl(Var("i", nullptr, Expr(2_i))),
CallStmt(Call("atomicStore", AddressOf(MemberAccessor("b", "u")), "u")),
CallStmt(Call("atomicStore", AddressOf(MemberAccessor("b", "i")), "i")),
},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -1922,8 +3369,8 @@ OpReturn
Validate(b);
}
-using Builtin_Builtin_AtomicRMW_i32 = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_AtomicRMW_i32, Test) {
+using Builtin_Builder_AtomicRMW_i32 = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_AtomicRMW_i32, Test) {
// struct S {
// v : atomic<i32>;
// }
@@ -1934,22 +3381,24 @@ TEST_P(Builtin_Builtin_AtomicRMW_i32, Test) {
// var v = 10;
// let x : i32 = atomicOP(&b.v, v);
// }
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("v", ty.atomic<i32>()),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("v", nullptr, Expr(10_i))),
Decl(Let("x", ty.i32(),
Call(GetParam().name, AddressOf(MemberAccessor("b", "v")), "v"))),
},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -1987,7 +3436,7 @@ TEST_P(Builtin_Builtin_AtomicRMW_i32, Test) {
Validate(b);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_AtomicRMW_i32,
+ Builtin_Builder_AtomicRMW_i32,
testing::Values(BuiltinData{"atomicAdd", "OpAtomicIAdd"},
BuiltinData{"atomicMax", "OpAtomicSMax"},
BuiltinData{"atomicMin", "OpAtomicSMin"},
@@ -1995,8 +3444,8 @@ INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
BuiltinData{"atomicOr", "OpAtomicOr"},
BuiltinData{"atomicXor", "OpAtomicXor"}));
-using Builtin_Builtin_AtomicRMW_u32 = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_AtomicRMW_u32, Test) {
+using Builtin_Builder_AtomicRMW_u32 = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_AtomicRMW_u32, Test) {
// struct S {
// v : atomic<u32>;
// }
@@ -2007,22 +3456,24 @@ TEST_P(Builtin_Builtin_AtomicRMW_u32, Test) {
// var v = 10u;
// let x : u32 = atomicOP(&b.v, v);
// }
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("v", ty.atomic<u32>()),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("v", nullptr, Expr(10_u))),
Decl(Let("x", ty.u32(),
Call(GetParam().name, AddressOf(MemberAccessor("b", "v")), "v"))),
},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -2059,7 +3510,7 @@ TEST_P(Builtin_Builtin_AtomicRMW_u32, Test) {
Validate(b);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_AtomicRMW_u32,
+ Builtin_Builder_AtomicRMW_u32,
testing::Values(BuiltinData{"atomicAdd", "OpAtomicIAdd"},
BuiltinData{"atomicMax", "OpAtomicUMax"},
BuiltinData{"atomicMin", "OpAtomicUMin"},
@@ -2081,18 +3532,18 @@ TEST_F(BuiltinBuilderTest, Call_AtomicExchange) {
// let r : u32 = atomicExchange(&b.u, u);
// let s : i32 = atomicExchange(&b.i, i);
// }
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("u", ty.atomic<u32>()),
Member("i", ty.atomic<i32>()),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Var("u", nullptr, Expr(10_u))),
Decl(Var("i", nullptr, Expr(10_i))),
Decl(Let("r", ty.u32(),
@@ -2100,7 +3551,9 @@ TEST_F(BuiltinBuilderTest, Call_AtomicExchange) {
Decl(Let("s", ty.i32(),
Call("atomicExchange", AddressOf(MemberAccessor("b", "i")), "i"))),
},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -2157,18 +3610,18 @@ TEST_F(BuiltinBuilderTest, Call_AtomicCompareExchangeWeak) {
// let u = atomicCompareExchangeWeak(&b.u, 10u, 20u);
// let i = atomicCompareExchangeWeak(&b.i, 10, 10);
// }
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("u", ty.atomic<u32>()),
Member("i", ty.atomic<i32>()),
});
- Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
-
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ GlobalVar("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
+
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(Let("u", nullptr,
Call("atomicCompareExchangeWeak", AddressOf(MemberAccessor("b", "u")), 10_u,
20_u))),
@@ -2176,7 +3629,9 @@ TEST_F(BuiltinBuilderTest, Call_AtomicCompareExchangeWeak) {
Call("atomicCompareExchangeWeak", AddressOf(MemberAccessor("b", "i")), 10_i,
20_i))),
},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -2222,14 +3677,22 @@ OpReturn
Validate(b);
}
-using Builtin_Builtin_DataPacking_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_DataPacking_Test, Binary) {
+} // namespace atomic_builtin_tests
+
+// Tests for Data Packing builtins
+namespace data_packing_builtin_tests {
+
+using Builtin_Builder_DataPacking_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_DataPacking_Test, Binary) {
auto param = GetParam();
bool pack4 = param.name == "pack4x8snorm" || param.name == "pack4x8unorm";
auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 1_f, 1_f, 1_f))
: Call(param.name, vec2<f32>(1_f, 1_f));
- auto* func = Func("a_func", {}, ty.void_(), {CallStmt(call)});
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(call),
+ });
spirv::Builder& b = Build();
@@ -2279,19 +3742,27 @@ OpFunctionEnd
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_DataPacking_Test,
+ Builtin_Builder_DataPacking_Test,
testing::Values(BuiltinData{"pack4x8snorm", "PackSnorm4x8"},
BuiltinData{"pack4x8unorm", "PackUnorm4x8"},
BuiltinData{"pack2x16snorm", "PackSnorm2x16"},
BuiltinData{"pack2x16unorm", "PackUnorm2x16"},
BuiltinData{"pack2x16float", "PackHalf2x16"}));
-using Builtin_Builtin_DataUnpacking_Test = BuiltinBuilderTestWithParam<BuiltinData>;
-TEST_P(Builtin_Builtin_DataUnpacking_Test, Binary) {
+} // namespace data_packing_builtin_tests
+
+// Tests for Data Unpacking builtins
+namespace data_unpacking_builtin_tests {
+
+using Builtin_Builder_DataUnpacking_Test = BuiltinBuilderTestWithParam<BuiltinData>;
+TEST_P(Builtin_Builder_DataUnpacking_Test, Binary) {
auto param = GetParam();
bool pack4 = param.name == "unpack4x8snorm" || param.name == "unpack4x8unorm";
- auto* func = Func("a_func", {}, ty.void_(), {CallStmt(Call(param.name, 1_u))});
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ CallStmt(Call(param.name, 1_u)),
+ });
spirv::Builder& b = Build();
@@ -2339,19 +3810,24 @@ OpFunctionEnd
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
- Builtin_Builtin_DataUnpacking_Test,
+ Builtin_Builder_DataUnpacking_Test,
testing::Values(BuiltinData{"unpack4x8snorm", "UnpackSnorm4x8"},
BuiltinData{"unpack4x8unorm", "UnpackUnorm4x8"},
BuiltinData{"unpack2x16snorm", "UnpackSnorm2x16"},
BuiltinData{"unpack2x16unorm", "UnpackUnorm2x16"},
BuiltinData{"unpack2x16float", "UnpackHalf2x16"}));
+} // namespace data_unpacking_builtin_tests
+
+// Tests for Synchronization builtins
+namespace synchronization_builtin_tests {
+
TEST_F(BuiltinBuilderTest, Call_WorkgroupBarrier) {
- Func("f", {}, ty.void_(),
- ast::StatementList{
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call("workgroupBarrier")),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -2381,11 +3857,11 @@ OpReturn
}
TEST_F(BuiltinBuilderTest, Call_StorageBarrier) {
- Func("f", {}, ty.void_(),
- ast::StatementList{
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
CallStmt(Call("storageBarrier")),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -2414,350 +3890,15 @@ OpReturn
Validate(b);
}
-TEST_F(BuiltinBuilderTest, Call_ExtractBits_i32) {
- auto* v = Var("v", ty.i32());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("extractBits", v, offset, count);
- auto* func = WrapInFunction(v, offset, count, call);
+} // namespace synchronization_builtin_tests
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %9 "offset"
-OpName %13 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 1
-%6 = OpTypePointer Function %7
-%8 = OpConstantNull %7
-%11 = OpTypeInt 32 0
-%10 = OpTypePointer Function %11
-%12 = OpConstantNull %11
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %8
-%9 = OpVariable %10 Function %12
-%13 = OpVariable %10 Function %12
-%15 = OpLoad %7 %5
-%16 = OpLoad %11 %9
-%17 = OpLoad %11 %13
-%14 = OpBitFieldSExtract %7 %15 %16 %17
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
-
-TEST_F(BuiltinBuilderTest, Call_ExtractBits_u32) {
- auto* v = Var("v", ty.u32());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("extractBits", v, offset, count);
- auto* func = WrapInFunction(v, offset, count, call);
-
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %9 "offset"
-OpName %10 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 0
-%6 = OpTypePointer Function %7
-%8 = OpConstantNull %7
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %8
-%9 = OpVariable %6 Function %8
-%10 = OpVariable %6 Function %8
-%12 = OpLoad %7 %5
-%13 = OpLoad %7 %9
-%14 = OpLoad %7 %10
-%11 = OpBitFieldUExtract %7 %12 %13 %14
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
-
-TEST_F(BuiltinBuilderTest, Call_ExtractBits_vec3_i32) {
- auto* v = Var("v", ty.vec3<i32>());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("extractBits", v, offset, count);
- auto* func = WrapInFunction(v, offset, count, call);
-
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %10 "offset"
-OpName %14 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%8 = OpTypeInt 32 1
-%7 = OpTypeVector %8 3
-%6 = OpTypePointer Function %7
-%9 = OpConstantNull %7
-%12 = OpTypeInt 32 0
-%11 = OpTypePointer Function %12
-%13 = OpConstantNull %12
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %9
-%10 = OpVariable %11 Function %13
-%14 = OpVariable %11 Function %13
-%16 = OpLoad %7 %5
-%17 = OpLoad %12 %10
-%18 = OpLoad %12 %14
-%15 = OpBitFieldSExtract %7 %16 %17 %18
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
-
-TEST_F(BuiltinBuilderTest, Call_ExtractBits_vec3_u32) {
- auto* v = Var("v", ty.vec3<u32>());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("extractBits", v, offset, count);
- auto* func = WrapInFunction(v, offset, count, call);
-
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %10 "offset"
-OpName %13 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%8 = OpTypeInt 32 0
-%7 = OpTypeVector %8 3
-%6 = OpTypePointer Function %7
-%9 = OpConstantNull %7
-%11 = OpTypePointer Function %8
-%12 = OpConstantNull %8
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %9
-%10 = OpVariable %11 Function %12
-%13 = OpVariable %11 Function %12
-%15 = OpLoad %7 %5
-%16 = OpLoad %8 %10
-%17 = OpLoad %8 %13
-%14 = OpBitFieldUExtract %7 %15 %16 %17
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
-
-TEST_F(BuiltinBuilderTest, Call_InsertBits_i32) {
- auto* v = Var("v", ty.i32());
- auto* n = Var("n", ty.i32());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("insertBits", v, n, offset, count);
- auto* func = WrapInFunction(v, n, offset, count, call);
-
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %9 "n"
-OpName %10 "offset"
-OpName %14 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 1
-%6 = OpTypePointer Function %7
-%8 = OpConstantNull %7
-%12 = OpTypeInt 32 0
-%11 = OpTypePointer Function %12
-%13 = OpConstantNull %12
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %8
-%9 = OpVariable %6 Function %8
-%10 = OpVariable %11 Function %13
-%14 = OpVariable %11 Function %13
-%16 = OpLoad %7 %5
-%17 = OpLoad %7 %9
-%18 = OpLoad %12 %10
-%19 = OpLoad %12 %14
-%15 = OpBitFieldInsert %7 %16 %17 %18 %19
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
-
-TEST_F(BuiltinBuilderTest, Call_InsertBits_u32) {
- auto* v = Var("v", ty.u32());
- auto* n = Var("n", ty.u32());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("insertBits", v, n, offset, count);
- auto* func = WrapInFunction(v, n, offset, count, call);
-
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %9 "n"
-OpName %10 "offset"
-OpName %11 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeInt 32 0
-%6 = OpTypePointer Function %7
-%8 = OpConstantNull %7
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %8
-%9 = OpVariable %6 Function %8
-%10 = OpVariable %6 Function %8
-%11 = OpVariable %6 Function %8
-%13 = OpLoad %7 %5
-%14 = OpLoad %7 %9
-%15 = OpLoad %7 %10
-%16 = OpLoad %7 %11
-%12 = OpBitFieldInsert %7 %13 %14 %15 %16
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
-
-TEST_F(BuiltinBuilderTest, Call_InsertBits_vec3_i32) {
- auto* v = Var("v", ty.vec3<i32>());
- auto* n = Var("n", ty.vec3<i32>());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("insertBits", v, n, offset, count);
- auto* func = WrapInFunction(v, n, offset, count, call);
-
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %10 "n"
-OpName %11 "offset"
-OpName %15 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%8 = OpTypeInt 32 1
-%7 = OpTypeVector %8 3
-%6 = OpTypePointer Function %7
-%9 = OpConstantNull %7
-%13 = OpTypeInt 32 0
-%12 = OpTypePointer Function %13
-%14 = OpConstantNull %13
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %9
-%10 = OpVariable %6 Function %9
-%11 = OpVariable %12 Function %14
-%15 = OpVariable %12 Function %14
-%17 = OpLoad %7 %5
-%18 = OpLoad %7 %10
-%19 = OpLoad %13 %11
-%20 = OpLoad %13 %15
-%16 = OpBitFieldInsert %7 %17 %18 %19 %20
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
-
-TEST_F(BuiltinBuilderTest, Call_InsertBits_vec3_u32) {
- auto* v = Var("v", ty.vec3<u32>());
- auto* n = Var("n", ty.vec3<u32>());
- auto* offset = Var("offset", ty.u32());
- auto* count = Var("count", ty.u32());
- auto* call = Call("insertBits", v, n, offset, count);
- auto* func = WrapInFunction(v, n, offset, count, call);
-
- spirv::Builder& b = Build();
-
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-
- auto got = DumpBuilder(b);
- auto expect = R"(OpEntryPoint GLCompute %3 "test_function"
-OpExecutionMode %3 LocalSize 1 1 1
-OpName %3 "test_function"
-OpName %5 "v"
-OpName %10 "n"
-OpName %11 "offset"
-OpName %14 "count"
-%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%8 = OpTypeInt 32 0
-%7 = OpTypeVector %8 3
-%6 = OpTypePointer Function %7
-%9 = OpConstantNull %7
-%12 = OpTypePointer Function %8
-%13 = OpConstantNull %8
-%3 = OpFunction %2 None %1
-%4 = OpLabel
-%5 = OpVariable %6 Function %9
-%10 = OpVariable %6 Function %9
-%11 = OpVariable %12 Function %13
-%14 = OpVariable %12 Function %13
-%16 = OpLoad %7 %5
-%17 = OpLoad %7 %10
-%18 = OpLoad %8 %11
-%19 = OpLoad %8 %14
-%15 = OpBitFieldInsert %7 %16 %17 %18 %19
-OpReturn
-OpFunctionEnd
-)";
- EXPECT_EQ(got, expect);
-}
+// Tests for DP4A builtins, tint:1497
+namespace DP4A_builtin_tests {
TEST_F(BuiltinBuilderTest, Call_Dot4I8Packed) {
auto* ext =
create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
- ast::Extension::kChromiumExperimentalDP4a);
+ ast::Extension::kChromiumExperimentalDp4A);
AST().AddEnable(ext);
auto* val1 = Var("val1", ty.u32());
@@ -2797,7 +3938,7 @@ OpFunctionEnd
TEST_F(BuiltinBuilderTest, Call_Dot4U8Packed) {
auto* ext =
create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
- ast::Extension::kChromiumExperimentalDP4a);
+ ast::Extension::kChromiumExperimentalDp4A);
AST().AddEnable(ext);
auto* val1 = Var("val1", ty.u32());
@@ -2833,5 +3974,7 @@ OpFunctionEnd
EXPECT_EQ(got, expect);
}
+} // namespace DP4A_builtin_tests
+
} // namespace
} // namespace tint::writer::spirv
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_texture_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_texture_test.cc
index b4abfcf141a..b5fcc9c631c 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_texture_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_builtin_texture_test.cc
@@ -2683,7 +2683,7 @@ OpCapability SampledCubeArray
%26 = OpConstantComposite %14 %23 %24 %25
%28 = OpTypeInt 32 1
%27 = OpTypeVector %28 3
-%29 = OpConstant %28 0
+%29 = OpConstantNull %28
%30 = OpConstant %28 1
%31 = OpConstant %28 2
%32 = OpConstantComposite %27 %29 %30 %31
@@ -3684,7 +3684,10 @@ TEST_P(BuiltinTextureTest, Call) {
auto* call = Call(param.function, param.args(this));
auto* stmt = CallStmt(call);
- Func("func", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{stmt},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = Build();
@@ -3710,7 +3713,10 @@ TEST_P(BuiltinTextureTest, ValidateSPIRV) {
auto* call = Call(param.function, param.args(this));
auto* stmt = CallStmt(call);
- Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+ Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = Build();
@@ -3730,8 +3736,10 @@ TEST_P(BuiltinTextureTest, OutsideFunction_IsError) {
auto* call = Call(param.function, param.args(this));
auto* stmt = CallStmt(call);
- Func("func", {}, ty.void_(), {stmt},
- {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+ Func("func", utils::Empty, ty.void_(), utils::Vector{stmt},
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_call_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_call_test.cc
index b81ca963f64..a0631ea3c5a 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_call_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_call_test.cc
@@ -25,12 +25,14 @@ namespace {
using BuilderTest = TestHelper;
TEST_F(BuilderTest, Expression_Call) {
- ast::VariableList func_params;
- func_params.push_back(Param("a", ty.f32()));
- func_params.push_back(Param("b", ty.f32()));
-
- auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))});
- auto* func = Func("main", {}, ty.void_(), {Assign(Phony(), Call("a_func", 1_f, 1_f))});
+ auto* a_func = Func("a_func",
+ utils::Vector{
+ Param("a", ty.f32()),
+ Param("b", ty.f32()),
+ },
+ ty.f32(), utils::Vector{Return(Add("a", "b"))});
+ auto* func = Func("main", utils::Empty, ty.void_(),
+ utils::Vector{Assign(Phony(), Call("a_func", 1_f, 1_f))});
spirv::Builder& b = Build();
@@ -62,13 +64,15 @@ OpFunctionEnd
}
TEST_F(BuilderTest, Statement_Call) {
- ast::VariableList func_params;
- func_params.push_back(Param("a", ty.f32()));
- func_params.push_back(Param("b", ty.f32()));
-
- auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))});
-
- auto* func = Func("main", {}, ty.void_(), {CallStmt(Call("a_func", 1_f, 1_f))});
+ auto* a_func = Func("a_func",
+ utils::Vector{
+ Param("a", ty.f32()),
+ Param("b", ty.f32()),
+ },
+ ty.f32(), utils::Vector{Return(Add("a", "b"))});
+
+ auto* func =
+ Func("main", utils::Empty, ty.void_(), utils::Vector{CallStmt(Call("a_func", 1_f, 1_f))});
spirv::Builder& b = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_constructor_expression_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_constructor_expression_test.cc
index d1fba8fb303..3ae4f659df3 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_constructor_expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -24,7 +24,7 @@ using SpvBuilderConstructorTest = TestHelper;
TEST_F(SpvBuilderConstructorTest, Const) {
auto* c = Expr(42.2_f);
- auto* g = Global("g", ty.f32(), c, ast::StorageClass::kPrivate);
+ auto* g = GlobalVar("g", ty.f32(), c, ast::StorageClass::kPrivate);
spirv::Builder& b = Build();
@@ -212,6 +212,23 @@ TEST_F(SpvBuilderConstructorTest, Type_F32_With_F32) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_F16_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = Construct<f16>(2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 2u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Literal) {
auto* cast = vec2<bool>(true);
WrapInFunction(cast);
@@ -270,6 +287,25 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_Literal) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_Literal) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
auto* cast = vec2<f32>("x", "x");
@@ -295,6 +331,33 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec2<f16>("x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 9u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpCompositeConstruct %6 %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32_Const) {
auto* cast = vec2<f32>(1_f, 2_f);
WrapInFunction(cast);
@@ -313,7 +376,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(1_h, 2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 5u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec2<f32>("x");
WrapInFunction(var, cast);
@@ -338,7 +421,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec2<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 10u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2_Const) {
auto* cast = vec2<f32>(vec2<f32>(1_f, 2_f));
WrapInFunction(cast);
@@ -356,6 +466,26 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(vec2<f16>(1_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 5u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
auto* cast = vec3<f32>("x", "x", "x");
@@ -382,6 +512,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec3<f16>("x", "x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 10u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpLoad %1 %3
+%10 = OpCompositeConstruct %6 %7 %8 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Const) {
auto* cast = vec3<f32>(1_f, 2_f, 3_f);
WrapInFunction(cast);
@@ -401,6 +559,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(1_h, 2_h, 3_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool) {
auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
auto* cast = vec3<bool>("x", "x", "x");
@@ -439,7 +618,7 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool_Const) {
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
%1 = OpTypeVector %2 3
%3 = OpConstantTrue %2
-%4 = OpConstantFalse %2
+%4 = OpConstantNull %2
%5 = OpConstantComposite %1 %3 %4 %3
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
@@ -471,6 +650,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec3<f16>("x", "x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 10u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpLoad %1 %3
+%10 = OpCompositeConstruct %6 %7 %8 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32_Const) {
auto* cast = vec3<f32>(1_f, 2_f, 3_f);
WrapInFunction(cast);
@@ -490,6 +697,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(1_h, 2_h, 3_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
auto* cast = vec3<f32>(1_f, "x");
@@ -520,6 +748,38 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
+ auto* cast = vec3<f16>(1_h, "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 14u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstant %2 0x1.8p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 3
+%10 = OpConstant %2 0x1p+0
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%11 = OpLoad %1 %6
+%12 = OpCompositeExtract %2 %11 0
+%13 = OpCompositeExtract %2 %11 1
+%14 = OpCompositeConstruct %9 %10 %12 %13
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2_Const) {
auto* cast = vec3<f32>(1_f, vec2<f32>(2_f, 3_f));
WrapInFunction(cast);
@@ -539,6 +799,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec3<f32>("x", 3_f);
@@ -569,6 +850,38 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec3<f16>("x", 3_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 14u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 3
+%13 = OpConstant %2 0x1.8p+1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%14 = OpCompositeConstruct %9 %11 %12 %13
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32_Const) {
auto* cast = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
WrapInFunction(cast);
@@ -588,7 +901,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec2<f16>(1_h, 2_h), 3_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3) {
auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(1_f, 2_f, 3_f)));
auto* cast = vec3<f32>("x");
WrapInFunction(var, cast);
@@ -614,7 +948,35 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(1_h, 2_h, 3_h)));
+ auto* cast = vec3<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Function %1
+%9 = OpConstantNull %1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %7 %6
+%11 = OpLoad %1 %7
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3_Const) {
auto* cast = vec3<f32>(vec3<f32>(1_f, 2_f, 3_f));
WrapInFunction(cast);
@@ -633,6 +995,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec3<f16>(1_h, 2_h, 3_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool) {
auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
auto* cast = vec4<bool>("x");
@@ -698,6 +1081,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec4<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 8u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpCompositeConstruct %6 %7 %7 %7 %7
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Const) {
auto* cast = vec4<f32>(2_f);
WrapInFunction(cast);
@@ -715,6 +1124,25 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
auto* cast = vec4<f32>("x", "x", "x", "x");
@@ -742,6 +1170,35 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec4<f16>("x", "x", "x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpLoad %1 %3
+%10 = OpLoad %1 %3
+%11 = OpCompositeConstruct %6 %7 %8 %9 %10
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32_Const) {
auto* cast = vec4<f32>(1_f, 2_f, 3_f, 4_f);
WrapInFunction(cast);
@@ -762,6 +1219,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(1_h, 2_h, 3_h, 4_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec4<f32>(1_f, 2_f, "x");
@@ -791,6 +1270,37 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec4<f16>(1_h, 2_h, "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%13 = OpCompositeConstruct %9 %3 %4 %11 %12
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2_Const) {
auto* cast = vec4<f32>(1_f, 2_f, vec2<f32>(3_f, 4_f));
WrapInFunction(cast);
@@ -811,6 +1321,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(1_h, 2_h, vec2<f16>(3_h, 4_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
auto* cast = vec4<f32>(1_f, "x", 4_f);
@@ -842,6 +1374,39 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
+ auto* cast = vec4<f16>(1_h, "x", 4_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 15u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstant %2 0x1.8p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+%10 = OpConstant %2 0x1p+0
+%14 = OpConstant %2 0x1p+2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%11 = OpLoad %1 %6
+%12 = OpCompositeExtract %2 %11 0
+%13 = OpCompositeExtract %2 %11 1
+%15 = OpCompositeConstruct %9 %10 %12 %13 %14
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32_Const) {
auto* cast = vec4<f32>(1_f, vec2<f32>(2_f, 3_f), 4_f);
WrapInFunction(cast);
@@ -862,6 +1427,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(1_h, vec2<f16>(2_h, 3_h), 4_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec4<f32>("x", 3_f, 4_f);
@@ -893,6 +1480,39 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec4<f16>("x", 3_h, 4_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 15u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+%13 = OpConstant %2 0x1.8p+1
+%14 = OpConstant %2 0x1p+2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%15 = OpCompositeConstruct %9 %11 %12 %13 %14
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32_Const) {
auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), 3_f, 4_f);
WrapInFunction(cast);
@@ -913,7 +1533,29 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), 3_h, 4_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec4<f32>("x", "x");
WrapInFunction(var, cast);
@@ -945,7 +1587,41 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec4<f16>("x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 16u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%13 = OpLoad %1 %6
+%14 = OpCompositeExtract %2 %13 0
+%15 = OpCompositeExtract %2 %13 1
+%16 = OpCompositeConstruct %9 %11 %12 %14 %15
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2_Const) {
auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), vec2<f32>(1_f, 2_f));
WrapInFunction(cast);
@@ -963,6 +1639,26 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), vec2<f16>(1_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 5u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4 %3 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3) {
auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
auto* cast = vec4<f32>(2_f, "x");
@@ -992,6 +1688,37 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
+ auto* cast = vec4<f16>(2_h, "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Function %1
+%7 = OpConstantNull %1
+%8 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %5 %4
+%9 = OpLoad %1 %5
+%10 = OpCompositeExtract %2 %9 0
+%11 = OpCompositeExtract %2 %9 1
+%12 = OpCompositeExtract %2 %9 2
+%13 = OpCompositeConstruct %8 %3 %10 %11 %12
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3_Const) {
auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1009,6 +1736,25 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32) {
auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
auto* cast = vec4<f32>("x", 2_f);
@@ -1038,6 +1784,37 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
+ auto* cast = vec4<f16>("x", 2_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Function %1
+%7 = OpConstantNull %1
+%8 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %5 %4
+%9 = OpLoad %1 %5
+%10 = OpCompositeExtract %2 %9 0
+%11 = OpCompositeExtract %2 %9 1
+%12 = OpCompositeExtract %2 %9 2
+%13 = OpCompositeConstruct %8 %10 %11 %12 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32_Const) {
auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
WrapInFunction(cast);
@@ -1055,7 +1832,26 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32_Const) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec4) {
auto* value = vec4<f32>(2_f, 2_f, 2_f, 2_f);
auto* cast = vec4<f32>(value);
WrapInFunction(cast);
@@ -1073,39 +1869,237 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec4) {
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_F32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* value = vec4<f16>(2_h, 2_h, 2_h, 2_h);
+ auto* cast = vec4<f16>(value);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F32_With_F32) {
auto* ctor = Construct<f32>(2_f);
GlobalConst("g", ty.f32(), ctor);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 2
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F16_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<f16>(2_h);
+ GlobalConst("g", ty.f16(), ctor);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 16
+%6 = OpConstant %5 0x1p+1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F32_With_F32) {
+ auto* ctor = Construct<f32>(2_f);
+ GlobalVar("g", ty.f32(), ast::StorageClass::kPrivate, ctor);
spirv::Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build());
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
%2 = OpConstant %1 2
-%4 = OpTypeVoid
-%3 = OpTypeFunction %4
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F16_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<f16>(2_h);
+ GlobalVar("g", ty.f16(), ast::StorageClass::kPrivate, ctor);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
)");
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_U32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F32) {
auto* ctor = Construct<u32>(1.5_f);
GlobalConst("g", ty.u32(), ctor);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<u32>(1.5_h);
+ GlobalConst("g", ty.u32(), ctor);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F32) {
+ auto* ctor = Construct<u32>(1.5_f);
+ GlobalVar("g", ty.u32(), ast::StorageClass::kPrivate, ctor);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+%2 = OpConstant %1 1
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<u32>(1.5_h);
+ GlobalVar("g", ty.u32(), ast::StorageClass::kPrivate, ctor);
spirv::Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build());
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
%2 = OpConstant %1 1
-%4 = OpTypeVoid
-%3 = OpTypeFunction %4
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
)");
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F32) {
auto* cast = vec2<f32>(2_f);
- auto* g = Global("g", ty.vec2<f32>(), cast, ast::StorageClass::kPrivate);
+ GlobalConst("g", ty.vec2<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(2_h);
+ GlobalConst("g", ty.vec2<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F32) {
+ auto* cast = vec2<f32>(2_f);
+ auto* g = GlobalVar("g", ty.vec2<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
@@ -1119,9 +2113,75 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_F32) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(2_h);
+ auto* g = GlobalVar("g", ty.vec2<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F32_With_Vec2) {
auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
- GlobalConst("a", ty.vec2<f32>(), cast);
+ GlobalConst("g", ty.vec2<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F16_With_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec2<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F32_With_Vec2) {
+ auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
+ GlobalVar("a", ty.vec2<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build());
@@ -1130,16 +2190,88 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_Vec2) {
%1 = OpTypeVector %2 2
%3 = OpConstant %2 2
%4 = OpConstantComposite %1 %3 %3
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F16_With_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
+ GlobalVar("a", ty.vec2<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F32_With_Vec3) {
+ auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
+ GlobalConst("g", ty.vec3<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F16_With_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F32_With_Vec3) {
auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
- GlobalConst("a", ty.vec3<f32>(), cast);
+ GlobalVar("a", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build());
@@ -1148,16 +2280,88 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec3) {
%1 = OpTypeVector %2 3
%3 = OpConstant %2 2
%4 = OpConstantComposite %1 %3 %3 %3
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F16_With_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
+ GlobalVar("a", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
)");
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec4) {
auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
- GlobalConst("a", ty.vec4<f32>(), cast);
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec4) {
+ auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
+ GlobalVar("a", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build());
@@ -1166,16 +2370,88 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec4) {
%1 = OpTypeVector %2 4
%3 = OpConstant %2 2
%4 = OpConstantComposite %1 %3 %3 %3 %3
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ GlobalVar("a", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32) {
+ auto* cast = vec3<f32>(2_f);
+ GlobalConst("g", ty.vec3<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
)");
+ Validate(b);
+}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h);
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32) {
auto* cast = vec3<f32>(2_f);
- auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+ auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
@@ -1189,55 +2465,239 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h);
+ auto* g = GlobalVar("g", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32_Vec2) {
+ auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
+ GlobalConst("g", ty.vec3<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32_Vec2) {
auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
- auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+ auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 3
%3 = OpConstant %2 2
-%4 = OpTypeVector %2 2
-%5 = OpConstantComposite %4 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %3 %6 %9
+%4 = OpConstantComposite %1 %3 %3 %3
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F32) {
auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
- auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+ GlobalConst("g", ty.vec3<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F32) {
+ auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
+ auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 3
-%3 = OpTypeVector %2 2
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %6 %9 %4
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
+ auto* g = GlobalVar("g", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32) {
auto* cast = vec4<f32>(2_f);
- auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32) {
+ auto* cast = vec4<f32>(2_f);
+ auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
@@ -1251,151 +2711,492 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_F32_Vec2) {
+ auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_F32_Vec2) {
auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
- auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+ auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 4
%3 = OpConstant %2 2
-%4 = OpTypeVector %2 2
-%5 = OpConstantComposite %4 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %3 %3 %6 %9
+%4 = OpConstantComposite %1 %3 %3 %3 %3
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec2_F32) {
+ auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec2_F32) {
auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
- auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+ auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 4
%3 = OpConstant %2 2
-%4 = OpTypeVector %2 2
-%5 = OpConstantComposite %4 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %3 %6 %9 %3
+%4 = OpConstantComposite %1 %3 %3 %3 %3
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec2_F32_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F32_F32) {
auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
- auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F32_F32) {
+ auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
+ auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 4
-%3 = OpTypeVector %2 2
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %6 %9 %4 %4
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec2_Vec2) {
auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
- auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec2_Vec2) {
+ auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
+ auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 4
-%3 = OpTypeVector %2 2
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantOp %2 CompositeExtract %5 8
-%12 = OpSpecConstantOp %2 CompositeExtract %5 10
-%13 = OpSpecConstantComposite %1 %6 %9 %11 %12
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec3) {
+ auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
)");
+ Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec3) {
auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
- auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+ auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 4
%3 = OpConstant %2 2
-%4 = OpTypeVector %2 3
-%5 = OpConstantComposite %4 %3 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%12 = OpConstant %7 2
-%11 = OpSpecConstantOp %2 CompositeExtract %5 12
-%13 = OpSpecConstantComposite %1 %3 %6 %9 %11
+%4 = OpConstantComposite %1 %3 %3 %3 %3
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec3_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F32) {
auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
- auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+ GlobalConst("g", ty.vec4<f32>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F32) {
+ auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
+ auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
spirv::Builder& b = Build();
b.push_function(Function{});
- EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 4
-%3 = OpTypeVector %2 3
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%12 = OpConstant %7 2
-%11 = OpSpecConstantOp %2 CompositeExtract %5 12
-%13 = OpSpecConstantComposite %1 %6 %9 %11 %4
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F32_With_Vec2_Vec2) {
auto* cast = mat2x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
WrapInFunction(cast);
@@ -1413,7 +3214,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_With_Vec2_Vec2) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_With_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat2x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 2
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4
+%6 = OpConstantComposite %1 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F32_With_Vec2_Vec2_Vec2) {
auto* cast = mat3x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
WrapInFunction(cast);
@@ -1431,7 +3252,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_With_Vec2_Vec2_Vec2) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_With_Vec2_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F16_With_Vec2_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat3x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 3
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F32_With_Vec2_Vec2_Vec2_Vec2) {
auto* cast = mat4x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f),
vec2<f32>(2_f, 2_f));
WrapInFunction(cast);
@@ -1450,7 +3291,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_With_Vec2_Vec2_Vec2_Vec2) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_With_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F16_With_Vec2_Vec2_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat4x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h),
+ vec2<f16>(2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 4
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F32_With_Vec3_Vec3) {
auto* cast = mat2x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1468,7 +3330,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_With_Vec3_Vec3) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_With_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F16_With_Vec3_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat2x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 2
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F32_With_Vec3_Vec3_Vec3) {
auto* cast =
mat3x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1487,7 +3369,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_With_Vec3_Vec3_Vec3) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_With_Vec3_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F16_With_Vec3_Vec3_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast =
+ mat3x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 3
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F32_With_Vec3_Vec3_Vec3_Vec3) {
auto* cast = mat4x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f),
vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1506,7 +3409,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_With_Vec3_Vec3_Vec3_Vec3) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_With_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F16_With_Vec3_Vec3_Vec3_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat4x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h),
+ vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 4
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F32_With_Vec4_Vec4) {
auto* cast = mat2x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1524,7 +3448,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_With_Vec4_Vec4) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_With_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F16_With_Vec4_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat2x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 2
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F32_With_Vec4_Vec4_Vec4) {
auto* cast = mat3x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
vec4<f32>(2_f, 2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1543,7 +3487,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_With_Vec4_Vec4_Vec4) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_With_Vec4_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F16_With_Vec4_Vec4_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat3x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
+ vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 3
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F32_With_Vec4_Vec4_Vec4_Vec4) {
auto* cast = mat4x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1562,6 +3527,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_With_Vec4_Vec4_Vec4_Vec4) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F16_With_Vec4_Vec4_Vec4_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat4x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
+ vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 4
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5 %5
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Array_5_F32) {
auto* cast = array<f32, 5>(2_f, 2_f, 2_f, 2_f, 2_f);
WrapInFunction(cast);
@@ -1580,7 +3566,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Array_5_F32) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Array_5_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = array<f16, 5>(2_h, 2_h, 2_h, 2_h, 2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%3 = OpTypeInt 32 0
+%4 = OpConstant %3 5
+%1 = OpTypeArray %2 %4
+%5 = OpConstant %2 0x1p+1
+%6 = OpConstantComposite %1 %5 %5 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F32) {
auto* first = vec3<f32>(1_f, 2_f, 3_f);
auto* second = vec3<f32>(1_f, 2_f, 3_f);
auto* t = Construct(ty.array(ty.vec3<f32>(), 2_u), first, second);
@@ -1602,14 +3608,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* first = vec3<f16>(1_h, 2_h, 3_h);
+ auto* second = vec3<f16>(1_h, 2_h, 3_h);
+ auto* t = Construct(ty.array(ty.vec3<f16>(), 2_u), first, second);
+ WrapInFunction(t);
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(t), 10u);
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%4 = OpTypeInt 32 0
+%5 = OpConstant %4 2
+%1 = OpTypeArray %2 %5
+%6 = OpConstant %3 0x1p+0
+%7 = OpConstant %3 0x1p+1
+%8 = OpConstant %3 0x1.8p+1
+%9 = OpConstantComposite %2 %6 %7 %8
+%10 = OpConstantComposite %1 %9 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoVectors) {
auto* v1 = vec3<f32>(2_f, 2_f, 2_f);
auto* v2 = vec3<f32>(2_f, 2_f, 2_f);
- ast::StatementList stmts = {
- WrapInStatement(v1),
- WrapInStatement(v2),
- };
- WrapInFunction(stmts);
+ WrapInFunction(WrapInStatement(v1), WrapInStatement(v2));
spirv::Builder& b = Build();
@@ -1627,11 +3653,7 @@ TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoVectors) {
TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoArrays) {
auto* a1 = array<f32, 3>(2_f, 2_f, 2_f);
auto* a2 = array<f32, 3>(2_f, 2_f, 2_f);
- ast::StatementList stmts = {
- WrapInStatement(a1),
- WrapInStatement(a2),
- };
- WrapInFunction(stmts);
+ WrapInFunction(WrapInStatement(a1), WrapInStatement(a2));
spirv::Builder& b = Build();
@@ -1654,11 +3676,7 @@ TEST_F(SpvBuilderConstructorTest, CommonInitializer_Array_VecArray) {
// crbug.com/tint/777
auto* a1 = array<f32, 2>(1_f, 2_f);
auto* a2 = vec2<f32>(1_f, 2_f);
- ast::StatementList stmts = {
- WrapInStatement(a1),
- WrapInStatement(a2),
- };
- WrapInFunction(stmts);
+ WrapInFunction(WrapInStatement(a1), WrapInStatement(a2));
spirv::Builder& b = Build();
b.push_function(Function{});
@@ -1678,7 +3696,7 @@ TEST_F(SpvBuilderConstructorTest, CommonInitializer_Array_VecArray) {
}
TEST_F(SpvBuilderConstructorTest, Type_Struct) {
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.vec3<f32>()),
});
@@ -1719,6 +3737,25 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* t = Construct<f16>();
+
+ WrapInFunction(t);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(t), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstantNull %1
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_I32) {
auto* t = Construct<i32>();
@@ -1788,7 +3825,7 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Vector) {
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F32) {
auto* t = mat4x2<f32>();
WrapInFunction(t);
@@ -1807,6 +3844,27 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* t = mat4x2<f16>();
+
+ WrapInFunction(t);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(t), 4u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 4
+%4 = OpConstantNull %1
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
auto* t = array<i32, 2>();
@@ -1828,7 +3886,7 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
}
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Struct) {
- auto* s = Structure("my_struct", {Member("a", ty.f32())});
+ auto* s = Structure("my_struct", utils::Vector{Member("a", ty.f32())});
auto* t = Construct(ty.Of(s));
WrapInFunction(t);
@@ -1917,6 +3975,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_I32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F16_To_I32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
+ auto* cast = Construct<i32>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.33p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeInt 32 1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertFToS %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_U32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2.4_f)));
auto* cast = Construct<u32>("x");
@@ -1941,6 +4025,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_U32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F16_To_U32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
+ auto* cast = Construct<u32>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.33p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeInt 32 0
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertFToU %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F32) {
auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
auto* cast = Construct<f32>("x");
@@ -1965,6 +4075,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
+ auto* cast = Construct<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+%2 = OpConstant %1 2
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeFloat 16
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertSToF %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F32) {
auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
auto* cast = Construct<f32>("x");
@@ -1989,8 +4125,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
+ auto* cast = Construct<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+%2 = OpConstant %1 2
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeFloat 16
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertUToF %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_I32) {
- auto* var = Global("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
auto* cast = vec3<i32>("i");
WrapInFunction(cast);
@@ -2016,7 +4178,7 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_I32) {
}
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_I32) {
- auto* var = Global("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* cast = vec3<i32>("i");
WrapInFunction(cast);
@@ -2041,8 +4203,36 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_I32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_I32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<i32>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 16
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 1
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertFToS %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_U32) {
- auto* var = Global("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
auto* cast = vec3<u32>("i");
WrapInFunction(cast);
@@ -2068,7 +4258,7 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_U32) {
}
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_U32) {
- auto* var = Global("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* cast = vec3<u32>("i");
WrapInFunction(cast);
@@ -2093,8 +4283,36 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_U32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_U32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<u32>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 16
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertFToU %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F32) {
- auto* var = Global("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
auto* cast = vec3<f32>("i");
WrapInFunction(cast);
@@ -2119,8 +4337,36 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<f16>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeFloat 16
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertSToF %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F32) {
- auto* var = Global("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
auto* cast = vec3<f32>("i");
WrapInFunction(cast);
@@ -2145,6 +4391,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F32) {
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<f16>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeFloat 16
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertUToF %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithAllConstConstructors) {
// vec3<f32>(1.0, 2.0, 3.0) -> true
auto* t = vec3<f32>(1_f, 2_f, 3_f);
@@ -2208,9 +4482,9 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_VectorWithAllConstConstruct
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Vector_WithIdent) {
// vec3<f32>(a, b, c) -> false
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
- Global("b", ty.f32(), ast::StorageClass::kPrivate);
- Global("c", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("c", ty.f32(), ast::StorageClass::kPrivate);
auto* t = vec3<f32>("a", "b", "c");
WrapInFunction(t);
@@ -2260,7 +4534,7 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) {
}
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.vec3<f32>()),
});
@@ -2275,13 +4549,13 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
}
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct_WithIdentSubExpression) {
- auto* s = Structure("my_struct", {
+ auto* s = Structure("my_struct", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.vec3<f32>()),
});
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
- Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* t = Construct(ty.Of(s), "a", "b");
WrapInFunction(t);
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_entry_point_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_entry_point_test.cc
index a407aa7fb9b..ea36e358e40 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_entry_point_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_entry_point_test.cc
@@ -15,8 +15,8 @@
#include <memory>
#include "gtest/gtest.h"
-#include "src/tint/ast/builtin.h"
#include "src/tint/ast/builtin_attribute.h"
+#include "src/tint/ast/builtin_value.h"
#include "src/tint/ast/location_attribute.h"
#include "src/tint/ast/return_statement.h"
#include "src/tint/ast/stage_attribute.h"
@@ -42,13 +42,18 @@ TEST_F(BuilderTest, EntryPoint_Parameters) {
// @location(1) loc1 : f32) {
// var col : f32 = (coord.x * loc1);
// }
- auto* coord = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
- auto* loc1 = Param("loc1", ty.f32(), {Location(1u)});
+ auto* coord = Param("coord", ty.vec4<f32>(),
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
+ auto* loc1 = Param("loc1", ty.f32(),
+ utils::Vector{
+ Location(1u),
+ });
auto* mul = Mul(Expr(MemberAccessor("coord", "x")), Expr("loc1"));
auto* col = Var("col", ty.f32(), ast::StorageClass::kNone, mul);
- Func("frag_main", ast::VariableList{coord, loc1}, ty.void_(),
- ast::StatementList{WrapInStatement(col)},
- ast::AttributeList{
+ Func("frag_main", utils::Vector{coord, loc1}, ty.void_(), utils::Vector{WrapInStatement(col)},
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -113,18 +118,24 @@ TEST_F(BuilderTest, EntryPoint_ReturnValue) {
// }
// return 1.0;
// }
- auto* loc_in = Param("loc_in", ty.u32(), {Location(0), Flat()});
+ auto* loc_in = Param("loc_in", ty.u32(),
+ utils::Vector{
+ Location(0),
+ Flat(),
+ });
auto* cond =
create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThan, Expr("loc_in"), Expr(10_u));
- Func("frag_main", ast::VariableList{loc_in}, ty.f32(),
- ast::StatementList{
+ Func("frag_main", utils::Vector{loc_in}, ty.f32(),
+ utils::Vector{
If(cond, Block(Return(0.5_f))),
Return(1_f),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
},
- ast::AttributeList{Location(0)});
+ utils::Vector{
+ Location(0),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -199,19 +210,26 @@ TEST_F(BuilderTest, EntryPoint_SharedStruct) {
auto* interface = Structure(
"Interface",
- {
- Member("value", ty.f32(), ast::AttributeList{Location(1u)}),
- Member("pos", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)}),
+ utils::Vector{
+ Member("value", ty.f32(), utils::Vector{Location(1u)}),
+ Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
});
auto* vert_retval = Construct(ty.Of(interface), 42_f, Construct(ty.vec4<f32>()));
- Func("vert_main", ast::VariableList{}, ty.Of(interface), {Return(vert_retval)},
- {Stage(ast::PipelineStage::kVertex)});
+ Func("vert_main", utils::Empty, ty.Of(interface), utils::Vector{Return(vert_retval)},
+ utils::Vector{
+ Stage(ast::PipelineStage::kVertex),
+ });
auto* frag_inputs = Param("inputs", ty.Of(interface));
- Func("frag_main", ast::VariableList{frag_inputs}, ty.f32(),
- {Return(MemberAccessor(Expr("inputs"), "value"))}, {Stage(ast::PipelineStage::kFragment)},
- {Builtin(ast::Builtin::kFragDepth)});
+ Func("frag_main", utils::Vector{frag_inputs}, ty.f32(),
+ utils::Vector{
+ Return(MemberAccessor(Expr("inputs"), "value")),
+ },
+ utils::Vector{Stage(ast::PipelineStage::kFragment)},
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFragDepth),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -302,8 +320,13 @@ OpFunctionEnd
}
TEST_F(BuilderTest, SampleIndex_SampleRateShadingCapability) {
- Func("main", {Param("sample_index", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})},
- ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+ Func("main",
+ utils::Vector{Param("sample_index", ty.u32(),
+ utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)})},
+ ty.void_(), utils::Empty,
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -311,9 +334,12 @@ TEST_F(BuilderTest, SampleIndex_SampleRateShadingCapability) {
// Make sure we generate the SampleRateShading capability.
EXPECT_EQ(DumpInstructions(b.capabilities()),
- "OpCapability Shader\n"
- "OpCapability SampleRateShading\n");
- EXPECT_EQ(DumpInstructions(b.annots()), "OpDecorate %1 BuiltIn SampleId\n");
+ R"(OpCapability Shader
+OpCapability SampleRateShading
+)");
+ EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 BuiltIn SampleId
+OpDecorate %1 Flat
+)");
}
} // namespace
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_attribute_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_attribute_test.cc
index e5bb43da5fc..449b75d735f 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_attribute_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_attribute_test.cc
@@ -25,8 +25,8 @@ namespace {
using BuilderTest = TestHelper;
TEST_F(BuilderTest, Attribute_Stage) {
- auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -52,22 +52,22 @@ TEST_P(Attribute_StageTest, Emit) {
const ast::Variable* var = nullptr;
const ast::Type* ret_type = nullptr;
- ast::AttributeList ret_type_attrs;
- ast::StatementList body;
+ utils::Vector<const ast::Attribute*, 2> ret_type_attrs;
+ utils::Vector<const ast::Statement*, 2> body;
if (params.stage == ast::PipelineStage::kVertex) {
ret_type = ty.vec4<f32>();
- ret_type_attrs.push_back(Builtin(ast::Builtin::kPosition));
- body.push_back(Return(Construct(ty.vec4<f32>())));
+ ret_type_attrs.Push(Builtin(ast::BuiltinValue::kPosition));
+ body.Push(Return(Construct(ty.vec4<f32>())));
} else {
ret_type = ty.void_();
}
- auto deco_list = ast::AttributeList{Stage(params.stage)};
+ utils::Vector<const ast::Attribute*, 2> deco_list{Stage(params.stage)};
if (params.stage == ast::PipelineStage::kCompute) {
- deco_list.push_back(WorkgroupSize(1_i));
+ deco_list.Push(WorkgroupSize(1_i));
}
- auto* func = Func("main", {}, ret_type, body, deco_list, ret_type_attrs);
+ auto* func = Func("main", utils::Empty, ret_type, body, deco_list, ret_type_attrs);
spirv::Builder& b = Build();
@@ -91,8 +91,8 @@ INSTANTIATE_TEST_SUITE_P(
FunctionStageData{ast::PipelineStage::kCompute, SpvExecutionModelGLCompute}));
TEST_F(BuilderTest, Decoration_ExecutionMode_Fragment_OriginUpperLeft) {
- auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -105,8 +105,8 @@ TEST_F(BuilderTest, Decoration_ExecutionMode_Fragment_OriginUpperLeft) {
}
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Default) {
- auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
spirv::Builder& b = Build();
@@ -117,8 +117,8 @@ TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Default) {
}
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Literals) {
- auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
WorkgroupSize(2_i, 4_i, 6_i),
Stage(ast::PipelineStage::kCompute),
});
@@ -135,8 +135,8 @@ TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Const) {
GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
- auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
WorkgroupSize("width", "height", "depth"),
Stage(ast::PipelineStage::kCompute),
});
@@ -150,11 +150,11 @@ TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Const) {
}
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_OverridableConst) {
- Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
- Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
- Override("depth", ty.i32(), Construct(ty.i32(), 4_i), {Id(9u)});
- auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ Override("width", ty.i32(), Construct(ty.i32(), 2_i), utils::Vector{Id(7u)});
+ Override("height", ty.i32(), Construct(ty.i32(), 3_i), utils::Vector{Id(8u)});
+ Override("depth", ty.i32(), Construct(ty.i32(), 4_i), utils::Vector{Id(9u)});
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
WorkgroupSize("width", "height", "depth"),
Stage(ast::PipelineStage::kCompute),
});
@@ -180,10 +180,10 @@ OpDecorate %3 BuiltIn WorkgroupSize
}
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst) {
- Override("height", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
+ Override("height", ty.i32(), Construct(ty.i32(), 2_i), utils::Vector{Id(7u)});
GlobalConst("depth", ty.i32(), Construct(ty.i32(), 3_i));
- auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* func = Func("main", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
WorkgroupSize(4_i, "height", "depth"),
Stage(ast::PipelineStage::kCompute),
});
@@ -207,13 +207,13 @@ OpDecorate %3 BuiltIn WorkgroupSize
}
TEST_F(BuilderTest, Decoration_ExecutionMode_MultipleFragment) {
- auto* func1 = Func("main1", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* func1 = Func("main1", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
- auto* func2 = Func("main2", {}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* func2 = Func("main2", utils::Empty, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -242,13 +242,15 @@ OpFunctionEnd
}
TEST_F(BuilderTest, Decoration_ExecutionMode_FragDepth) {
- Func("main", ast::VariableList{}, ty.f32(),
- ast::StatementList{
+ Func("main", utils::Empty, ty.f32(),
+ utils::Vector{
Return(Expr(1_f)),
},
- ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
- ast::AttributeList{
- Builtin(ast::Builtin::kFragDepth),
+ utils::Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kFragDepth),
});
spirv::Builder& b = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_test.cc
index 2fd1c32696e..7cbd4420ac7 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_test.cc
@@ -24,7 +24,7 @@ namespace {
using BuilderTest = TestHelper;
TEST_F(BuilderTest, Function_Empty) {
- Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+ Func("a_func", utils::Empty, ty.void_(), utils::Empty);
spirv::Builder& b = Build();
@@ -41,11 +41,10 @@ OpFunctionEnd
}
TEST_F(BuilderTest, Function_Terminator_Return) {
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
- },
- ast::AttributeList{});
+ });
spirv::Builder& b = Build();
@@ -62,9 +61,9 @@ OpFunctionEnd
}
TEST_F(BuilderTest, Function_Terminator_ReturnValue) {
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
- Func("a_func", {}, ty.f32(), ast::StatementList{Return("a")}, ast::AttributeList{});
+ Func("a_func", utils::Empty, ty.f32(), utils::Vector{Return("a")}, utils::Empty);
spirv::Builder& b = Build();
@@ -89,11 +88,10 @@ OpFunctionEnd
}
TEST_F(BuilderTest, Function_Terminator_Discard) {
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
create<ast::DiscardStatement>(),
- },
- ast::AttributeList{});
+ });
spirv::Builder& b = Build();
@@ -110,9 +108,12 @@ OpFunctionEnd
}
TEST_F(BuilderTest, Function_WithParams) {
- ast::VariableList params = {Param("a", ty.f32()), Param("b", ty.i32())};
-
- Func("a_func", params, ty.f32(), ast::StatementList{Return("a")}, ast::AttributeList{});
+ Func("a_func",
+ utils::Vector{
+ Param("a", ty.f32()),
+ Param("b", ty.i32()),
+ },
+ ty.f32(), utils::Vector{Return("a")}, utils::Empty);
spirv::Builder& b = Build();
@@ -134,11 +135,10 @@ OpFunctionEnd
}
TEST_F(BuilderTest, Function_WithBody) {
- Func("a_func", {}, ty.void_(),
- ast::StatementList{
+ Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
- },
- ast::AttributeList{});
+ });
spirv::Builder& b = Build();
@@ -155,7 +155,7 @@ OpFunctionEnd
}
TEST_F(BuilderTest, FunctionType) {
- Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+ Func("a_func", utils::Empty, ty.void_(), utils::Empty, utils::Empty);
spirv::Builder& b = Build();
@@ -167,8 +167,8 @@ TEST_F(BuilderTest, FunctionType) {
}
TEST_F(BuilderTest, FunctionType_DeDuplicate) {
- auto* func1 = Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
- auto* func2 = Func("b_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+ auto* func1 = Func("a_func", utils::Empty, ty.void_(), utils::Empty, utils::Empty);
+ auto* func2 = Func("b_func", utils::Empty, ty.void_(), utils::Empty, utils::Empty);
spirv::Builder& b = Build();
@@ -196,34 +196,34 @@ TEST_F(BuilderTest, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
// return;
// }
- auto* s = Structure("Data", {Member("d", ty.f32())});
+ auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
- Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("a", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("a", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
}
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("b", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("b", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+ utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
}
spirv::Builder& b = SanitizeAndBuild();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_variable_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_variable_test.cc
index da72233cd7a..4045f4c6b05 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_variable_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_function_variable_test.cc
@@ -73,32 +73,34 @@ TEST_F(BuilderTest, FunctionVar_WithConstantConstructor) {
}
TEST_F(BuilderTest, FunctionVar_WithNonConstantConstructor) {
- auto* init = vec2<f32>(1_f, Add(3_f, 3_f));
+ auto* a = Let("a", nullptr, Expr(3_f));
+ auto* init = vec2<f32>(1_f, Add(Expr("a"), 3_f));
auto* v = Var("var", ty.vec2<f32>(), ast::StorageClass::kNone, init);
- WrapInFunction(v);
+ WrapInFunction(a, v);
spirv::Builder& b = Build();
b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateFunctionVariable(a)) << b.error();
EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %7 "var"
)");
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstant %2 1
-%4 = OpConstant %2 3
-%8 = OpTypePointer Function %1
-%9 = OpConstantNull %1
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+%2 = OpConstant %1 3
+%3 = OpTypeVector %1 2
+%4 = OpConstant %1 1
+%8 = OpTypePointer Function %3
+%9 = OpConstantNull %3
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
R"(%7 = OpVariable %8 Function %9
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%5 = OpFAdd %2 %4 %4
-%6 = OpCompositeConstruct %1 %3 %5
+ R"(%5 = OpFAdd %1 %2 %2
+%6 = OpCompositeConstruct %3 %4 %5
OpStore %7 %6
)");
}
@@ -138,7 +140,7 @@ OpStore %7 %6
)");
}
-TEST_F(BuilderTest, FunctionVar_ConstWithVarInitializer) {
+TEST_F(BuilderTest, FunctionVar_LetWithVarInitializer) {
// var v : f32 = 1.0;
// let v2 : f32 = v; // Should generate the load
@@ -173,7 +175,38 @@ OpStore %7 %6
)");
}
-TEST_F(BuilderTest, FunctionVar_Const) {
+TEST_F(BuilderTest, FunctionVar_ConstWithVarInitializer) {
+ // const v : f32 = 1.0;
+ // let v2 : f32 = v;
+
+ auto* v = Const("v", ty.f32(), Expr(1_f));
+
+ auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
+ WrapInFunction(v, v2);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+ EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v2"
+)");
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+%2 = OpConstant %1 1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+ R"(%3 = OpVariable %4 Function %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+)");
+}
+
+TEST_F(BuilderTest, FunctionVar_Let) {
auto* init = vec3<f32>(1_f, 1_f, 3_f);
auto* v = Let("var", ty.vec3<f32>(), init);
@@ -193,5 +226,20 @@ TEST_F(BuilderTest, FunctionVar_Const) {
)");
}
+TEST_F(BuilderTest, FunctionVar_Const) {
+ auto* init = vec3<f32>(1_f, 1_f, 3_f);
+
+ auto* v = Const("var", ty.vec3<f32>(), init);
+
+ WrapInFunction(v);
+
+ spirv::Builder& b = Build();
+
+ EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), ""); // Not a mistake - 'const' is inlined
+}
+
} // namespace
} // namespace tint::writer::spirv
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_global_variable_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_global_variable_test.cc
index 9b30bb168ab..e14a0174a96 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -25,7 +25,7 @@ namespace {
using BuilderTest = TestHelper;
TEST_F(BuilderTest, GlobalVar_WithStorageClass) {
- auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
spirv::Builder& b = Build();
@@ -42,7 +42,7 @@ TEST_F(BuilderTest, GlobalVar_WithStorageClass) {
TEST_F(BuilderTest, GlobalVar_WithConstructor) {
auto* init = vec3<f32>(1_f, 1_f, 3_f);
- auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate, init);
+ auto* v = GlobalVar("var", ty.vec3<f32>(), ast::StorageClass::kPrivate, init);
spirv::Builder& b = Build();
@@ -61,35 +61,129 @@ TEST_F(BuilderTest, GlobalVar_WithConstructor) {
)");
}
-TEST_F(BuilderTest, GlobalVar_Const) {
- auto* init = vec3<f32>(1_f, 1_f, 3_f);
+TEST_F(BuilderTest, GlobalConst) {
+ // const c = 42;
+ // var v = c;
- auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+ auto* c = GlobalConst("c", nullptr, Expr(42_a));
+ GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
- spirv::Builder& b = Build();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
- ASSERT_FALSE(b.has_error()) << b.error();
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %5 "var"
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+%2 = OpConstant %1 42
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, GlobalConst_Vec_Constructor) {
+ // const c = vec3<f32>(1f, 2f, 3f);
+ // var v = c;
+
+ auto* c = GlobalConst("c", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 3
%3 = OpConstant %2 1
-%4 = OpConstant %2 3
-%5 = OpConstantComposite %1 %3 %3 %4
+%4 = OpConstant %2 2
+%5 = OpConstant %2 3
+%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+ Validate(b);
}
-TEST_F(BuilderTest, GlobalVar_Complex_Constructor) {
- auto* init = vec3<f32>(1_f, 2_f, 3_f);
+TEST_F(BuilderTest, GlobalConst_Vec_F16_Constructor) {
+ // const c = vec3<f16>(1h, 2h, 3h);
+ // var v = c;
+ Enable(ast::Extension::kF16);
- auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+ auto* c = GlobalConst("c", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
- spirv::Builder& b = Build();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
- ASSERT_FALSE(b.has_error()) << b.error();
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, GlobalConst_Vec_AInt_Constructor) {
+ // const c = vec3(1, 2, 3);
+ // var v = c;
+
+ auto* c = GlobalConst("c", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 1
+%4 = OpConstant %2 2
+%5 = OpConstant %2 3
+%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+ Validate(b);
+}
+
+TEST_F(BuilderTest, GlobalConst_Vec_AFloat_Constructor) {
+ // const c = vec3(1.0, 2.0, 3.0);
+ // var v = c;
+
+ auto* c = GlobalConst("c", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 3
@@ -97,18 +191,28 @@ TEST_F(BuilderTest, GlobalVar_Complex_Constructor) {
%4 = OpConstant %2 2
%5 = OpConstant %2 3
%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
)");
+
+ Validate(b);
}
-TEST_F(BuilderTest, GlobalVar_Complex_ConstructorNestedVector) {
- auto* init = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
+TEST_F(BuilderTest, GlobalConst_Nested_Vec_Constructor) {
+ // const c = vec3<f32>(vec2<f32>(1f, 2f), 3f));
+ // var v = c;
- auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+ auto* c = GlobalConst("c", nullptr, vec3<f32>(vec2<f32>(1_f, 2_f), 3_f));
+ GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
- spirv::Builder& b = Build();
+ spirv::Builder& b = SanitizeAndBuild();
- EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
- ASSERT_FALSE(b.has_error()) << b.error();
+ ASSERT_TRUE(b.Build()) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeVector %2 3
@@ -116,16 +220,25 @@ TEST_F(BuilderTest, GlobalVar_Complex_ConstructorNestedVector) {
%4 = OpConstant %2 2
%5 = OpConstant %2 3
%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
)");
+
+ Validate(b);
}
TEST_F(BuilderTest, GlobalVar_WithBindingAndGroup) {
auto* v =
- Global("var", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
- ast::AttributeList{
- create<ast::BindingAttribute>(2),
- create<ast::GroupAttribute>(3),
- });
+ GlobalVar("var", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ create<ast::BindingAttribute>(2u),
+ create<ast::GroupAttribute>(3u),
+ });
spirv::Builder& b = Build();
@@ -143,7 +256,7 @@ OpDecorate %1 DescriptorSet 3
TEST_F(BuilderTest, GlobalVar_Override_Bool) {
auto* v = Override("var", ty.bool_(), Expr(true),
- ast::AttributeList{
+ utils::Vector{
Id(1200),
});
@@ -161,7 +274,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Bool) {
TEST_F(BuilderTest, GlobalVar_Override_Bool_ZeroValue) {
auto* v = Override("var", ty.bool_(), Construct<bool>(),
- ast::AttributeList{
+ utils::Vector{
Id(1200),
});
@@ -179,7 +292,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Bool_ZeroValue) {
TEST_F(BuilderTest, GlobalVar_Override_Bool_NoConstructor) {
auto* v = Override("var", ty.bool_(), nullptr,
- ast::AttributeList{
+ utils::Vector{
Id(1200),
});
@@ -197,7 +310,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Bool_NoConstructor) {
TEST_F(BuilderTest, GlobalVar_Override_Scalar) {
auto* v = Override("var", ty.f32(), Expr(2_f),
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
@@ -215,7 +328,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Scalar) {
TEST_F(BuilderTest, GlobalVar_Override_Scalar_ZeroValue) {
auto* v = Override("var", ty.f32(), Construct<f32>(),
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
@@ -233,7 +346,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Scalar_ZeroValue) {
TEST_F(BuilderTest, GlobalVar_Override_Scalar_F32_NoConstructor) {
auto* v = Override("var", ty.f32(), nullptr,
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
@@ -251,7 +364,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Scalar_F32_NoConstructor) {
TEST_F(BuilderTest, GlobalVar_Override_Scalar_I32_NoConstructor) {
auto* v = Override("var", ty.i32(), nullptr,
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
@@ -269,7 +382,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Scalar_I32_NoConstructor) {
TEST_F(BuilderTest, GlobalVar_Override_Scalar_U32_NoConstructor) {
auto* v = Override("var", ty.u32(), nullptr,
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
@@ -287,7 +400,7 @@ TEST_F(BuilderTest, GlobalVar_Override_Scalar_U32_NoConstructor) {
TEST_F(BuilderTest, GlobalVar_Override_NoId) {
auto* var_a = Override("a", ty.bool_(), Expr(true),
- ast::AttributeList{
+ utils::Vector{
Id(0),
});
auto* var_b = Override("b", ty.bool_(), Expr(false));
@@ -309,7 +422,7 @@ OpDecorate %3 SpecId 1
}
struct BuiltinData {
- ast::Builtin builtin;
+ ast::BuiltinValue builtin;
ast::StorageClass storage;
SpvBuiltIn result;
};
@@ -329,30 +442,31 @@ INSTANTIATE_TEST_SUITE_P(
BuilderTest_Type,
BuiltinDataTest,
testing::Values(
- BuiltinData{ast::Builtin::kNone, ast::StorageClass::kNone, SpvBuiltInMax},
- BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kInput, SpvBuiltInFragCoord},
- BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kOutput, SpvBuiltInPosition},
+ BuiltinData{ast::BuiltinValue::kInvalid, ast::StorageClass::kNone, SpvBuiltInMax},
+ BuiltinData{ast::BuiltinValue::kPosition, ast::StorageClass::kIn, SpvBuiltInFragCoord},
+ BuiltinData{ast::BuiltinValue::kPosition, ast::StorageClass::kOut, SpvBuiltInPosition},
BuiltinData{
- ast::Builtin::kVertexIndex,
- ast::StorageClass::kInput,
+ ast::BuiltinValue::kVertexIndex,
+ ast::StorageClass::kIn,
SpvBuiltInVertexIndex,
},
- BuiltinData{ast::Builtin::kInstanceIndex, ast::StorageClass::kInput,
+ BuiltinData{ast::BuiltinValue::kInstanceIndex, ast::StorageClass::kIn,
SpvBuiltInInstanceIndex},
- BuiltinData{ast::Builtin::kFrontFacing, ast::StorageClass::kInput, SpvBuiltInFrontFacing},
- BuiltinData{ast::Builtin::kFragDepth, ast::StorageClass::kOutput, SpvBuiltInFragDepth},
- BuiltinData{ast::Builtin::kLocalInvocationId, ast::StorageClass::kInput,
+ BuiltinData{ast::BuiltinValue::kFrontFacing, ast::StorageClass::kIn, SpvBuiltInFrontFacing},
+ BuiltinData{ast::BuiltinValue::kFragDepth, ast::StorageClass::kOut, SpvBuiltInFragDepth},
+ BuiltinData{ast::BuiltinValue::kLocalInvocationId, ast::StorageClass::kIn,
SpvBuiltInLocalInvocationId},
- BuiltinData{ast::Builtin::kLocalInvocationIndex, ast::StorageClass::kInput,
+ BuiltinData{ast::BuiltinValue::kLocalInvocationIndex, ast::StorageClass::kIn,
SpvBuiltInLocalInvocationIndex},
- BuiltinData{ast::Builtin::kGlobalInvocationId, ast::StorageClass::kInput,
+ BuiltinData{ast::BuiltinValue::kGlobalInvocationId, ast::StorageClass::kIn,
SpvBuiltInGlobalInvocationId},
- BuiltinData{ast::Builtin::kWorkgroupId, ast::StorageClass::kInput, SpvBuiltInWorkgroupId},
- BuiltinData{ast::Builtin::kNumWorkgroups, ast::StorageClass::kInput,
+ BuiltinData{ast::BuiltinValue::kWorkgroupId, ast::StorageClass::kIn, SpvBuiltInWorkgroupId},
+ BuiltinData{ast::BuiltinValue::kNumWorkgroups, ast::StorageClass::kIn,
SpvBuiltInNumWorkgroups},
- BuiltinData{ast::Builtin::kSampleIndex, ast::StorageClass::kInput, SpvBuiltInSampleId},
- BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kInput, SpvBuiltInSampleMask},
- BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kOutput, SpvBuiltInSampleMask}));
+ BuiltinData{ast::BuiltinValue::kSampleIndex, ast::StorageClass::kIn, SpvBuiltInSampleId},
+ BuiltinData{ast::BuiltinValue::kSampleMask, ast::StorageClass::kIn, SpvBuiltInSampleMask},
+ BuiltinData{ast::BuiltinValue::kSampleMask, ast::StorageClass::kOut,
+ SpvBuiltInSampleMask}));
TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
// struct A {
@@ -360,16 +474,16 @@ TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
// };
// var b<storage, read> : A
- auto* A = Structure("A", {
+ auto* A = Structure("A", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.i32()),
});
- Global("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -404,13 +518,13 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
// type B = A;
// var b<storage, read> : B
- auto* A = Structure("A", {Member("a", ty.i32())});
+ auto* A = Structure("A", utils::Vector{Member("a", ty.i32())});
auto* B = Alias("B", ty.Of(A));
- Global("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -443,13 +557,13 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
// type B = A;
// var<storage, read> b : B
- auto* A = Structure("A", {Member("a", ty.i32())});
+ auto* A = Structure("A", utils::Vector{Member("a", ty.i32())});
auto* B = Alias("B", ty.Of(A));
- Global("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -482,17 +596,17 @@ TEST_F(BuilderTest, GlobalVar_TwoVarDeclReadOnly) {
// var<storage, read> b : A
// var<storage, read_write> c : A
- auto* A = Structure("A", {Member("a", ty.i32())});
- Global("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::GroupAttribute>(0),
- create<ast::BindingAttribute>(0),
- });
- Global("c", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::GroupAttribute>(1),
- create<ast::BindingAttribute>(0),
- });
+ auto* A = Structure("A", utils::Vector{Member("a", ty.i32())});
+ GlobalVar("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::GroupAttribute>(0u),
+ create<ast::BindingAttribute>(0u),
+ });
+ GlobalVar("c", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::GroupAttribute>(1u),
+ create<ast::BindingAttribute>(0u),
+ });
spirv::Builder& b = SanitizeAndBuild();
@@ -529,11 +643,11 @@ TEST_F(BuilderTest, GlobalVar_TextureStorageWriteOnly) {
auto* type = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
ast::Access::kWrite);
- auto* var_a = Global("a", type,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* var_a = GlobalVar("a", type,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -560,19 +674,19 @@ TEST_F(BuilderTest, DISABLED_GlobalVar_TextureStorageWithDifferentAccess) {
auto* type_a = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
ast::Access::kReadWrite);
- auto* var_a = Global("a", type_a, ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* var_a = GlobalVar("a", type_a, ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
auto* type_b = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
ast::Access::kWrite);
- auto* var_b = Global("b", type_b, ast::StorageClass::kNone,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(0),
- });
+ auto* var_b = GlobalVar("b", type_b, ast::StorageClass::kNone,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -599,16 +713,16 @@ OpDecorate %5 DescriptorSet 0
TEST_F(BuilderTest, GlobalVar_WorkgroupWithZeroInit) {
auto* type_scalar = ty.i32();
- auto* var_scalar = Global("a", type_scalar, ast::StorageClass::kWorkgroup);
+ auto* var_scalar = GlobalVar("a", type_scalar, ast::StorageClass::kWorkgroup);
auto* type_array = ty.array<f32, 16>();
- auto* var_array = Global("b", type_array, ast::StorageClass::kWorkgroup);
+ auto* var_array = GlobalVar("b", type_array, ast::StorageClass::kWorkgroup);
- auto* type_struct = Structure("C", {
+ auto* type_struct = Structure("C", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.i32()),
});
- auto* var_struct = Global("c", ty.Of(type_struct), ast::StorageClass::kWorkgroup);
+ auto* var_struct = GlobalVar("c", ty.Of(type_struct), ast::StorageClass::kWorkgroup);
program = std::make_unique<Program>(std::move(*this));
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_ident_expression_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_ident_expression_test.cc
index e2e9826a27b..0f24146580d 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_ident_expression_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_ident_expression_test.cc
@@ -25,9 +25,9 @@ using BuilderTest = TestHelper;
TEST_F(BuilderTest, IdentifierExpression_GlobalConst) {
auto* init = vec3<f32>(1_f, 1_f, 3_f);
- auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+ auto* v = GlobalConst("c", ty.vec3<f32>(), init);
- auto* expr = Expr("var");
+ auto* expr = Expr("c");
WrapInFunction(expr);
spirv::Builder& b = Build();
@@ -35,18 +35,13 @@ TEST_F(BuilderTest, IdentifierExpression_GlobalConst) {
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
ASSERT_FALSE(b.has_error()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 3
-%3 = OpConstant %2 1
-%4 = OpConstant %2 3
-%5 = OpConstantComposite %1 %3 %3 %4
-)");
+ EXPECT_EQ(DumpInstructions(b.types()), R"()");
- EXPECT_EQ(b.GenerateIdentifierExpression(expr), 5u);
+ EXPECT_EQ(b.GenerateIdentifierExpression(expr), 0u);
}
TEST_F(BuilderTest, IdentifierExpression_GlobalVar) {
- auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Expr("var");
WrapInFunction(expr);
@@ -114,8 +109,7 @@ TEST_F(BuilderTest, IdentifierExpression_FunctionVar) {
}
TEST_F(BuilderTest, IdentifierExpression_Load) {
- auto* var = Global("var", ty.i32(), ast::StorageClass::kPrivate);
-
+ auto* var = GlobalVar("var", ty.i32(), ast::StorageClass::kPrivate);
auto* expr = Add("var", "var");
WrapInFunction(expr);
@@ -138,15 +132,14 @@ TEST_F(BuilderTest, IdentifierExpression_Load) {
}
TEST_F(BuilderTest, IdentifierExpression_NoLoadConst) {
- auto* var = GlobalConst("var", ty.i32(), Expr(2_i));
-
- auto* expr = Add("var", "var");
- WrapInFunction(expr);
+ auto* let = Let("let", ty.i32(), Expr(2_i));
+ auto* expr = Add("let", "let");
+ WrapInFunction(let, expr);
spirv::Builder& b = Build();
b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ ASSERT_TRUE(b.GenerateFunctionVariable(let)) << b.error();
EXPECT_EQ(b.GenerateBinaryExpression(expr->As<ast::BinaryExpression>()), 3u) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_if_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_if_test.cc
index 8c7c8eef0f2..6705cce586c 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_if_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_if_test.cc
@@ -68,7 +68,7 @@ TEST_F(BuilderTest, If_WithStatements) {
// v = 2;
// }
- auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
auto* body = Block(Assign("v", 2_i));
auto* expr = If(true, body);
WrapInFunction(expr);
@@ -104,7 +104,7 @@ TEST_F(BuilderTest, If_WithElse) {
// v = 3i;
// }
- auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
auto* body = Block(Assign("v", 2_i));
auto* else_body = Block(Assign("v", 3_i));
@@ -146,7 +146,7 @@ TEST_F(BuilderTest, If_WithElseIf) {
// v = 3i;
// }
- auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
auto* body = Block(Assign("v", 2_i));
auto* else_body = Block(Assign("v", 3_i));
@@ -197,7 +197,7 @@ TEST_F(BuilderTest, If_WithMultiple) {
// v = 5i;
// }
- auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
auto* body = Block(Assign("v", 2_i));
auto* elseif_1_body = Block(Assign("v", 3_i));
auto* elseif_2_body = Block(Assign("v", 4_i));
@@ -434,7 +434,10 @@ TEST_F(BuilderTest, If_WithReturn) {
// return;
// }
- auto* fn = Func("f", {}, ty.void_(), {If(true, Block(Return()))});
+ auto* fn = Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ If(true, Block(Return())),
+ });
spirv::Builder& b = Build();
@@ -460,8 +463,8 @@ TEST_F(BuilderTest, If_WithReturnValue) {
// }
// return true;
- auto* fn = Func("f", {}, ty.bool_(),
- {
+ auto* fn = Func("f", utils::Empty, ty.bool_(),
+ utils::Vector{
If(true, Block(Return(false))),
Return(true),
});
@@ -491,8 +494,8 @@ TEST_F(BuilderTest, IfElse_BothReturn) {
// return true;
// }
- auto* fn = Func("f", {}, ty.bool_(),
- {
+ auto* fn = Func("f", utils::Empty, ty.bool_(),
+ utils::Vector{
If(true, //
Block(Return(true)), //
Else(Block(Return(true)))),
@@ -530,8 +533,8 @@ TEST_F(BuilderTest, If_WithNestedBlockReturnValue) {
// }
// return true;
- auto* fn = Func("f", {}, ty.bool_(),
- {
+ auto* fn = Func("f", utils::Empty, ty.bool_(),
+ utils::Vector{
If(true, Block(Block(Block(Block(Return(false)))))),
Return(true),
});
@@ -559,8 +562,11 @@ TEST_F(BuilderTest, If_WithLoad_Bug327) {
// if (a) {
// }
- auto* var = Global("a", ty.bool_(), ast::StorageClass::kPrivate);
- auto* fn = Func("f", {}, ty.void_(), {If("a", Block())});
+ auto* var = GlobalVar("a", ty.bool_(), ast::StorageClass::kPrivate);
+ auto* fn = Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ If("a", Block()),
+ });
spirv::Builder& b = Build();
@@ -592,7 +598,7 @@ TEST_F(BuilderTest, If_ElseIf_WithReturn) {
// }
auto* if_stmt = If(false, Block(), Else(If(true, Block(Return()))));
- auto* fn = Func("f", {}, ty.void_(), {if_stmt});
+ auto* fn = Func("f", utils::Empty, ty.void_(), utils::Vector{if_stmt});
spirv::Builder& b = Build();
@@ -630,7 +636,10 @@ TEST_F(BuilderTest, Loop_If_ElseIf_WithBreak) {
// }
auto* if_stmt = If(false, Block(), Else(If(true, Block(Break()))));
- auto* fn = Func("f", {}, ty.void_(), {Loop(Block(if_stmt))});
+ auto* fn = Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Loop(Block(if_stmt)),
+ });
spirv::Builder& b = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_literal_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_literal_test.cc
index 218db86919a..374c80be123 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_literal_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_literal_test.cc
@@ -163,4 +163,39 @@ TEST_F(BuilderTest, Literal_F32_Dedup) {
)");
}
+TEST_F(BuilderTest, Literal_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* i = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
+ WrapInFunction(i);
+
+ spirv::Builder& b = Build();
+
+ auto id = b.GenerateLiteralIfNeeded(nullptr, i);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(2u, id);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.73cp+4
+)");
+}
+
+TEST_F(BuilderTest, Literal_F16_Dedup) {
+ Enable(ast::Extension::kF16);
+
+ auto* i1 = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
+ auto* i2 = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
+ WrapInFunction(i1, i2);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
+ ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.73cp+4
+)");
+}
+
} // namespace tint::writer::spirv
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_loop_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_loop_test.cc
index b4c2baa5e54..ae9e408f9d1 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_loop_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_loop_test.cc
@@ -54,7 +54,7 @@ TEST_F(BuilderTest, Loop_WithoutContinuing) {
// break;
// }
- auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
auto* body = Block(Assign("v", 2_i), //
Break());
@@ -96,7 +96,7 @@ TEST_F(BuilderTest, Loop_WithContinuing) {
// }
// }
- auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* var = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
auto* body = Block(Assign("v", 2_i), //
Break());
auto* continuing = Block(Assign("v", 3_i));
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_return_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_return_test.cc
index 0027311e3cb..825529e9066 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_return_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_return_test.cc
@@ -40,7 +40,7 @@ TEST_F(BuilderTest, Return_WithValue) {
auto* val = vec3<f32>(1_f, 1_f, 3_f);
auto* ret = Return(val);
- Func("test", {}, ty.vec3<f32>(), {ret}, {});
+ Func("test", utils::Empty, ty.vec3<f32>(), utils::Vector{ret}, utils::Empty);
spirv::Builder& b = Build();
@@ -63,7 +63,7 @@ TEST_F(BuilderTest, Return_WithValue_GeneratesLoad) {
auto* var = Var("param", ty.f32());
auto* ret = Return(var);
- Func("test", {}, ty.f32(), {Decl(var), ret}, {});
+ Func("test", utils::Empty, ty.f32(), utils::Vector{Decl(var), ret}, utils::Empty);
spirv::Builder& b = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_static_assert_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_static_assert_test.cc
new file mode 100644
index 00000000000..c6d6a51ec0d
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_static_assert_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/fallthrough_statement.h"
+#include "src/tint/writer/spirv/spv_dump.h"
+#include "src/tint/writer/spirv/test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::writer::spirv {
+namespace {
+
+using BuilderTest = TestHelper;
+
+TEST_F(BuilderTest, GlobalStaticAssert) {
+ GlobalStaticAssert(true);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ // static asserts are not emitted
+ EXPECT_EQ(DumpInstructions(b.types()), "");
+ EXPECT_EQ(b.functions().size(), 0u);
+}
+
+TEST_F(BuilderTest, FunctionStaticAssert) {
+ Func("f", utils::Empty, ty.void_(), utils::Vector{StaticAssert(true)});
+
+ spirv::Builder& b = Build();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ // static asserts are not emitted
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+}
+
+} // namespace
+} // namespace tint::writer::spirv
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_switch_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_switch_test.cc
index 7ddd1bdac8d..c2f526e5c2d 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_switch_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_switch_test.cc
@@ -57,11 +57,11 @@ TEST_F(BuilderTest, Switch_WithCase) {
// default: {}
// }
- auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
- auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Switch("a", //
Case(Expr(1_i), Block(Assign("v", 1_i))), //
Case(Expr(2_i), Block(Assign("v", 2_i))), //
@@ -114,11 +114,11 @@ TEST_F(BuilderTest, Switch_WithCase_Unsigned) {
// default: {}
// }
- auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
- auto* a = Global("a", ty.u32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.u32(), ast::StorageClass::kPrivate);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Switch("a", //
Case(Expr(1_u), Block(Assign("v", 1_i))), //
Case(Expr(2_u), Block(Assign("v", 2_i))), //
@@ -171,11 +171,11 @@ TEST_F(BuilderTest, Switch_WithDefault) {
// v = 1i;
// }
- auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
- auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Switch("a", //
DefaultCase(Block(Assign("v", 1_i)))), //
});
@@ -221,16 +221,16 @@ TEST_F(BuilderTest, Switch_WithCaseAndDefault) {
// v = 3i;
// }
- auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
- auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
- auto* func = Func("a_func", {}, ty.void_(),
- {
- Switch(Expr("a"), //
- Case(Expr(1_i), //
- Block(Assign("v", 1_i))), //
- Case({Expr(2_i), Expr(3_i)}, //
- Block(Assign("v", 2_i))), //
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Switch(Expr("a"), //
+ Case(Expr(1_i), //
+ Block(Assign("v", 1_i))), //
+ Case(utils::Vector{Expr(2_i), Expr(3_i)}, //
+ Block(Assign("v", 2_i))), //
DefaultCase(Block(Assign("v", 3_i)))),
});
@@ -284,11 +284,11 @@ TEST_F(BuilderTest, Switch_CaseWithFallthrough) {
// v = 3i;
// }
- auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
- auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Switch(Expr("a"), //
Case(Expr(1_i), //
Block(Assign("v", 1_i), Fallthrough())), //
@@ -346,11 +346,11 @@ TEST_F(BuilderTest, Switch_WithNestedBreak) {
// default: {}
// }
- auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
- auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
+ auto* a = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
- auto* func = Func("a_func", {}, ty.void_(),
- {
+ auto* func = Func("a_func", utils::Empty, ty.void_(),
+ utils::Vector{
Switch("a", //
Case(Expr(1_i), //
Block( //
@@ -412,8 +412,8 @@ TEST_F(BuilderTest, Switch_AllReturn) {
// }
// }
- auto* fn = Func("f", {}, ty.i32(),
- {
+ auto* fn = Func("f", utils::Empty, ty.i32(),
+ utils::Vector{
Switch(1_i, //
Case(Expr(1_i), Block(Return(1_i))), //
Case(Expr(2_i), Block(Fallthrough())), //
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/builder_type_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/builder_type_test.cc
index 8dc048e998c..58fc17458ae 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/builder_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/builder_type_test.cc
@@ -27,12 +27,12 @@ using BuilderTest_Type = TestHelper;
TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
auto* ary = ty.array(ty.i32());
- auto* str = Structure("S", {Member("x", ary)});
- Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* str = Structure("S", utils::Vector{Member("x", ary)});
+ GlobalVar("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -47,12 +47,12 @@ TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
auto* ary = ty.array(ty.i32());
- auto* str = Structure("S", {Member("x", ary)});
- Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* str = Structure("S", utils::Vector{Member("x", ary)});
+ GlobalVar("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -67,7 +67,7 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
TEST_F(BuilderTest_Type, GenerateArray) {
auto* ary = ty.array(ty.i32(), 4_u);
- Global("a", ary, ast::StorageClass::kPrivate);
+ GlobalVar("a", ary, ast::StorageClass::kPrivate);
spirv::Builder& b = Build();
@@ -84,7 +84,7 @@ TEST_F(BuilderTest_Type, GenerateArray) {
TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
auto* ary = ty.array(ty.i32(), 4_u, 16u);
- Global("a", ary, ast::StorageClass::kPrivate);
+ GlobalVar("a", ary, ast::StorageClass::kPrivate);
spirv::Builder& b = Build();
@@ -104,7 +104,7 @@ TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
TEST_F(BuilderTest_Type, ReturnsGeneratedArray) {
auto* ary = ty.array(ty.i32(), 4_u);
- Global("a", ary, ast::StorageClass::kPrivate);
+ GlobalVar("a", ary, ast::StorageClass::kPrivate);
spirv::Builder& b = Build();
@@ -175,6 +175,34 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedF32) {
ASSERT_FALSE(b.has_error()) << b.error();
}
+TEST_F(BuilderTest_Type, GenerateF16) {
+ auto* f16 = create<sem::F16>();
+
+ spirv::Builder& b = Build();
+
+ auto id = b.GenerateTypeIfNeeded(f16);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(id, 1u);
+
+ ASSERT_EQ(b.types().size(), 1u);
+ EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeFloat 16
+)");
+}
+
+TEST_F(BuilderTest_Type, ReturnsGeneratedF16) {
+ auto* f16 = create<sem::F16>();
+ auto* i32 = create<sem::I32>();
+
+ spirv::Builder& b = Build();
+
+ EXPECT_EQ(b.GenerateTypeIfNeeded(f16), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(f16), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+}
+
TEST_F(BuilderTest_Type, GenerateI32) {
auto* i32 = create<sem::I32>();
@@ -236,9 +264,42 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedMatrix) {
ASSERT_FALSE(b.has_error()) << b.error();
}
+TEST_F(BuilderTest_Type, GenerateF16Matrix) {
+ auto* f16 = create<sem::F16>();
+ auto* vec3 = create<sem::Vector>(f16, 3u);
+ auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+
+ spirv::Builder& b = Build();
+
+ auto id = b.GenerateTypeIfNeeded(mat2x3);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(id, 1u);
+
+ EXPECT_EQ(b.types().size(), 3u);
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 2
+)");
+}
+
+TEST_F(BuilderTest_Type, ReturnsGeneratedF16Matrix) {
+ auto* f16 = create<sem::F16>();
+ auto* col = create<sem::Vector>(f16, 4u);
+ auto* mat = create<sem::Matrix>(col, 3u);
+
+ spirv::Builder& b = Build();
+
+ EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(f16), 3u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+}
+
TEST_F(BuilderTest_Type, GeneratePtr) {
auto* i32 = create<sem::I32>();
- auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput, ast::Access::kReadWrite);
+ auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOut, ast::Access::kReadWrite);
spirv::Builder& b = Build();
@@ -253,7 +314,7 @@ TEST_F(BuilderTest_Type, GeneratePtr) {
TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
auto* i32 = create<sem::I32>();
- auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput, ast::Access::kReadWrite);
+ auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOut, ast::Access::kReadWrite);
spirv::Builder& b = Build();
@@ -262,7 +323,7 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
}
TEST_F(BuilderTest_Type, GenerateStruct) {
- auto* s = Structure("my_struct", {Member("a", ty.f32())});
+ auto* s = Structure("my_struct", utils::Vector{Member("a", ty.f32())});
spirv::Builder& b = Build();
@@ -279,9 +340,9 @@ OpMemberName %1 0 "a"
}
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.f32()),
- Member("b", ty.f32(), {MemberAlign(8)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(8)}),
});
spirv::Builder& b = Build();
@@ -303,7 +364,7 @@ OpMemberDecorate %1 1 Offset 8
}
TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.mat2x2<f32>()),
Member("b", ty.mat2x3<f32>()),
Member("c", ty.mat4x4<f32>()),
@@ -343,7 +404,7 @@ OpMemberDecorate %1 2 MatrixStride 16
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
// We have to infer layout for matrix when it also has an offset.
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.mat2x2<f32>()),
Member("b", ty.mat2x3<f32>()),
Member("c", ty.mat4x4<f32>()),
@@ -389,7 +450,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
auto* arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1_u); // Doubly nested array
auto* rtarr_mat4x4 = ty.array(ty.mat4x4<f32>()); // Runtime array
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", arr_mat2x2),
Member("b", arr_arr_mat2x3),
Member("c", rtarr_mat4x4),
@@ -540,8 +601,8 @@ INSTANTIATE_TEST_SUITE_P(
BuilderTest_Type,
PtrDataTest,
testing::Values(PtrData{ast::StorageClass::kNone, SpvStorageClassMax},
- PtrData{ast::StorageClass::kInput, SpvStorageClassInput},
- PtrData{ast::StorageClass::kOutput, SpvStorageClassOutput},
+ PtrData{ast::StorageClass::kIn, SpvStorageClassInput},
+ PtrData{ast::StorageClass::kOut, SpvStorageClassOutput},
PtrData{ast::StorageClass::kUniform, SpvStorageClassUniform},
PtrData{ast::StorageClass::kWorkgroup, SpvStorageClassWorkgroup},
PtrData{ast::StorageClass::kHandle, SpvStorageClassUniformConstant},
@@ -781,11 +842,11 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
auto* s = ty.storage_texture(ast::TextureDimension::k1d, ast::TexelFormat::kR32Float,
ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -800,11 +861,11 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -819,11 +880,11 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
auto* s = ty.storage_texture(ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Float,
ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -838,11 +899,11 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
auto* s = ty.storage_texture(ast::TextureDimension::k3d, ast::TexelFormat::kR32Float,
ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -857,11 +918,11 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeFloat_Format_r32floa
auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -876,11 +937,11 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeSint_Format_r32sint)
auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Sint,
ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
@@ -895,11 +956,11 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeUint_Format_r32uint)
auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
ast::Access::kWrite);
- Global("test_var", s,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("test_var", s,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
spirv::Builder& b = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/generator_impl.cc b/chromium/third_party/dawn/src/tint/writer/spirv/generator_impl.cc
index b8ca89c4b15..85865627414 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/generator_impl.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/generator_impl.cc
@@ -26,12 +26,14 @@
#include "src/tint/transform/for_loop_to_loop.h"
#include "src/tint/transform/manager.h"
#include "src/tint/transform/promote_side_effects_to_decl.h"
+#include "src/tint/transform/remove_phonies.h"
#include "src/tint/transform/remove_unreachable_statements.h"
#include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/unshadow.h"
#include "src/tint/transform/unwind_discard_functions.h"
#include "src/tint/transform/var_for_dynamic_index.h"
#include "src/tint/transform/vectorize_scalar_matrix_constructors.h"
+#include "src/tint/transform/while_to_loop.h"
#include "src/tint/transform/zero_init_workgroup_memory.h"
#include "src/tint/writer/generate_external_texture_bindings.h"
@@ -45,6 +47,8 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
{ // Builtin polyfills
transform::BuiltinPolyfill::Builtins polyfills;
+ polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
+ polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
polyfills.count_leading_zeros = true;
polyfills.count_trailing_zeros = true;
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
@@ -72,9 +76,10 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
manager.Add<transform::PromoteSideEffectsToDecl>();
manager.Add<transform::UnwindDiscardFunctions>();
manager.Add<transform::SimplifyPointers>(); // Required for arrayLength()
+ manager.Add<transform::RemovePhonies>();
manager.Add<transform::VectorizeScalarMatrixConstructors>();
manager.Add<transform::ForLoopToLoop>(); // Must come after
- // ZeroInitWorkgroupMemory
+ manager.Add<transform::WhileToLoop>(); // ZeroInitWorkgroupMemory
manager.Add<transform::CanonicalizeEntryPointIO>();
manager.Add<transform::AddEmptyEntryPoint>();
manager.Add<transform::AddSpirvBlockAttribute>();
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/operand.h b/chromium/third_party/dawn/src/tint/writer/spirv/operand.h
index 3174d0cc301..dab10e9141d 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/operand.h
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/operand.h
@@ -17,8 +17,7 @@
#include <cstring>
#include <string>
-// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
-#include <variant> // NOLINT(build/include_order)
+#include <variant>
#include <vector>
#include "src/tint/utils/hash.h"
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant.h b/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant.h
index 14bcefbc174..0629d0cdc46 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant.h
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant.h
@@ -20,6 +20,7 @@
#include <cstring>
#include <functional>
+#include "src/tint/number.h"
#include "src/tint/utils/hash.h"
// Forward declarations
@@ -31,6 +32,12 @@ namespace tint::writer::spirv {
/// ScalarConstant represents a scalar constant value
struct ScalarConstant {
+ /// The struct type to hold the bits representation of f16 in the Value union
+ struct F16 {
+ /// The 16 bits representation of the f16, stored as uint16_t
+ uint16_t bits_representation;
+ };
+
/// The constant value
union Value {
/// The value as a bool
@@ -41,6 +48,8 @@ struct ScalarConstant {
int32_t i32;
/// The value as a float
float f32;
+ /// The value as bits representation of a f16
+ F16 f16;
/// The value that is wide enough to encompass all other types (including
/// future 64-bit data types).
@@ -48,7 +57,7 @@ struct ScalarConstant {
};
/// The kind of constant
- enum class Kind { kBool, kU32, kI32, kF32 };
+ enum class Kind { kBool, kU32, kI32, kF32, kF16 };
/// Constructor
inline ScalarConstant() { value.u64 = 0; }
@@ -72,7 +81,7 @@ struct ScalarConstant {
}
/// @param value the value of the constant
- /// @returns a new ScalarConstant with the provided value and kind Kind::kI32
+ /// @returns a new ScalarConstant with the provided value and kind Kind::kF32
static inline ScalarConstant F32(float value) {
ScalarConstant c;
c.value.f32 = value;
@@ -81,6 +90,15 @@ struct ScalarConstant {
}
/// @param value the value of the constant
+ /// @returns a new ScalarConstant with the provided value and kind Kind::kF16
+ static inline ScalarConstant F16(f16::type value) {
+ ScalarConstant c;
+ c.value.f16 = {f16(value).BitsRepresentation()};
+ c.kind = Kind::kF16;
+ return c;
+ }
+
+ /// @param value the value of the constant
/// @returns a new ScalarConstant with the provided value and kind Kind::kBool
static inline ScalarConstant Bool(bool value) {
ScalarConstant c;
diff --git a/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant_test.cc b/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant_test.cc
index 196e600e148..b00f82ab0b2 100644
--- a/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/spirv/scalar_constant_test.cc
@@ -52,5 +52,12 @@ TEST_F(SpirvScalarConstantTest, U32) {
EXPECT_EQ(c.kind, ScalarConstant::Kind::kU32);
}
+TEST_F(SpirvScalarConstantTest, F16) {
+ auto c = ScalarConstant::F16(123.456f);
+ // 123.456f will be quantized to f16 123.4375h, bit pattern 0x57b7
+ EXPECT_EQ(c.value.f16.bits_representation, 0x57b7u);
+ EXPECT_EQ(c.kind, ScalarConstant::Kind::kF16);
+}
+
} // namespace
} // namespace tint::writer::spirv
diff --git a/chromium/third_party/dawn/src/tint/writer/text_generator.cc b/chromium/third_party/dawn/src/tint/writer/text_generator.cc
index 5e4e93f801b..3dabb5caaf2 100644
--- a/chromium/third_party/dawn/src/tint/writer/text_generator.cc
+++ b/chromium/third_party/dawn/src/tint/writer/text_generator.cc
@@ -84,12 +84,13 @@ void TextGenerator::TextBuffer::Insert(const std::string& line, size_t before, u
<< " lines.size(): " << lines.size();
return;
}
- lines.insert(lines.begin() + before, Line{indent, line});
+ using DT = decltype(lines)::difference_type;
+ lines.insert(lines.begin() + static_cast<DT>(before), Line{indent, line});
}
void TextGenerator::TextBuffer::Append(const TextBuffer& tb) {
for (auto& line : tb.lines) {
- // TODO(bclayton): inefficent, consider optimizing
+ // TODO(bclayton): inefficient, consider optimizing
lines.emplace_back(Line{current_indent + line.indent, line.content});
}
}
@@ -104,8 +105,10 @@ void TextGenerator::TextBuffer::Insert(const TextBuffer& tb, size_t before, uint
}
size_t idx = 0;
for (auto& line : tb.lines) {
- // TODO(bclayton): inefficent, consider optimizing
- lines.insert(lines.begin() + before + idx, Line{indent + line.indent, line.content});
+ // TODO(bclayton): inefficient, consider optimizing
+ using DT = decltype(lines)::difference_type;
+ lines.insert(lines.begin() + static_cast<DT>(before + idx),
+ Line{indent + line.indent, line.content});
idx++;
}
}
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.cc
index 5e0ce8c16f0..efc96016a00 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.cc
@@ -67,7 +67,7 @@ bool GeneratorImpl::Generate() {
return false;
}
}
- if (!program_->AST().Enables().empty()) {
+ if (!program_->AST().Enables().IsEmpty()) {
line();
}
// Generate global declarations in the order they appear in the module.
@@ -80,13 +80,14 @@ bool GeneratorImpl::Generate() {
[&](const ast::TypeDecl* td) { return EmitTypeDecl(td); },
[&](const ast::Function* func) { return EmitFunction(func); },
[&](const ast::Variable* var) { return EmitVariable(line(), var); },
+ [&](const ast::StaticAssert* sa) { return EmitStaticAssert(sa); },
[&](Default) {
TINT_UNREACHABLE(Writer, diagnostics_);
return false;
})) {
return false;
}
- if (decl != program_->AST().GlobalDeclarations().back()) {
+ if (decl != program_->AST().GlobalDeclarations().Back()) {
line();
}
}
@@ -258,6 +259,10 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
return true;
},
[&](const ast::FloatLiteralExpression* l) { //
+ // f16 literals are also emitted as float value with suffix "h".
+ // Note that all normal and subnormal f16 values are normal f32 values, and since NaN
+ // and Inf are not allowed to be spelled in literal, it should be fine to emit f16
+ // literals in this way.
out << FloatToBitPreservingString(static_cast<float>(l->value)) << l->suffix;
return true;
},
@@ -277,7 +282,7 @@ bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpre
}
bool GeneratorImpl::EmitFunction(const ast::Function* func) {
- if (func->attributes.size()) {
+ if (func->attributes.Length()) {
if (!EmitAttributes(line(), func->attributes)) {
return false;
}
@@ -293,7 +298,7 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
}
first = false;
- if (!v->attributes.empty()) {
+ if (!v->attributes.IsEmpty()) {
if (!EmitAttributes(out, v->attributes)) {
return false;
}
@@ -309,10 +314,10 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
out << ")";
- if (!func->return_type->Is<ast::Void>() || !func->return_type_attributes.empty()) {
+ if (!func->return_type->Is<ast::Void>() || !func->return_type_attributes.IsEmpty()) {
out << " -> ";
- if (!func->return_type_attributes.empty()) {
+ if (!func->return_type_attributes.IsEmpty()) {
if (!EmitAttributes(out, func->return_type_attributes)) {
return false;
}
@@ -341,7 +346,7 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
bool GeneratorImpl::EmitImageFormat(std::ostream& out, const ast::TexelFormat fmt) {
switch (fmt) {
- case ast::TexelFormat::kNone:
+ case ast::TexelFormat::kInvalid:
diagnostics_.add_error(diag::System::Writer, "unknown image format");
return false;
default:
@@ -378,19 +383,22 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
}
}
- out << "array<";
- if (!EmitType(out, ary->type)) {
- return false;
- }
+ out << "array";
+ if (ary->type) {
+ out << "<";
+ TINT_DEFER(out << ">");
- if (!ary->IsRuntimeArray()) {
- out << ", ";
- if (!EmitExpression(out, ary->count)) {
+ if (!EmitType(out, ary->type)) {
return false;
}
- }
- out << ">";
+ if (!ary->IsRuntimeArray()) {
+ out << ", ";
+ if (!EmitExpression(out, ary->count)) {
+ return false;
+ }
+ }
+ }
return true;
},
[&](const ast::Bool*) {
@@ -402,9 +410,8 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
return true;
},
[&](const ast::F16*) {
- diagnostics_.add_error(diag::System::Writer,
- "Type f16 is not completely implemented yet.");
- return false;
+ out << "f16";
+ return true;
},
[&](const ast::I32*) {
out << "i32";
@@ -576,7 +583,7 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
}
bool GeneratorImpl::EmitStructType(const ast::Struct* str) {
- if (str->attributes.size()) {
+ if (str->attributes.Length()) {
if (!EmitAttributes(line(), str->attributes)) {
return false;
}
@@ -608,15 +615,15 @@ bool GeneratorImpl::EmitStructType(const ast::Struct* str) {
// Offset attributes no longer exist in the WGSL spec, but are emitted
// by the SPIR-V reader and are consumed by the Resolver(). These should not
// be emitted, but instead struct padding fields should be emitted.
- ast::AttributeList attributes_sanitized;
- attributes_sanitized.reserve(mem->attributes.size());
+ utils::Vector<const ast::Attribute*, 4> attributes_sanitized;
+ attributes_sanitized.Reserve(mem->attributes.Length());
for (auto* attr : mem->attributes) {
if (!attr->Is<ast::StructMemberOffsetAttribute>()) {
- attributes_sanitized.emplace_back(attr);
+ attributes_sanitized.Push(attr);
}
}
- if (!attributes_sanitized.empty()) {
+ if (!attributes_sanitized.IsEmpty()) {
if (!EmitAttributes(line(), attributes_sanitized)) {
return false;
}
@@ -635,46 +642,64 @@ bool GeneratorImpl::EmitStructType(const ast::Struct* str) {
return true;
}
-bool GeneratorImpl::EmitVariable(std::ostream& out, const ast::Variable* var) {
- if (!var->attributes.empty()) {
- if (!EmitAttributes(out, var->attributes)) {
+bool GeneratorImpl::EmitVariable(std::ostream& out, const ast::Variable* v) {
+ if (!v->attributes.IsEmpty()) {
+ if (!EmitAttributes(out, v->attributes)) {
return false;
}
out << " ";
}
- if (var->is_overridable) {
- out << "override";
- } else if (var->is_const) {
- out << "let";
- } else {
- out << "var";
- auto sc = var->declared_storage_class;
- auto ac = var->declared_access;
- if (sc != ast::StorageClass::kNone || ac != ast::Access::kUndefined) {
- out << "<" << sc;
- if (ac != ast::Access::kUndefined) {
- out << ", ";
- if (!EmitAccess(out, ac)) {
- return false;
+ bool ok = Switch(
+ v, //
+ [&](const ast::Var* var) {
+ out << "var";
+ auto sc = var->declared_storage_class;
+ auto ac = var->declared_access;
+ if (sc != ast::StorageClass::kNone || ac != ast::Access::kUndefined) {
+ out << "<" << sc;
+ if (ac != ast::Access::kUndefined) {
+ out << ", ";
+ if (!EmitAccess(out, ac)) {
+ return false;
+ }
}
+ out << ">";
}
- out << ">";
- }
+ return true;
+ },
+ [&](const ast::Let*) {
+ out << "let";
+ return true;
+ },
+ [&](const ast::Override*) {
+ out << "override";
+ return true;
+ },
+ [&](const ast::Const*) {
+ out << "const";
+ return true;
+ },
+ [&](Default) {
+ TINT_ICE(Writer, diagnostics_) << "unhandled variable type " << v->TypeInfo().name;
+ return false;
+ });
+ if (!ok) {
+ return false;
}
- out << " " << program_->Symbols().NameFor(var->symbol);
+ out << " " << program_->Symbols().NameFor(v->symbol);
- if (auto* ty = var->type) {
+ if (auto* ty = v->type) {
out << " : ";
if (!EmitType(out, ty)) {
return false;
}
}
- if (var->constructor != nullptr) {
+ if (v->constructor != nullptr) {
out << " = ";
- if (!EmitExpression(out, var->constructor)) {
+ if (!EmitExpression(out, v->constructor)) {
return false;
}
}
@@ -683,7 +708,8 @@ bool GeneratorImpl::EmitVariable(std::ostream& out, const ast::Variable* var) {
return true;
}
-bool GeneratorImpl::EmitAttributes(std::ostream& out, const ast::AttributeList& attrs) {
+bool GeneratorImpl::EmitAttributes(std::ostream& out,
+ utils::VectorRef<const ast::Attribute*> attrs) {
bool first = true;
for (auto* attr : attrs) {
if (!first) {
@@ -696,7 +722,7 @@ bool GeneratorImpl::EmitAttributes(std::ostream& out, const ast::AttributeList&
[&](const ast::WorkgroupAttribute* workgroup) {
auto values = workgroup->Values();
out << "workgroup_size(";
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (values[i]) {
if (i > 0) {
out << ", ";
@@ -919,7 +945,9 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
[&](const ast::IncrementDecrementStatement* l) { return EmitIncrementDecrement(l); },
[&](const ast::LoopStatement* l) { return EmitLoop(l); },
[&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
+ [&](const ast::WhileStatement* l) { return EmitWhile(l); },
[&](const ast::ReturnStatement* r) { return EmitReturn(r); },
+ [&](const ast::StaticAssert* s) { return EmitStaticAssert(s); },
[&](const ast::SwitchStatement* s) { return EmitSwitch(s); },
[&](const ast::VariableDeclStatement* v) { return EmitVariable(line(), v->variable); },
[&](Default) {
@@ -929,7 +957,7 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
});
}
-bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatements(utils::VectorRef<const ast::Statement*> stmts) {
for (auto* s : stmts) {
if (!EmitStatement(s)) {
return false;
@@ -938,7 +966,7 @@ bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
return true;
}
-bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
+bool GeneratorImpl::EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts) {
ScopedIndent si(this);
return EmitStatements(stmts);
}
@@ -1181,6 +1209,30 @@ bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
return true;
}
+bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
+ {
+ auto out = line();
+ out << "while";
+ {
+ ScopedParen sp(out);
+
+ auto* cond = stmt->condition;
+ if (!EmitExpression(out, cond)) {
+ return false;
+ }
+ }
+ out << " {";
+ }
+
+ if (!EmitStatementsWithIndent(stmt->body->statements)) {
+ return false;
+ }
+
+ line() << "}";
+
+ return true;
+}
+
bool GeneratorImpl::EmitReturn(const ast::ReturnStatement* stmt) {
auto out = line();
out << "return";
@@ -1194,6 +1246,16 @@ bool GeneratorImpl::EmitReturn(const ast::ReturnStatement* stmt) {
return true;
}
+bool GeneratorImpl::EmitStaticAssert(const ast::StaticAssert* stmt) {
+ auto out = line();
+ out << "static_assert ";
+ if (!EmitExpression(out, stmt->condition)) {
+ return false;
+ }
+ out << ";";
+ return true;
+}
+
bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
{
auto out = line();
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.h b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.h
index a17e2da70fb..f4fc4678c97 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.h
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl.h
@@ -152,6 +152,10 @@ class GeneratorImpl : public TextGenerator {
/// @param stmt the statement to emit
/// @returns true if the statement was emtited
bool EmitForLoop(const ast::ForLoopStatement* stmt);
+ /// Handles a while statement
+ /// @param stmt the statement to emit
+ /// @returns true if the statement was emtited
+ bool EmitWhile(const ast::WhileStatement* stmt);
/// Handles a member accessor expression
/// @param out the output of the expression stream
/// @param expr the member accessor expression
@@ -161,6 +165,10 @@ class GeneratorImpl : public TextGenerator {
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
bool EmitReturn(const ast::ReturnStatement* stmt);
+ /// Handles static assertion statements
+ /// @param stmt the statement to emit
+ /// @returns true if the statement was successfully emitted
+ bool EmitStaticAssert(const ast::StaticAssert* stmt);
/// Handles statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
@@ -168,11 +176,11 @@ class GeneratorImpl : public TextGenerator {
/// Handles a statement list
/// @param stmts the statements to emit
/// @returns true if the statements were emitted
- bool EmitStatements(const ast::StatementList& stmts);
+ bool EmitStatements(utils::VectorRef<const ast::Statement*> stmts);
/// Handles a statement list with an increased indentation
/// @param stmts the statements to emit
/// @returns true if the statements were emitted
- bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+ bool EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts);
/// Handles generating a switch statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
@@ -210,7 +218,7 @@ class GeneratorImpl : public TextGenerator {
/// @param out the output of the expression stream
/// @param attrs the attribute list
/// @returns true if the attributes were emitted
- bool EmitAttributes(std::ostream& out, const ast::AttributeList& attrs);
+ bool EmitAttributes(std::ostream& out, utils::VectorRef<const ast::Attribute*> attrs);
};
} // namespace tint::writer::wgsl
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_alias_type_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_alias_type_test.cc
index 92a6868f794..dd0584d0053 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_alias_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_alias_type_test.cc
@@ -30,7 +30,7 @@ TEST_F(WgslGeneratorImplTest, EmitAlias_F32) {
}
TEST_F(WgslGeneratorImplTest, EmitTypeDecl_Struct) {
- auto* s = Structure("A", {
+ auto* s = Structure("A", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.i32()),
});
@@ -50,7 +50,7 @@ type B = A;
}
TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) {
- auto* s = Structure("A", {
+ auto* s = Structure("A", utils::Vector{
Member("a", ty.f32()),
Member("b", ty.i32()),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
index 2b4e8b43346..d5f7f9fcb57 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
@@ -22,7 +22,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, IndexAccessor) {
- Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+ GlobalVar("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
auto* expr = IndexAccessor("ary", 5_i);
WrapInFunction(expr);
@@ -34,7 +34,7 @@ TEST_F(WgslGeneratorImplTest, IndexAccessor) {
}
TEST_F(WgslGeneratorImplTest, IndexAccessor_OfDref) {
- Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+ GlobalVar("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
auto* p = Let("p", nullptr, AddressOf("ary"));
auto* expr = IndexAccessor(Deref("p"), 5_i);
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_assign_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_assign_test.cc
index 8d5e75efa1d..e390d2f300d 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_assign_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_assign_test.cc
@@ -20,8 +20,8 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, Emit_Assign) {
- auto* lhs = Global("lhs", ty.i32(), ast::StorageClass::kPrivate);
- auto* rhs = Global("rhs", ty.i32(), ast::StorageClass::kPrivate);
+ auto* lhs = GlobalVar("lhs", ty.i32(), ast::StorageClass::kPrivate);
+ auto* rhs = GlobalVar("rhs", ty.i32(), ast::StorageClass::kPrivate);
auto* assign = Assign(lhs, rhs);
WrapInFunction(assign);
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_binary_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_binary_test.cc
index acc41807551..682c0017225 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_binary_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_binary_test.cc
@@ -37,8 +37,8 @@ TEST_P(WgslBinaryTest, Emit) {
}
};
- Global("left", op_ty(), ast::StorageClass::kPrivate);
- Global("right", op_ty(), ast::StorageClass::kPrivate);
+ GlobalVar("left", op_ty(), ast::StorageClass::kPrivate);
+ GlobalVar("right", op_ty(), ast::StorageClass::kPrivate);
auto* left = Expr("left");
auto* right = Expr("right");
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_call_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_call_test.cc
index 6a7e0774369..4746be20309 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_call_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_call_test.cc
@@ -23,7 +23,10 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithoutParams) {
- Func("my_func", {}, ty.f32(), {Return(1.23_f)});
+ Func("my_func", utils::Empty, ty.f32(),
+ utils::Vector{
+ Return(1.23_f),
+ });
auto* call = Call("my_func");
WrapInFunction(call);
@@ -37,13 +40,16 @@ TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithoutParams) {
TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithParams) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.f32(), {Return(1.23_f)});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.f32(),
+ utils::Vector{
+ Return(1.23_f),
+ });
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = Call("my_func", "param1", "param2");
WrapInFunction(call);
@@ -57,13 +63,13 @@ TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithParams) {
TEST_F(WgslGeneratorImplTest, EmitStatement_Call) {
Func("my_func",
- {
+ utils::Vector{
Param(Sym(), ty.f32()),
Param(Sym(), ty.f32()),
},
- ty.void_(), ast::StatementList{}, ast::AttributeList{});
- Global("param1", ty.f32(), ast::StorageClass::kPrivate);
- Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+ ty.void_(), utils::Empty, utils::Empty);
+ GlobalVar("param1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("param2", ty.f32(), ast::StorageClass::kPrivate);
auto* call = Call("my_func", "param1", "param2");
auto* stmt = CallStmt(call);
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_case_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_case_test.cc
index c12997e3ec6..6d59970ff7d 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_case_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_case_test.cc
@@ -37,7 +37,13 @@ TEST_F(WgslGeneratorImplTest, Emit_Case) {
}
TEST_F(WgslGeneratorImplTest, Emit_Case_MultipleSelectors) {
- auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+ auto* s = Switch(1_i,
+ Case(
+ utils::Vector{
+ Expr(5_i),
+ Expr(6_i),
+ },
+ Block(create<ast::BreakStatement>())),
DefaultCase());
WrapInFunction(s);
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_cast_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_cast_test.cc
index c423943e40f..9b9379b34e5 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_cast_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_cast_test.cc
@@ -21,7 +21,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
-TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar) {
+TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar_F32_From_I32) {
auto* cast = Construct<f32>(1_i);
WrapInFunction(cast);
@@ -32,7 +32,20 @@ TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar) {
EXPECT_EQ(out.str(), "f32(1i)");
}
-TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector) {
+TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar_F16_From_I32) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = Construct<f16>(1_i);
+ WrapInFunction(cast);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+ EXPECT_EQ(out.str(), "f16(1i)");
+}
+
+TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector_F32_From_I32) {
auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
WrapInFunction(cast);
@@ -43,5 +56,18 @@ TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector) {
EXPECT_EQ(out.str(), "vec3<f32>(vec3<i32>(1i, 2i, 3i))");
}
+TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector_F16_From_I32) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec3<i32>(1_i, 2_i, 3_i));
+ WrapInFunction(cast);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+ EXPECT_EQ(out.str(), "vec3<f16>(vec3<i32>(1i, 2i, 3i))");
+}
+
} // namespace
} // namespace tint::writer::wgsl
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_constructor_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_constructor_test.cc
index ae9f2b74f6d..40bf393b289 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_constructor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_constructor_test.cc
@@ -51,7 +51,7 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_UInt) {
EXPECT_THAT(gen.result(), HasSubstr("56779u"));
}
-TEST_F(WgslGeneratorImplTest, EmitConstructor_Float) {
+TEST_F(WgslGeneratorImplTest, EmitConstructor_F32) {
// Use a number close to 1<<30 but whose decimal representation ends in 0.
WrapInFunction(Expr(f32((1 << 30) - 4)));
@@ -61,7 +61,19 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Float) {
EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
}
-TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Float) {
+TEST_F(WgslGeneratorImplTest, EmitConstructor_F16) {
+ Enable(ast::Extension::kF16);
+
+ // Use a number close to 1<<16 but whose decimal representation ends in 0.
+ WrapInFunction(Expr(f16((1 << 15) - 8)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("32752.0h"));
+}
+
+TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_F32) {
WrapInFunction(Construct<f32>(Expr(-1.2e-5_f)));
GeneratorImpl& gen = Build();
@@ -70,6 +82,17 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Float) {
EXPECT_THAT(gen.result(), HasSubstr("f32(-0.000012f)"));
}
+TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(Construct<f16>(Expr(-1.2e-5_h)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("f16(-1.19805336e-05h)"));
+}
+
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Bool) {
WrapInFunction(Construct<bool>(true));
@@ -97,7 +120,7 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Uint) {
EXPECT_THAT(gen.result(), HasSubstr("u32(12345u)"));
}
-TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec) {
+TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec_F32) {
WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
GeneratorImpl& gen = Build();
@@ -106,7 +129,18 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec) {
EXPECT_THAT(gen.result(), HasSubstr("vec3<f32>(1.0f, 2.0f, 3.0f)"));
}
-TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat) {
+TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("vec3<f16>(1.0h, 2.0h, 3.0h)"));
+}
+
+TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat_F32) {
WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
GeneratorImpl& gen = Build();
@@ -116,6 +150,18 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat) {
"vec3<f32>(3.0f, 4.0f, 5.0f))"));
}
+TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat_F16) {
+ Enable(ast::Extension::kF16);
+
+ WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(), HasSubstr("mat2x3<f16>(vec3<f16>(1.0h, 2.0h, 3.0h), "
+ "vec3<f16>(3.0h, 4.0h, 5.0h))"));
+}
+
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Array) {
WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
@@ -128,5 +174,17 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Array) {
"vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f))"));
}
+TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_ImplicitArray) {
+ WrapInFunction(Construct(ty.array(nullptr, nullptr), vec3<f32>(1_f, 2_f, 3_f),
+ vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_THAT(gen.result(),
+ HasSubstr("array(vec3<f32>(1.0f, 2.0f, 3.0f), "
+ "vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f))"));
+}
+
} // namespace
} // namespace tint::writer::wgsl
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_function_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_function_test.cc
index e34292bb157..9e9c3a3666f 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_function_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_function_test.cc
@@ -25,11 +25,10 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, Emit_Function) {
- auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ auto* func = Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
Return(),
- },
- ast::AttributeList{});
+ });
GeneratorImpl& gen = Build();
@@ -43,12 +42,15 @@ TEST_F(WgslGeneratorImplTest, Emit_Function) {
}
TEST_F(WgslGeneratorImplTest, Emit_Function_WithParams) {
- auto* func =
- Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())}, ty.void_(),
- ast::StatementList{
- Return(),
- },
- ast::AttributeList{});
+ auto* func = Func("my_func",
+ utils::Vector{
+ Param("a", ty.f32()),
+ Param("b", ty.i32()),
+ },
+ ty.void_(),
+ utils::Vector{
+ Return(),
+ });
GeneratorImpl& gen = Build();
@@ -62,8 +64,11 @@ TEST_F(WgslGeneratorImplTest, Emit_Function_WithParams) {
}
TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize) {
- auto* func = Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{Return()},
- ast::AttributeList{
+ auto* func = Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(2_i, 4_i, 6_i),
});
@@ -82,8 +87,11 @@ TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize) {
TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize_WithIdent) {
GlobalConst("height", ty.i32(), Expr(2_i));
- auto* func = Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{Return()},
- ast::AttributeList{
+ auto* func = Func("my_func", utils::Empty, ty.void_(),
+ utils::Vector{
+ Return(),
+ },
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(2_i, "height"),
});
@@ -102,10 +110,16 @@ TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize_WithIden
TEST_F(WgslGeneratorImplTest, Emit_Function_EntryPoint_Parameters) {
auto* vec4 = ty.vec4<f32>();
- auto* coord = Param("coord", vec4, {Builtin(ast::Builtin::kPosition)});
- auto* loc1 = Param("loc1", ty.f32(), {Location(1u)});
- auto* func = Func("frag_main", ast::VariableList{coord, loc1}, ty.void_(), ast::StatementList{},
- ast::AttributeList{
+ auto* coord = Param("coord", vec4,
+ utils::Vector{
+ Builtin(ast::BuiltinValue::kPosition),
+ });
+ auto* loc1 = Param("loc1", ty.f32(),
+ utils::Vector{
+ Location(1u),
+ });
+ auto* func = Func("frag_main", utils::Vector{coord, loc1}, ty.void_(), utils::Empty,
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
@@ -121,14 +135,14 @@ TEST_F(WgslGeneratorImplTest, Emit_Function_EntryPoint_Parameters) {
}
TEST_F(WgslGeneratorImplTest, Emit_Function_EntryPoint_ReturnValue) {
- auto* func = Func("frag_main", ast::VariableList{}, ty.f32(),
- ast::StatementList{
+ auto* func = Func("frag_main", utils::Empty, ty.f32(),
+ utils::Vector{
Return(1_f),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kFragment),
},
- ast::AttributeList{
+ utils::Vector{
Location(1u),
});
@@ -161,23 +175,25 @@ TEST_F(WgslGeneratorImplTest, Emit_Function_Multiple_EntryPoint_With_Same_Module
// return;
// }
- auto* s = Structure("Data", {Member("d", ty.f32())});
+ auto* s = Structure("Data", utils::Vector{
+ Member("d", ty.f32()),
+ });
- Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ GlobalVar("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("a", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("a", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -186,12 +202,12 @@ TEST_F(WgslGeneratorImplTest, Emit_Function_Multiple_EntryPoint_With_Same_Module
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
- Func("b", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("b", utils::Empty, ty.void_(),
+ utils::Vector{
Decl(var),
Return(),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_global_decl_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
index 48f1276790c..04f520ac299 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
@@ -28,7 +28,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalDeclAfterFunction) {
auto* func_var = Var("a", ty.f32());
WrapInFunction(func_var);
- Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -45,27 +45,31 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalDeclAfterFunction) {
}
TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
- Global("a0", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a0", ty.f32(), ast::StorageClass::kPrivate);
- auto* s0 = Structure("S0", {Member("a", ty.i32())});
+ auto* s0 = Structure("S0", utils::Vector{
+ Member("a", ty.i32()),
+ });
- Func("func", ast::VariableList{}, ty.f32(),
- ast::StatementList{
+ Func("func", {}, ty.f32(),
+ utils::Vector{
Return("a0"),
},
- ast::AttributeList{});
+ utils::Empty);
- Global("a1", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("a1", ty.f32(), ast::StorageClass::kPrivate);
- auto* s1 = Structure("S1", {Member("a", ty.i32())});
+ auto* s1 = Structure("S1", utils::Vector{
+ Member("a", ty.i32()),
+ });
- Func("main", ast::VariableList{}, ty.void_(),
- ast::StatementList{
+ Func("main", {}, ty.void_(),
+ utils::Vector{
Decl(Var("s0", ty.Of(s0))),
Decl(Var("s1", ty.Of(s1))),
Assign("a1", Call("func")),
},
- ast::AttributeList{
+ utils::Vector{
Stage(ast::PipelineStage::kCompute),
WorkgroupSize(1_i),
});
@@ -101,11 +105,11 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
}
TEST_F(WgslGeneratorImplTest, Emit_Global_Sampler) {
- Global("s", ty.sampler(ast::SamplerKind::kSampler),
- ast::AttributeList{
- create<ast::GroupAttribute>(0),
- create<ast::BindingAttribute>(0),
- });
+ GlobalVar("s", ty.sampler(ast::SamplerKind::kSampler),
+ utils::Vector{
+ create<ast::GroupAttribute>(0u),
+ create<ast::BindingAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -117,11 +121,11 @@ TEST_F(WgslGeneratorImplTest, Emit_Global_Sampler) {
TEST_F(WgslGeneratorImplTest, Emit_Global_Texture) {
auto* st = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
- Global("t", st,
- ast::AttributeList{
- create<ast::GroupAttribute>(0),
- create<ast::BindingAttribute>(0),
- });
+ GlobalVar("t", st,
+ utils::Vector{
+ create<ast::GroupAttribute>(0u),
+ create<ast::BindingAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -131,9 +135,27 @@ TEST_F(WgslGeneratorImplTest, Emit_Global_Texture) {
EXPECT_EQ(gen.result(), " @group(0) @binding(0) var t : texture_1d<f32>;\n");
}
+TEST_F(WgslGeneratorImplTest, Emit_GlobalConst) {
+ GlobalConst("explicit", ty.f32(), Expr(1_f));
+ GlobalConst("inferred", nullptr, Expr(1_f));
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"( const explicit : f32 = 1.0f;
+
+ const inferred = 1.0f;
+)");
+}
+
TEST_F(WgslGeneratorImplTest, Emit_OverridableConstants) {
Override("a", ty.f32(), nullptr);
- Override("b", ty.f32(), nullptr, {Id(7u)});
+ Override("b", ty.f32(), nullptr,
+ utils::Vector{
+ Id(7u),
+ });
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_identifier_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_identifier_test.cc
index c6bccf671a7..2e20d4c71a3 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_identifier_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_identifier_test.cc
@@ -20,7 +20,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_Single) {
- Global("glsl", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("glsl", ty.f32(), ast::StorageClass::kPrivate);
auto* i = Expr("glsl");
WrapInFunction(i);
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_if_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_if_test.cc
index 18c0ffddc46..88f6aba0530 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_if_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_if_test.cc
@@ -20,7 +20,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, Emit_If) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* cond = Expr("cond");
auto* body = Block(Return());
@@ -39,8 +39,8 @@ TEST_F(WgslGeneratorImplTest, Emit_If) {
}
TEST_F(WgslGeneratorImplTest, Emit_IfWithElseIf) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
- Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_cond = Expr("else_cond");
auto* else_body = Block(Return());
@@ -64,7 +64,7 @@ TEST_F(WgslGeneratorImplTest, Emit_IfWithElseIf) {
}
TEST_F(WgslGeneratorImplTest, Emit_IfWithElse) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_body = Block(Return());
@@ -87,8 +87,8 @@ TEST_F(WgslGeneratorImplTest, Emit_IfWithElse) {
}
TEST_F(WgslGeneratorImplTest, Emit_IfWithMultiple) {
- Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
- Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
auto* else_cond = Expr("else_cond");
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_literal_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_literal_test.cc
index dd715d4fbe4..f33bd0ec69a 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_literal_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_literal_test.cc
@@ -25,7 +25,7 @@ namespace {
// - 0 sign if sign is 0, 1 otherwise
// - 'exponent_bits' is placed in the exponent space.
// So, the exponent bias must already be included.
-f32 MakeFloat(int sign, int biased_exponent, int mantissa) {
+f32 MakeF32(uint32_t sign, uint32_t biased_exponent, uint32_t mantissa) {
const uint32_t sign_bit = sign ? 0x80000000u : 0u;
// The binary32 exponent is 8 bits, just below the sign.
const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
@@ -40,18 +40,75 @@ f32 MakeFloat(int sign, int biased_exponent, int mantissa) {
return f32(result);
}
-struct FloatData {
+// Get the representation of an IEEE 754 binary16 floating point number with
+// - 0 sign if sign is 0, 1 otherwise
+// - 'exponent_bits' is placed in the exponent space.
+// - the exponent bias (15) already be included.
+f16 MakeF16(uint32_t sign, uint32_t f16_biased_exponent, uint16_t f16_mantissa) {
+ assert((f16_biased_exponent & 0xffffffe0u) == 0);
+ assert((f16_mantissa & 0xfc00u) == 0);
+
+ const uint32_t sign_bit = sign ? 0x80000000u : 0u;
+
+ // F16 has a exponent bias of 15, and f32 bias 127. Adding 127-15=112 to the f16-biased exponent
+ // to get f32-biased exponent.
+ uint32_t f32_biased_exponent = (f16_biased_exponent & 0x1fu) + 112;
+ assert((f32_biased_exponent & 0xffffff00u) == 0);
+
+ if (f16_biased_exponent == 0) {
+ // +/- zero, or subnormal
+ if (f16_mantissa == 0) {
+ // +/- zero
+ return sign ? f16(-0.0f) : f16(0.0f);
+ }
+ // Subnormal f16, calc the corresponding exponent and mantissa of normal f32.
+ f32_biased_exponent += 1;
+ // There must be at least one of the 10 mantissa bits being 1, left-shift the mantissa bits
+ // until the most significant 1 bit is left-shifted to 10th bit (count from zero), which
+ // will be omitted in the resulting f32 mantissa part.
+ assert(f16_mantissa & 0x03ffu);
+ while ((f16_mantissa & 0x0400u) == 0) {
+ f16_mantissa = static_cast<uint16_t>(f16_mantissa << 1);
+ f32_biased_exponent--;
+ }
+ }
+
+ // The binary32 exponent is 8 bits, just below the sign.
+ const uint32_t f32_exponent_bits = (f32_biased_exponent & 0xffu) << 23;
+ // The mantissa is the bottom 23 bits.
+ const uint32_t f32_mantissa_bits = (f16_mantissa & 0x03ffu) << 13;
+
+ uint32_t bits = sign_bit | f32_exponent_bits | f32_mantissa_bits;
+ float result = 0.0f;
+ static_assert(sizeof(result) == sizeof(bits),
+ "expected float and uint32_t to be the same size");
+ std::memcpy(&result, &bits, sizeof(bits));
+ return f16(result);
+}
+
+struct F32Data {
f32 value;
std::string expected;
};
-inline std::ostream& operator<<(std::ostream& out, FloatData data) {
+
+struct F16Data {
+ f16 value;
+ std::string expected;
+};
+
+inline std::ostream& operator<<(std::ostream& out, F32Data data) {
+ out << "{" << data.value << "," << data.expected << "}";
+ return out;
+}
+
+inline std::ostream& operator<<(std::ostream& out, F16Data data) {
out << "{" << data.value << "," << data.expected << "}";
return out;
}
-using WgslGenerator_FloatLiteralTest = TestParamHelper<FloatData>;
+using WgslGenerator_F32LiteralTest = TestParamHelper<F32Data>;
-TEST_P(WgslGenerator_FloatLiteralTest, Emit) {
+TEST_P(WgslGenerator_F32LiteralTest, Emit) {
auto* v = Expr(GetParam().value);
SetResolveOnBuild(false);
@@ -63,38 +120,37 @@ TEST_P(WgslGenerator_FloatLiteralTest, Emit) {
}
INSTANTIATE_TEST_SUITE_P(Zero,
- WgslGenerator_FloatLiteralTest,
- ::testing::ValuesIn(std::vector<FloatData>{
- {0_f, "0.0f"},
- {MakeFloat(0, 0, 0), "0.0f"},
- {MakeFloat(1, 0, 0), "-0.0f"}}));
+ WgslGenerator_F32LiteralTest,
+ ::testing::ValuesIn(std::vector<F32Data>{{0_f, "0.0f"},
+ {MakeF32(0, 0, 0), "0.0f"},
+ {MakeF32(1, 0, 0), "-0.0f"}}));
INSTANTIATE_TEST_SUITE_P(Normal,
- WgslGenerator_FloatLiteralTest,
- ::testing::ValuesIn(std::vector<FloatData>{{1_f, "1.0f"},
- {-1_f, "-1.0f"},
- {101.375_f, "101.375f"}}));
+ WgslGenerator_F32LiteralTest,
+ ::testing::ValuesIn(std::vector<F32Data>{{1_f, "1.0f"},
+ {-1_f, "-1.0f"},
+ {101.375_f, "101.375f"}}));
INSTANTIATE_TEST_SUITE_P(Subnormal,
- WgslGenerator_FloatLiteralTest,
- ::testing::ValuesIn(std::vector<FloatData>{
- {MakeFloat(0, 0, 1), "0x1p-149f"}, // Smallest
- {MakeFloat(1, 0, 1), "-0x1p-149f"},
- {MakeFloat(0, 0, 2), "0x1p-148f"},
- {MakeFloat(1, 0, 2), "-0x1p-148f"},
- {MakeFloat(0, 0, 0x7fffff), "0x1.fffffcp-127f"}, // Largest
- {MakeFloat(1, 0, 0x7fffff), "-0x1.fffffcp-127f"}, // Largest
- {MakeFloat(0, 0, 0xcafebe), "0x1.2bfaf8p-127f"}, // Scattered bits
- {MakeFloat(1, 0, 0xcafebe), "-0x1.2bfaf8p-127f"}, // Scattered bits
- {MakeFloat(0, 0, 0xaaaaa), "0x1.55554p-130f"}, // Scattered bits
- {MakeFloat(1, 0, 0xaaaaa), "-0x1.55554p-130f"}, // Scattered bits
+ WgslGenerator_F32LiteralTest,
+ ::testing::ValuesIn(std::vector<F32Data>{
+ {MakeF32(0, 0, 1), "0x1p-149f"}, // Smallest
+ {MakeF32(1, 0, 1), "-0x1p-149f"},
+ {MakeF32(0, 0, 2), "0x1p-148f"},
+ {MakeF32(1, 0, 2), "-0x1p-148f"},
+ {MakeF32(0, 0, 0x7fffff), "0x1.fffffcp-127f"}, // Largest
+ {MakeF32(1, 0, 0x7fffff), "-0x1.fffffcp-127f"}, // Largest
+ {MakeF32(0, 0, 0xcafebe), "0x1.2bfaf8p-127f"}, // Scattered bits
+ {MakeF32(1, 0, 0xcafebe), "-0x1.2bfaf8p-127f"}, // Scattered bits
+ {MakeF32(0, 0, 0xaaaaa), "0x1.55554p-130f"}, // Scattered bits
+ {MakeF32(1, 0, 0xaaaaa), "-0x1.55554p-130f"}, // Scattered bits
}));
INSTANTIATE_TEST_SUITE_P(Infinity,
- WgslGenerator_FloatLiteralTest,
- ::testing::ValuesIn(std::vector<FloatData>{
- {MakeFloat(0, 255, 0), "0x1p+128f"},
- {MakeFloat(1, 255, 0), "-0x1p+128f"}}));
+ WgslGenerator_F32LiteralTest,
+ ::testing::ValuesIn(std::vector<F32Data>{
+ {MakeF32(0, 255, 0), "0x1p+128f"},
+ {MakeF32(1, 255, 0), "-0x1p+128f"}}));
INSTANTIATE_TEST_SUITE_P(
// TODO(dneto): It's unclear how Infinity and NaN should be handled.
@@ -106,23 +162,95 @@ INSTANTIATE_TEST_SUITE_P(
// whether the NaN is signalling or quiet, but no agreement between
// different machine architectures on whether 1 means signalling or
// if 1 means quiet.
- WgslGenerator_FloatLiteralTest,
- ::testing::ValuesIn(std::vector<FloatData>{
+ WgslGenerator_F32LiteralTest,
+ ::testing::ValuesIn(std::vector<F32Data>{
+ // LSB only. Smallest mantissa.
+ {MakeF32(0, 255, 1), "0x1.000002p+128f"}, // Smallest mantissa
+ {MakeF32(1, 255, 1), "-0x1.000002p+128f"},
+ // MSB only.
+ {MakeF32(0, 255, 0x400000), "0x1.8p+128f"},
+ {MakeF32(1, 255, 0x400000), "-0x1.8p+128f"},
+ // All 1s in the mantissa.
+ {MakeF32(0, 255, 0x7fffff), "0x1.fffffep+128f"},
+ {MakeF32(1, 255, 0x7fffff), "-0x1.fffffep+128f"},
+ // Scattered bits, with 0 in top mantissa bit.
+ {MakeF32(0, 255, 0x20101f), "0x1.40203ep+128f"},
+ {MakeF32(1, 255, 0x20101f), "-0x1.40203ep+128f"},
+ // Scattered bits, with 1 in top mantissa bit.
+ {MakeF32(0, 255, 0x40101f), "0x1.80203ep+128f"},
+ {MakeF32(1, 255, 0x40101f), "-0x1.80203ep+128f"}}));
+
+using WgslGenerator_F16LiteralTest = TestParamHelper<F16Data>;
+
+TEST_P(WgslGenerator_F16LiteralTest, Emit) {
+ Enable(ast::Extension::kF16);
+
+ auto* v = Expr(GetParam().value);
+
+ SetResolveOnBuild(false);
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitLiteral(out, v)) << gen.error();
+ EXPECT_EQ(out.str(), GetParam().expected);
+}
+
+INSTANTIATE_TEST_SUITE_P(Zero,
+ WgslGenerator_F16LiteralTest,
+ ::testing::ValuesIn(std::vector<F16Data>{{0_h, "0.0h"},
+ {MakeF16(0, 0, 0), "0.0h"},
+ {MakeF16(1, 0, 0), "-0.0h"}}));
+
+INSTANTIATE_TEST_SUITE_P(Normal,
+ WgslGenerator_F16LiteralTest,
+ ::testing::ValuesIn(std::vector<F16Data>{{1_h, "1.0h"},
+ {-1_h, "-1.0h"},
+ {101.375_h, "101.375h"}}));
+
+INSTANTIATE_TEST_SUITE_P(Subnormal,
+ WgslGenerator_F16LiteralTest,
+ ::testing::ValuesIn(std::vector<F16Data>{
+ {MakeF16(0, 0, 1), "5.96046448e-08h"}, // Smallest
+ {MakeF16(1, 0, 1), "-5.96046448e-08h"},
+ {MakeF16(0, 0, 2), "1.1920929e-07h"},
+ {MakeF16(1, 0, 2), "-1.1920929e-07h"},
+ {MakeF16(0, 0, 0x3ffu), "6.09755516e-05h"}, // Largest
+ {MakeF16(1, 0, 0x3ffu), "-6.09755516e-05h"}, // Largest
+ {MakeF16(0, 0, 0x3afu), "5.620718e-05h"}, // Scattered bits
+ {MakeF16(1, 0, 0x3afu), "-5.620718e-05h"}, // Scattered bits
+ {MakeF16(0, 0, 0x2c7u), "4.23789024e-05h"}, // Scattered bits
+ {MakeF16(1, 0, 0x2c7u), "-4.23789024e-05h"}, // Scattered bits
+ }));
+
+INSTANTIATE_TEST_SUITE_P(
+ // Currently Inf is impossible to be spelled out in literal.
+ // https://github.com/gpuweb/gpuweb/issues/1769
+ DISABLED_Infinity,
+ WgslGenerator_F16LiteralTest,
+ ::testing::ValuesIn(std::vector<F16Data>{{MakeF16(0, 31, 0), "0x1p+128h"},
+ {MakeF16(1, 31, 0), "-0x1p+128h"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+ // Currently NaN is impossible to be spelled out in literal.
+ // https://github.com/gpuweb/gpuweb/issues/1769
+ DISABLED_NaN,
+ WgslGenerator_F16LiteralTest,
+ ::testing::ValuesIn(std::vector<F16Data>{
// LSB only. Smallest mantissa.
- {MakeFloat(0, 255, 1), "0x1.000002p+128f"}, // Smallest mantissa
- {MakeFloat(1, 255, 1), "-0x1.000002p+128f"},
+ {MakeF16(0, 31, 1), "0x1.004p+128h"}, // Smallest mantissa
+ {MakeF16(1, 31, 1), "-0x1.004p+128h"},
// MSB only.
- {MakeFloat(0, 255, 0x400000), "0x1.8p+128f"},
- {MakeFloat(1, 255, 0x400000), "-0x1.8p+128f"},
+ {MakeF16(0, 31, 0x200u), "0x1.8p+128h"},
+ {MakeF16(1, 31, 0x200u), "-0x1.8p+128h"},
// All 1s in the mantissa.
- {MakeFloat(0, 255, 0x7fffff), "0x1.fffffep+128f"},
- {MakeFloat(1, 255, 0x7fffff), "-0x1.fffffep+128f"},
+ {MakeF16(0, 31, 0x3ffu), "0x1.ffcp+128h"},
+ {MakeF16(1, 31, 0x3ffu), "-0x1.ffcp+128h"},
// Scattered bits, with 0 in top mantissa bit.
- {MakeFloat(0, 255, 0x20101f), "0x1.40203ep+128f"},
- {MakeFloat(1, 255, 0x20101f), "-0x1.40203ep+128f"},
+ {MakeF16(0, 31, 0x11fu), "0x1.47cp+128h"},
+ {MakeF16(1, 31, 0x11fu), "-0x1.47cp+128h"},
// Scattered bits, with 1 in top mantissa bit.
- {MakeFloat(0, 255, 0x40101f), "0x1.80203ep+128f"},
- {MakeFloat(1, 255, 0x40101f), "-0x1.80203ep+128f"}}));
+ {MakeF16(0, 31, 0x23fu), "0x1.8fcp+128h"},
+ {MakeF16(1, 31, 0x23fu), "-0x1.8fcp+128h"}}));
} // namespace
} // namespace tint::writer::wgsl
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_loop_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_loop_test.cc
index 2d6a8f4a7af..3570957dd37 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_loop_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_loop_test.cc
@@ -68,7 +68,7 @@ TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithMultiStmtInit) {
// for({ignore(1i); ignore(2i);}; ; ) {
// return;
// }
- Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
auto* multi_stmt = Block(Ignore(1_i), Ignore(2_i));
auto* f = For(multi_stmt, nullptr, nullptr, Block(Return()));
WrapInFunction(f);
@@ -132,7 +132,7 @@ TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithMultiStmtCont) {
// return;
// }
- Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
auto* multi_stmt = Block(Ignore(1_i), Ignore(2_i));
auto* f = For(nullptr, nullptr, multi_stmt, Block(Return()));
WrapInFunction(f);
@@ -175,7 +175,7 @@ TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithMultiStmtInitCondCont) {
// for({ ignore(1i); ignore(2i); }; true; { ignore(3i); ignore(4i); }) {
// return;
// }
- Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+ GlobalVar("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
auto* multi_stmt_a = Block(Ignore(1_i), Ignore(2_i));
auto* multi_stmt_b = Block(Ignore(3_i), Ignore(4_i));
auto* f = For(multi_stmt_a, Expr(true), multi_stmt_b, Block(Return()));
@@ -198,5 +198,64 @@ TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithMultiStmtInitCondCont) {
)");
}
+TEST_F(WgslGeneratorImplTest, Emit_While) {
+ // while(true) {
+ // return;
+ // }
+
+ auto* f = While(Expr(true), Block(Return()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while(true) {
+ return;
+ }
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_While_WithContinue) {
+ // while(true) {
+ // continue;
+ // }
+
+ auto* f = While(Expr(true), Block(Continue()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while(true) {
+ continue;
+ }
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_WhileMultiCond) {
+ // while(true && false) {
+ // return;
+ // }
+
+ auto* multi_stmt =
+ create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+ auto* f = While(multi_stmt, Block(Return()));
+ WrapInFunction(f);
+
+ GeneratorImpl& gen = Build();
+
+ gen.increment_indent();
+
+ ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+ EXPECT_EQ(gen.result(), R"( while((true && false)) {
+ return;
+ }
+)");
+}
+
} // namespace
} // namespace tint::writer::wgsl
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
index d8bd3495f13..7386cd08515 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
@@ -20,8 +20,8 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
- auto* s = Structure("Data", {Member("mem", ty.f32())});
- Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+ auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
+ GlobalVar("str", ty.Of(s), ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("str", "mem");
WrapInFunction(expr);
@@ -34,8 +34,8 @@ TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
}
TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor_OfDref) {
- auto* s = Structure("Data", {Member("mem", ty.f32())});
- Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+ auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
+ GlobalVar("str", ty.Of(s), ast::StorageClass::kPrivate);
auto* p = Let("p", nullptr, AddressOf("str"));
auto* expr = MemberAccessor(Deref("p"), "mem");
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_return_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_return_test.cc
index ed1027d63b4..fbbf9ded648 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_return_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_return_test.cc
@@ -35,7 +35,7 @@ TEST_F(WgslGeneratorImplTest, Emit_Return) {
TEST_F(WgslGeneratorImplTest, Emit_ReturnWithValue) {
auto* r = Return(123_i);
- Func("f", {}, ty.i32(), {r});
+ Func("f", utils::Empty, ty.i32(), utils::Vector{r});
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_static_assert_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_static_assert_test.cc
new file mode 100644
index 00000000000..9e7a1c013ac
--- /dev/null
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_static_assert_test.cc
@@ -0,0 +1,47 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/writer/wgsl/test_helper.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::writer::wgsl {
+namespace {
+
+using WgslGeneratorImplTest = TestHelper;
+
+TEST_F(WgslGeneratorImplTest, Emit_GlobalStaticAssert) {
+ GlobalStaticAssert(true);
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(static_assert true;
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_FunctionStaticAssert) {
+ Func("f", utils::Empty, ty.void_(), utils::Vector{StaticAssert(true)});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ static_assert true;
+}
+)");
+}
+
+} // namespace
+} // namespace tint::writer::wgsl
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_switch_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_switch_test.cc
index 11424f0f83b..491660e2da0 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_switch_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_switch_test.cc
@@ -22,21 +22,21 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, Emit_Switch) {
- Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("cond", ty.i32(), ast::StorageClass::kPrivate);
auto* def_body = Block(create<ast::BreakStatement>());
- auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
+ auto* def = create<ast::CaseStatement>(utils::Empty, def_body);
- ast::CaseSelectorList case_val;
- case_val.push_back(Expr(5_i));
+ utils::Vector case_val{Expr(5_i)};
auto* case_body = Block(create<ast::BreakStatement>());
auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
- ast::CaseStatementList body;
- body.push_back(case_stmt);
- body.push_back(def);
+ utils::Vector body{
+ case_stmt,
+ def,
+ };
auto* cond = Expr("cond");
auto* s = create<ast::SwitchStatement>(cond, body);
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_test.cc
index f8972c70864..4d9815887c8 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_test.cc
@@ -21,7 +21,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, Generate) {
- Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+ Func("my_func", {}, ty.void_(), {}, {});
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_type_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_type_test.cc
index 0973ffadadf..a86c2a00286 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -91,6 +91,19 @@ TEST_F(WgslGeneratorImplTest, EmitType_F32) {
EXPECT_EQ(out.str(), "f32");
}
+TEST_F(WgslGeneratorImplTest, EmitType_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* f16 = ty.f16();
+ Alias("make_type_reachable", f16);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, f16)) << gen.error();
+ EXPECT_EQ(out.str(), "f16");
+}
+
TEST_F(WgslGeneratorImplTest, EmitType_I32) {
auto* i32 = ty.i32();
Alias("make_type_reachable", i32);
@@ -102,7 +115,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_I32) {
EXPECT_EQ(out.str(), "i32");
}
-TEST_F(WgslGeneratorImplTest, EmitType_Matrix) {
+TEST_F(WgslGeneratorImplTest, EmitType_Matrix_F32) {
auto* mat2x3 = ty.mat2x3<f32>();
Alias("make_type_reachable", mat2x3);
@@ -113,6 +126,19 @@ TEST_F(WgslGeneratorImplTest, EmitType_Matrix) {
EXPECT_EQ(out.str(), "mat2x3<f32>");
}
+TEST_F(WgslGeneratorImplTest, EmitType_Matrix_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* mat2x3 = ty.mat2x3<f16>();
+ Alias("make_type_reachable", mat2x3);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, mat2x3)) << gen.error();
+ EXPECT_EQ(out.str(), "mat2x3<f16>");
+}
+
TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
auto* p = ty.pointer<f32>(ast::StorageClass::kWorkgroup);
Alias("make_type_reachable", p);
@@ -136,7 +162,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_PointerAccessMode) {
}
TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
Member("b", ty.f32()),
});
@@ -151,9 +177,9 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
}
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
- auto* s = Structure("S", {
- Member("a", ty.i32(), {MemberOffset(8)}),
- Member("b", ty.f32(), {MemberOffset(16)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberOffset(8)}),
+ Member("b", ty.f32(), utils::Vector{MemberOffset(16)}),
});
GeneratorImpl& gen = Build();
@@ -171,10 +197,11 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
}
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
- auto* s = Structure("S", {
- Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
- Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
- });
+ auto* s =
+ Structure("S", utils::Vector{
+ Member("tint_0_padding", ty.i32(), utils::Vector{MemberOffset(8)}),
+ Member("tint_2_padding", ty.f32(), utils::Vector{MemberOffset(16)}),
+ });
GeneratorImpl& gen = Build();
@@ -191,9 +218,9 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
}
TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
- auto* s = Structure("S", {
- Member("a", ty.i32(), {MemberAlign(8)}),
- Member("b", ty.f32(), {MemberAlign(16)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberAlign(8)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(16)}),
});
GeneratorImpl& gen = Build();
@@ -209,9 +236,9 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
}
TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
- auto* s = Structure("S", {
- Member("a", ty.i32(), {MemberSize(16)}),
- Member("b", ty.f32(), {MemberSize(32)}),
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.i32(), utils::Vector{MemberSize(16)}),
+ Member("b", ty.f32(), utils::Vector{MemberSize(32)}),
});
GeneratorImpl& gen = Build();
@@ -227,9 +254,9 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
}
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithAttribute) {
- auto* s = Structure("S", {
+ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()),
- Member("b", ty.f32(), {MemberAlign(8)}),
+ Member("b", ty.f32(), utils::Vector{MemberAlign(8)}),
});
GeneratorImpl& gen = Build();
@@ -245,8 +272,10 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithAttribute) {
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithEntryPointAttributes) {
auto* s = Structure(
- "S", ast::StructMemberList{Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}),
- Member("b", ty.f32(), {Location(2u)})});
+ "S", utils::Vector{
+ Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kVertexIndex)}),
+ Member("b", ty.f32(), utils::Vector{Location(2u)}),
+ });
GeneratorImpl& gen = Build();
@@ -271,7 +300,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_U32) {
EXPECT_EQ(out.str(), "u32");
}
-TEST_F(WgslGeneratorImplTest, EmitType_Vector) {
+TEST_F(WgslGeneratorImplTest, EmitType_Vector_F32) {
auto* vec3 = ty.vec3<f32>();
Alias("make_type_reachable", vec3);
@@ -282,6 +311,19 @@ TEST_F(WgslGeneratorImplTest, EmitType_Vector) {
EXPECT_EQ(out.str(), "vec3<f32>");
}
+TEST_F(WgslGeneratorImplTest, EmitType_Vector_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* vec3 = ty.vec3<f16>();
+ Alias("make_type_reachable", vec3);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitType(out, vec3)) << gen.error();
+ EXPECT_EQ(out.str(), "vec3<f16>");
+}
+
struct TextureData {
ast::TextureDimension dim;
const char* name;
@@ -420,11 +462,11 @@ TEST_P(WgslGenerator_StorageTextureTest, EmitType_StorageTexture) {
auto param = GetParam();
auto* t = ty.storage_texture(param.dim, param.fmt, param.access);
- Global("g", t,
- ast::AttributeList{
- create<ast::BindingAttribute>(1),
- create<ast::GroupAttribute>(2),
- });
+ GlobalVar("g", t,
+ utils::Vector{
+ create<ast::BindingAttribute>(1u),
+ create<ast::GroupAttribute>(2u),
+ });
GeneratorImpl& gen = Build();
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_unary_op_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
index 2c46b44621b..b741dc80f09 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@ namespace {
using WgslUnaryOpTest = TestHelper;
TEST_F(WgslUnaryOpTest, AddressOf) {
- Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.f32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
WrapInFunction(op);
@@ -32,7 +32,7 @@ TEST_F(WgslUnaryOpTest, AddressOf) {
}
TEST_F(WgslUnaryOpTest, Complement) {
- Global("expr", ty.u32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.u32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
WrapInFunction(op);
@@ -44,7 +44,7 @@ TEST_F(WgslUnaryOpTest, Complement) {
}
TEST_F(WgslUnaryOpTest, Indirection) {
- Global("G", ty.f32(), ast::StorageClass::kPrivate);
+ GlobalVar("G", ty.f32(), ast::StorageClass::kPrivate);
auto* p =
Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
@@ -58,7 +58,7 @@ TEST_F(WgslUnaryOpTest, Indirection) {
}
TEST_F(WgslUnaryOpTest, Not) {
- Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.bool_(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
WrapInFunction(op);
@@ -70,7 +70,7 @@ TEST_F(WgslUnaryOpTest, Not) {
}
TEST_F(WgslUnaryOpTest, Negation) {
- Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+ GlobalVar("expr", ty.i32(), ast::StorageClass::kPrivate);
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
WrapInFunction(op);
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
index a68932cf59b..1d5e4d4c5e8 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
@@ -50,5 +50,306 @@ TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_InferredType) {
EXPECT_EQ(gen.result(), " var a = 123i;\n");
}
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_AInt) {
+ auto* C = Const("C", nullptr, Expr(1_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = 1;
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_AFloat) {
+ auto* C = Const("C", nullptr, Expr(1._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = 1.0;
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_i32) {
+ auto* C = Const("C", nullptr, Expr(1_i));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = 1i;
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_u32) {
+ auto* C = Const("C", nullptr, Expr(1_u));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = 1u;
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_f32) {
+ auto* C = Const("C", nullptr, Expr(1_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = 1.0f;
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, Expr(1_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(enable f16;
+
+fn f() {
+ const C = 1.0h;
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AInt) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = vec3(1, 2, 3);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+ auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = vec3(1.0, 2.0, 3.0);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f32) {
+ auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = vec3<f32>(1.0f, 2.0f, 3.0f);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(enable f16;
+
+fn f() {
+ const C = vec3<f16>(1.0h, 2.0h, 3.0h);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+ auto* C =
+ Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = mat2x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+ auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = mat2x3<f32>(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f16) {
+ Enable(ast::Extension::kF16);
+
+ auto* C = Const("C", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(enable f16;
+
+fn f() {
+ const C = mat2x3<f16>(1.0h, 2.0h, 3.0h, 4.0h, 5.0h, 6.0h);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_f32) {
+ auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = array<f32, 3u>(1.0f, 2.0f, 3.0f);
+ let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+ auto* C = Const("C", nullptr,
+ Construct(ty.array(ty.vec2<bool>(), 3_u), //
+ vec2<bool>(true, false), //
+ vec2<bool>(false, true), //
+ vec2<bool>(true, true)));
+ Func("f", utils::Empty, ty.void_(),
+ utils::Vector{
+ Decl(C),
+ Decl(Let("l", nullptr, Expr(C))),
+ });
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+
+ EXPECT_EQ(gen.result(), R"(fn f() {
+ const C = array<vec2<bool>, 3u>(vec2<bool>(true, false), vec2<bool>(false, true), vec2<bool>(true, true));
+ let l = C;
+}
+)");
+}
} // namespace
} // namespace tint::writer::wgsl
diff --git a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_test.cc b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_test.cc
index 83af7c25ea9..78e518e6234 100644
--- a/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_test.cc
+++ b/chromium/third_party/dawn/src/tint/writer/wgsl/generator_impl_variable_test.cc
@@ -22,7 +22,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitVariable) {
- auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -32,7 +32,7 @@ TEST_F(WgslGeneratorImplTest, EmitVariable) {
}
TEST_F(WgslGeneratorImplTest, EmitVariable_StorageClass) {
- auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+ auto* v = GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
@@ -42,12 +42,12 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_StorageClass) {
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Read) {
- auto* s = Structure("S", {Member("a", ty.i32())});
- auto* v = Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{Member("a", ty.i32())});
+ auto* v = GlobalVar("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -56,28 +56,13 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Read) {
EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, read> a : S;)");
}
-TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Write) {
- auto* s = Structure("S", {Member("a", ty.i32())});
- auto* v = Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
-
- GeneratorImpl& gen = Build();
-
- std::stringstream out;
- ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
- EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, write> a : S;)");
-}
-
TEST_F(WgslGeneratorImplTest, EmitVariable_Access_ReadWrite) {
- auto* s = Structure("S", {Member("a", ty.i32())});
- auto* v = Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
- ast::AttributeList{
- create<ast::BindingAttribute>(0),
- create<ast::GroupAttribute>(0),
- });
+ auto* s = Structure("S", utils::Vector{Member("a", ty.i32())});
+ auto* v = GlobalVar("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+ utils::Vector{
+ create<ast::BindingAttribute>(0u),
+ create<ast::GroupAttribute>(0u),
+ });
GeneratorImpl& gen = Build();
@@ -87,11 +72,12 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_Access_ReadWrite) {
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
- auto* v = Global("a", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
- ast::AttributeList{
- create<ast::GroupAttribute>(1),
- create<ast::BindingAttribute>(2),
- });
+ auto* v =
+ GlobalVar("a", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
+ utils::Vector{
+ create<ast::GroupAttribute>(1u),
+ create<ast::BindingAttribute>(2u),
+ });
GeneratorImpl& gen = Build();
@@ -101,7 +87,7 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Constructor) {
- auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(1_f));
+ auto* v = GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate, Expr(1_f));
GeneratorImpl& gen = Build();
@@ -110,9 +96,9 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_Constructor) {
EXPECT_EQ(out.str(), R"(var<private> a : f32 = 1.0f;)");
}
-TEST_F(WgslGeneratorImplTest, EmitVariable_Const) {
+TEST_F(WgslGeneratorImplTest, EmitVariable_Let_Explicit) {
auto* v = Let("a", ty.f32(), Expr(1_f));
- WrapInFunction(Decl(v));
+ WrapInFunction(v);
GeneratorImpl& gen = Build();
@@ -121,5 +107,38 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_Const) {
EXPECT_EQ(out.str(), R"(let a : f32 = 1.0f;)");
}
+TEST_F(WgslGeneratorImplTest, EmitVariable_Let_Inferred) {
+ auto* v = Let("a", nullptr, Expr(1_f));
+ WrapInFunction(v);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+ EXPECT_EQ(out.str(), R"(let a = 1.0f;)");
+}
+
+TEST_F(WgslGeneratorImplTest, EmitVariable_Const_Explicit) {
+ auto* v = Const("a", ty.f32(), Expr(1_f));
+ WrapInFunction(v);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+ EXPECT_EQ(out.str(), R"(const a : f32 = 1.0f;)");
+}
+
+TEST_F(WgslGeneratorImplTest, EmitVariable_Const_Inferred) {
+ auto* v = Const("a", nullptr, Expr(1_f));
+ WrapInFunction(v);
+
+ GeneratorImpl& gen = Build();
+
+ std::stringstream out;
+ ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+ EXPECT_EQ(out.str(), R"(const a = 1.0f;)");
+}
+
} // namespace
} // namespace tint::writer::wgsl