Skip to content

Commit ee4f6be

Browse files
authored
Add support for SPV_EXT_split_barrier (#6732)
1 parent b0333e7 commit ee4f6be

6 files changed

Lines changed: 238 additions & 26 deletions

File tree

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ vars = {
1414

1515
're2_revision': '972a15cedd008d846f1a39b2e88ce48d7f166cbd',
1616

17-
'spirv_headers_revision': '1e770e7de8373a8dd49f23416cf7ca4001d01040',
17+
'spirv_headers_revision': '8c5559c134abcf432ec59db842404087b9906c1a',
1818

1919
'mimalloc_revision': 'fef6b0dd70f9d7fa0750b0d0b9fbb471203b94cd',
2020
}

source/val/validate_barriers.cpp

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,52 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) {
3333
const uint32_t result_type = inst->type_id();
3434

3535
switch (opcode) {
36-
case spv::Op::OpControlBarrier: {
37-
if (_.version() < SPV_SPIRV_VERSION_WORD(1, 3)) {
38-
_.function(inst->function()->id())
39-
->RegisterExecutionModelLimitation(
40-
[](spv::ExecutionModel model, std::string* message) {
41-
if (model != spv::ExecutionModel::TessellationControl &&
42-
model != spv::ExecutionModel::GLCompute &&
43-
model != spv::ExecutionModel::Kernel &&
44-
model != spv::ExecutionModel::TaskNV &&
45-
model != spv::ExecutionModel::MeshNV) {
46-
if (message) {
47-
*message =
48-
"In SPIR-V 1.2 or earlier, OpControlBarrier requires "
49-
"one of the following "
50-
"Execution Models: TessellationControl, GLCompute, "
51-
"Kernel, MeshNV or TaskNV";
52-
}
53-
return false;
36+
case spv::Op::OpControlBarrier:
37+
case spv::Op::OpControlBarrierArriveEXT:
38+
case spv::Op::OpControlBarrierWaitEXT: {
39+
if (opcode == spv::Op::OpControlBarrier) {
40+
if (_.version() < SPV_SPIRV_VERSION_WORD(1, 3)) {
41+
_.function(inst->function()->id())
42+
->RegisterExecutionModelLimitation([](spv::ExecutionModel model,
43+
std::string* message) {
44+
if (model != spv::ExecutionModel::TessellationControl &&
45+
model != spv::ExecutionModel::GLCompute &&
46+
model != spv::ExecutionModel::Kernel &&
47+
model != spv::ExecutionModel::TaskNV &&
48+
model != spv::ExecutionModel::MeshNV) {
49+
if (message) {
50+
*message =
51+
"In SPIR-V 1.2 or earlier, OpControlBarrier requires "
52+
"one of the following "
53+
"Execution Models: TessellationControl, GLCompute, "
54+
"Kernel, MeshNV or TaskNV";
5455
}
55-
return true;
56-
});
56+
return false;
57+
}
58+
return true;
59+
});
60+
}
61+
}
62+
63+
if (opcode == spv::Op::OpControlBarrierArriveEXT ||
64+
opcode == spv::Op::OpControlBarrierWaitEXT) {
65+
_.function(inst->function()->id())
66+
->RegisterExecutionModelLimitation([&_](spv::ExecutionModel model,
67+
std::string* message) {
68+
if (model != spv::ExecutionModel::GLCompute &&
69+
model != spv::ExecutionModel::Kernel) {
70+
if (message) {
71+
*message = _.VkErrorID(13552)
72+
.append(
73+
"The SplitBarrierEXT capability must not "
74+
"be enabled in any stage other than "
75+
"GLCompute or Kernel.")
76+
.c_str();
77+
}
78+
return false;
79+
}
80+
return true;
81+
});
5782
}
5883

5984
const uint32_t execution_scope = inst->word(1);

source/val/validate_memory_semantics.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
194194
}
195195
if (!spvOpcodeIsAtomicOp(inst->opcode())) {
196196
return _.diag(SPV_ERROR_INVALID_DATA, inst)
197-
<< _.VkErrorID(10874) << spvOpcodeString(opcode)
197+
<< _.VkErrorID(13551) << spvOpcodeString(opcode)
198198
<< ": Memory Semantics with Volatile bit set must not be used "
199199
"with barrier instructions";
200200
}
@@ -286,6 +286,36 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
286286
}
287287
}
288288

289+
if (is_vulkan && (opcode == spv::Op::OpControlBarrierArriveEXT ||
290+
opcode == spv::Op::OpControlBarrierWaitEXT)) {
291+
auto aquire_release_mask = uint32_t(
292+
spv::MemorySemanticsMask::Acquire | spv::MemorySemanticsMask::Release |
293+
spv::MemorySemanticsMask::AcquireRelease);
294+
295+
if (opcode == spv::Op::OpControlBarrierArriveEXT) {
296+
if ((value & aquire_release_mask) !=
297+
uint32_t(spv::MemorySemanticsMask::Release) &&
298+
((value & aquire_release_mask) !=
299+
uint32_t(spv::MemorySemanticsMask::MaskNone))) {
300+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
301+
<< _.VkErrorID(13556) << spvOpcodeString(opcode)
302+
<< " Memory Semantics must not have any non-relaxed memory "
303+
"order set other than Release";
304+
}
305+
}
306+
if (opcode == spv::Op::OpControlBarrierWaitEXT) {
307+
if ((value & aquire_release_mask) !=
308+
uint32_t(spv::MemorySemanticsMask::Acquire) &&
309+
((value & aquire_release_mask) !=
310+
uint32_t(spv::MemorySemanticsMask::MaskNone))) {
311+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
312+
<< _.VkErrorID(13557) << spvOpcodeString(opcode)
313+
<< " Memory Semantics must not have any non-relaxed memory "
314+
"order set other than Acquire";
315+
}
316+
}
317+
}
318+
289319
// TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments.
290320

291321
return SPV_SUCCESS;

source/val/validation_state.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,8 +3422,6 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
34223422
return VUID_WRAP(VUID-StandaloneSpirv-MemorySemantics-10872);
34233423
case 10873:
34243424
return VUID_WRAP(VUID-StandaloneSpirv-MemorySemantics-10873);
3425-
case 10874:
3426-
return VUID_WRAP(VUID-StandaloneSpirv-MemorySemantics-10874);
34273425
case 10875:
34283426
return VUID_WRAP(VUID-StandaloneSpirv-UnequalMemorySemantics-10875);
34293427
case 10876:
@@ -3471,6 +3469,14 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
34713469
return VUID_WRAP(VUID-StandaloneSpirv-None-12295);
34723470
case 12297:
34733471
return VUID_WRAP(VUID-StandaloneSpirv-Type-12297);
3472+
case 13551:
3473+
return VUID_WRAP(VUID-StandaloneSpirv-MemorySemantics-13551);
3474+
case 13552:
3475+
return VUID_WRAP(VUID-StandaloneSpirv-SplitBarrierEXT-13552);
3476+
case 13556:
3477+
return VUID_WRAP(VUID-StandaloneSpirv-MemorySemantics-13556);
3478+
case 13557:
3479+
return VUID_WRAP(VUID-StandaloneSpirv-MemorySemantics-13557);
34743480
default:
34753481
return ""; // unknown id
34763482
}

test/val/val_barriers_test.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ OpCapability Shader
4545
} else if (execution_model == "Geometry") {
4646
ss << "OpExecutionMode %main InputPoints\n";
4747
ss << "OpExecutionMode %main OutputPoints\n";
48+
} else if (execution_model == "MeshEXT") {
49+
ss << "OpExecutionMode %main OutputPoints\n";
50+
ss << "OpExecutionMode %main OutputPrimitivesEXT 124\n";
51+
ss << "OpExecutionMode %main OutputVertices 5\n";
52+
ss << "OpExecutionMode %main LocalSize 1 1 1\n";
4853
} else if (execution_model == "GLCompute") {
4954
ss << "OpExecutionMode %main LocalSize 1 1 1\n";
5055
}
@@ -89,6 +94,11 @@ OpCapability Shader
8994
%workgroup_memory = OpConstant %u32 256
9095
%image_memory = OpConstant %u32 2048
9196
%uniform_image_memory = OpConstant %u32 2112
97+
%acquire_uniform_memory = OpConstant %u32 66
98+
%acquire_workgroup_memory = OpConstant %u32 258
99+
%release_uniform_memory = OpConstant %u32 68
100+
%release_workgroup_memory = OpConstant %u32 260
101+
%release_workgroup_memory_volatile = OpConstant %u32 33028
92102
93103
%main = OpFunction %void None %func
94104
%main_entry = OpLabel
@@ -1274,6 +1284,147 @@ TEST_F(ValidateBarriers, OpControlBarrierShaderCallRayGenFailure) {
12741284
"Workgroup and Subgroup"));
12751285
}
12761286

1287+
TEST_F(ValidateBarriers, OpControlBarrierArriveWaitGLComputeSuccess) {
1288+
const std::string body = R"(
1289+
OpControlBarrierArriveEXT %workgroup %workgroup %release_workgroup_memory
1290+
OpControlBarrierWaitEXT %workgroup %workgroup %acquire_workgroup_memory
1291+
)";
1292+
1293+
CompileSuccessfully(GenerateShaderCodeImpl(body,
1294+
// capabilities_and_extensions
1295+
R"(
1296+
OpCapability VulkanMemoryModelKHR
1297+
OpCapability SplitBarrierEXT
1298+
OpExtension "SPV_KHR_vulkan_memory_model"
1299+
OpExtension "SPV_EXT_split_barrier"
1300+
)",
1301+
// definitions
1302+
"",
1303+
// execution_model
1304+
"GLCompute",
1305+
// memory_model
1306+
"OpMemoryModel Logical VulkanKHR"),
1307+
SPV_ENV_VULKAN_1_1);
1308+
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1309+
}
1310+
1311+
TEST_F(ValidateBarriers, OpControlBarrierArriveWaitInvalidVolatile) {
1312+
const std::string body = R"(
1313+
OpControlBarrierArriveEXT %workgroup %workgroup %release_workgroup_memory_volatile
1314+
OpControlBarrierWaitEXT %workgroup %workgroup %acquire_workgroup_memory
1315+
)";
1316+
1317+
CompileSuccessfully(GenerateShaderCodeImpl(body,
1318+
// capabilities_and_extensions
1319+
R"(
1320+
OpCapability VulkanMemoryModelKHR
1321+
OpCapability SplitBarrierEXT
1322+
OpExtension "SPV_KHR_vulkan_memory_model"
1323+
OpExtension "SPV_EXT_split_barrier"
1324+
)",
1325+
// definitions
1326+
"",
1327+
// execution_model
1328+
"GLCompute",
1329+
// memory_model
1330+
"OpMemoryModel Logical VulkanKHR"),
1331+
SPV_ENV_VULKAN_1_1);
1332+
1333+
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1334+
EXPECT_THAT(getDiagnosticString(),
1335+
AnyVUID("VUID-StandaloneSpirv-MemorySemantics-13551"));
1336+
EXPECT_THAT(
1337+
getDiagnosticString(),
1338+
HasSubstr("Memory Semantics with Volatile bit set must not be used with "
1339+
"barrier instructions"));
1340+
}
1341+
1342+
TEST_F(ValidateBarriers, SplitBarrierInvalidExecutionModel) {
1343+
const std::string body = R"(
1344+
OpControlBarrierArriveEXT %workgroup %workgroup %release_workgroup_memory
1345+
OpControlBarrierWaitEXT %workgroup %workgroup %acquire_workgroup_memory
1346+
)";
1347+
1348+
CompileSuccessfully(GenerateShaderCode(body,
1349+
// capabilities_and_extensions
1350+
R"(
1351+
OpCapability MeshShadingEXT
1352+
OpCapability SplitBarrierEXT
1353+
OpExtension "SPV_EXT_mesh_shader"
1354+
OpExtension "SPV_EXT_split_barrier"
1355+
)",
1356+
// execution_model
1357+
"MeshEXT"),
1358+
SPV_ENV_VULKAN_1_4);
1359+
1360+
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_4));
1361+
EXPECT_THAT(getDiagnosticString(),
1362+
AnyVUID("VUID-StandaloneSpirv-SplitBarrierEXT-13552"));
1363+
EXPECT_THAT(getDiagnosticString(),
1364+
HasSubstr("The SplitBarrierEXT capability must not be enabled in "
1365+
"any stage other than GLCompute or Kernel."));
1366+
}
1367+
1368+
TEST_F(ValidateBarriers, OpControlBarrierArriveInvalidMemorySemantics) {
1369+
const std::string body = R"(
1370+
OpControlBarrierArriveEXT %workgroup %workgroup %acquire_release_workgroup
1371+
OpControlBarrierWaitEXT %workgroup %workgroup %acquire_workgroup_memory
1372+
)";
1373+
1374+
CompileSuccessfully(GenerateShaderCodeImpl(body,
1375+
// capabilities_and_extensions
1376+
R"(
1377+
OpCapability VulkanMemoryModelKHR
1378+
OpCapability SplitBarrierEXT
1379+
OpExtension "SPV_KHR_vulkan_memory_model"
1380+
OpExtension "SPV_EXT_split_barrier"
1381+
)",
1382+
// definitions
1383+
"",
1384+
// execution_model
1385+
"GLCompute",
1386+
// memory_model
1387+
"OpMemoryModel Logical VulkanKHR"),
1388+
SPV_ENV_VULKAN_1_1);
1389+
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1390+
EXPECT_THAT(getDiagnosticString(),
1391+
AnyVUID("VUID-StandaloneSpirv-MemorySemantics-13556"));
1392+
EXPECT_THAT(
1393+
getDiagnosticString(),
1394+
HasSubstr("Memory Semantics must not have any non-relaxed memory order "
1395+
"set other than Release"));
1396+
}
1397+
1398+
TEST_F(ValidateBarriers, OpControlBarrierWaitInvalidMemorySemantics) {
1399+
const std::string body = R"(
1400+
OpControlBarrierArriveEXT %workgroup %workgroup %release_workgroup_memory
1401+
OpControlBarrierWaitEXT %workgroup %workgroup %acquire_release_workgroup
1402+
)";
1403+
1404+
CompileSuccessfully(GenerateShaderCodeImpl(body,
1405+
// capabilities_and_extensions
1406+
R"(
1407+
OpCapability VulkanMemoryModelKHR
1408+
OpCapability SplitBarrierEXT
1409+
OpExtension "SPV_KHR_vulkan_memory_model"
1410+
OpExtension "SPV_EXT_split_barrier"
1411+
)",
1412+
// definitions
1413+
"",
1414+
// execution_model
1415+
"GLCompute",
1416+
// memory_model
1417+
"OpMemoryModel Logical VulkanKHR"),
1418+
SPV_ENV_VULKAN_1_1);
1419+
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1420+
EXPECT_THAT(getDiagnosticString(),
1421+
AnyVUID("VUID-StandaloneSpirv-MemorySemantics-13557"));
1422+
EXPECT_THAT(
1423+
getDiagnosticString(),
1424+
HasSubstr("Memory Semantics must not have any non-relaxed memory order "
1425+
"set other than Acquire"));
1426+
}
1427+
12771428
} // namespace
12781429
} // namespace val
12791430
} // namespace spvtools

test/val/val_memory_semantics_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ INSTANTIATE_TEST_SUITE_P(
385385
Values(OpControlBarrier),
386386
Values(TestResult(
387387
SPV_ERROR_INVALID_DATA,
388-
"VUID-StandaloneSpirv-MemorySemantics-10874",
388+
"VUID-StandaloneSpirv-MemorySemantics-13551",
389389
"Memory Semantics with Volatile bit set must not be used with "
390390
"barrier instructions"))));
391391

@@ -401,7 +401,7 @@ INSTANTIATE_TEST_SUITE_P(
401401
Values(OpControlBarrier, OpMemoryBarrier),
402402
Values(TestResult(
403403
SPV_ERROR_INVALID_DATA,
404-
"VUID-StandaloneSpirv-MemorySemantics-10874",
404+
"VUID-StandaloneSpirv-MemorySemantics-13551",
405405
"Memory Semantics with Volatile bit set must not be used with "
406406
"barrier instructions"))));
407407

0 commit comments

Comments
 (0)