Update OpControlBarriers rules for WebGPU (#2769)
* Update OpControlBarriers rules for WebGPU
Part of #2724
diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp
index 0088cdd..c8df405 100644
--- a/source/val/validate_memory_semantics.cpp
+++ b/source/val/validate_memory_semantics.cpp
@@ -57,36 +57,59 @@
}
if (spvIsWebGPUEnv(_.context()->target_env)) {
- uint32_t valid_bits = SpvMemorySemanticsUniformMemoryMask |
- SpvMemorySemanticsWorkgroupMemoryMask |
- SpvMemorySemanticsImageMemoryMask |
- SpvMemorySemanticsOutputMemoryKHRMask |
- SpvMemorySemanticsMakeAvailableKHRMask |
- SpvMemorySemanticsMakeVisibleKHRMask;
- if (!spvOpcodeIsAtomicOp(inst->opcode())) {
- valid_bits |= SpvMemorySemanticsAcquireReleaseMask;
- }
-
- if (value & ~valid_bits) {
- if (spvOpcodeIsAtomicOp(inst->opcode())) {
+ if (inst->opcode() == SpvOpControlBarrier) {
+ if (!(value & SpvMemorySemanticsAcquireReleaseMask)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "WebGPU spec disallows, for OpAtomic*, any bit masks in "
- "Memory Semantics that are not UniformMemory, "
- "WorkgroupMemory, ImageMemory, or OutputMemoryKHR";
- } else {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "WebGPU spec disallows any bit masks in Memory Semantics "
- "that are not AcquireRelease, UniformMemory, "
- "WorkgroupMemory, ImageMemory, OutputMemoryKHR, "
- "MakeAvailableKHR, or MakeVisibleKHR";
+ << "For WebGPU, AcquireRelease must be set for Memory Semantics "
+ "of OpControlBarrier.";
}
- }
- if (!spvOpcodeIsAtomicOp(inst->opcode()) &&
- !(value & SpvMemorySemanticsAcquireReleaseMask)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "WebGPU spec requires AcquireRelease to set in Memory "
- "Semantics.";
+ if (!(value & SpvMemorySemanticsWorkgroupMemoryMask)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "For WebGPU, WorkgroupMemory must be set for Memory "
+ "Semantics of OpControlBarrier.";
+ }
+
+ uint32_t valid_bits = SpvMemorySemanticsAcquireReleaseMask |
+ SpvMemorySemanticsWorkgroupMemoryMask;
+ if (value & ~valid_bits) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "For WebGPU only WorkgroupMemory and AcquireRelease may be "
+ "set for Memory Semantics of OpControlBarrier.";
+ }
+ } else {
+ // TODO(2723): Rewrite this to be in the style of above and simplify.
+ uint32_t valid_bits = SpvMemorySemanticsUniformMemoryMask |
+ SpvMemorySemanticsWorkgroupMemoryMask |
+ SpvMemorySemanticsImageMemoryMask |
+ SpvMemorySemanticsOutputMemoryKHRMask |
+ SpvMemorySemanticsMakeAvailableKHRMask |
+ SpvMemorySemanticsMakeVisibleKHRMask;
+ if (!spvOpcodeIsAtomicOp(inst->opcode())) {
+ valid_bits |= SpvMemorySemanticsAcquireReleaseMask;
+ }
+
+ if (value & ~valid_bits) {
+ if (spvOpcodeIsAtomicOp(inst->opcode())) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "WebGPU spec disallows, for OpAtomic*, any bit masks in "
+ "Memory Semantics that are not UniformMemory, "
+ "WorkgroupMemory, ImageMemory, or OutputMemoryKHR";
+ } else {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "WebGPU spec disallows any bit masks in Memory Semantics "
+ "that are not AcquireRelease, UniformMemory, "
+ "WorkgroupMemory, ImageMemory, OutputMemoryKHR, "
+ "MakeAvailableKHR, or MakeVisibleKHR";
+ }
+ }
+
+ if (!spvOpcodeIsAtomicOp(inst->opcode()) &&
+ !(value & SpvMemorySemanticsAcquireReleaseMask)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "WebGPU spec requires AcquireRelease to set in Memory "
+ "Semantics.";
+ }
}
}
diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp
index c607984..32a52a8 100644
--- a/source/val/validate_scopes.cpp
+++ b/source/val/validate_scopes.cpp
@@ -122,7 +122,6 @@
// WebGPU Specific rules
if (spvIsWebGPUEnv(_.context()->target_env)) {
- // Scope for execution must be limited to Workgroup or Subgroup
if (value != SpvScopeWorkgroup) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< spvOpcodeString(opcode)
@@ -229,12 +228,21 @@
// WebGPU specific rules
if (spvIsWebGPUEnv(_.context()->target_env)) {
- if (value != SpvScopeWorkgroup && value != SpvScopeInvocation &&
- value != SpvScopeQueueFamilyKHR) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
- << ": in WebGPU environment Memory Scope is limited to "
- << "Workgroup, Invocation, and QueueFamilyKHR";
+ if (inst->opcode() == SpvOpControlBarrier) {
+ if (value != SpvScopeWorkgroup) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << spvOpcodeString(opcode)
+ << ": in WebGPU environment Memory Scope is limited to "
+ << "Workgroup for OpControlBarrier";
+ }
+ } else {
+ if (value != SpvScopeWorkgroup && value != SpvScopeInvocation &&
+ value != SpvScopeQueueFamilyKHR) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << spvOpcodeString(opcode)
+ << ": in WebGPU environment Memory Scope is limited to "
+ << "Workgroup, Invocation, and QueueFamilyKHR";
+ }
}
}
diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp
index 2214197..1d71e90 100644
--- a/test/val/val_barriers_test.cpp
+++ b/test/val/val_barriers_test.cpp
@@ -82,8 +82,10 @@
%release_uniform_workgroup = OpConstant %u32 324
%acquire_and_release_uniform = OpConstant %u32 70
%acquire_release_subgroup = OpConstant %u32 136
+%acquire_release_workgroup = OpConstant %u32 264
%uniform = OpConstant %u32 64
%uniform_workgroup = OpConstant %u32 320
+%workgroup_memory = OpConstant %u32 256
%main = OpFunction %void None %func
@@ -251,7 +253,7 @@
TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireReleaseSuccess) {
const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
+OpControlBarrier %workgroup %workgroup %acquire_release_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
@@ -260,25 +262,39 @@
TEST_F(ValidateBarriers, OpControlBarrierWebGPURelaxedFailure) {
const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %uniform_workgroup
+OpControlBarrier %workgroup %workgroup %workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("WebGPU spec requires AcquireRelease to set"));
+ HasSubstr("For WebGPU, AcquireRelease must be set for Memory "
+ "Semantics of OpControlBarrier"));
}
-TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireFailure) {
+TEST_F(ValidateBarriers, OpControlBarrierWebGPUMissingWorkgroupFailure) {
const std::string body = R"(
-OpControlBarrier %workgroup %workgroup %acquire_uniform_workgroup
+OpControlBarrier %workgroup %workgroup %acquire_release
+)";
+
+ CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("For WebGPU, WorkgroupMemory must be set for Memory "
+ "Semantics"));
+}
+
+TEST_F(ValidateBarriers, OpControlBarrierWebGPUUniformFailure) {
+ const std::string body = R"(
+OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics"));
+ HasSubstr("For WebGPU only WorkgroupMemory and AcquireRelease may be set "
+ "for Memory Semantics of OpControlBarrier."));
}
TEST_F(ValidateBarriers, OpControlBarrierWebGPUReleaseFailure) {
@@ -288,9 +304,9 @@
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("For WebGPU, AcquireRelease must be set for Memory "
+ "Semantics of OpControlBarrier"));
}
TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) {
@@ -461,6 +477,18 @@
"cannot be CrossDevice"));
}
+TEST_F(ValidateBarriers, OpControlBarrierWebGPUMemoryScopeNonWorkgroup) {
+ const std::string body = R"(
+OpControlBarrier %workgroup %subgroup %acquire_release_workgroup
+)";
+
+ CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("ControlBarrier: in WebGPU environment Memory Scope is "
+ "limited to Workgroup for OpControlBarrier"));
+}
+
TEST_F(ValidateBarriers, OpControlBarrierAcquireAndRelease) {
const std::string body = R"(
OpControlBarrier %device %device %acquire_and_release_uniform