Skip to content

Commit a6e2406

Browse files
authored
Validate that OpDecorateId IDs are well-ordered (KhronosGroup#6227)
* spirv-val: Validate that OpDecorateId does not target OpDecorationGroup * spirv-val: Validate that OpDecorateId decorations come before the target There were a handful of tests which were violating this so we'll fix them up at the same time.
1 parent a983ab1 commit a6e2406

File tree

3 files changed

+120
-6
lines changed

3 files changed

+120
-6
lines changed

source/val/validate_annotation.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,13 +333,35 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
333333
}
334334

335335
spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) {
336+
const auto target_id = inst->GetOperandAs<uint32_t>(0);
337+
const auto target = _.FindDef(target_id);
338+
if (target && spv::Op::OpDecorationGroup == target->opcode()) {
339+
return _.diag(SPV_ERROR_INVALID_ID, inst)
340+
<< "OpMemberDecorate Target <id> " << _.getIdName(target_id)
341+
<< " must not be an OpDecorationGroup instruction.";
342+
}
343+
336344
const auto decoration = inst->GetOperandAs<spv::Decoration>(1);
337345
if (!DecorationTakesIdParameters(decoration)) {
338346
return _.diag(SPV_ERROR_INVALID_ID, inst)
339347
<< "Decorations that don't take ID parameters may not be used with "
340348
"OpDecorateId";
341349
}
342350

351+
for (uint32_t i = 2; i < inst->operands().size(); ++i) {
352+
const auto param_id = inst->GetOperandAs<uint32_t>(i);
353+
const auto param = _.FindDef(param_id);
354+
355+
// Both target and param are elements of ordered_instructions we can
356+
// determine their relative positions in the SPIR-V module by comparing
357+
// pointers.
358+
if (target <= param) {
359+
return _.diag(SPV_ERROR_INVALID_ID, inst)
360+
<< "Parameter <ID> " << _.getIdName(param_id)
361+
<< " must appear earlier in the binary than the target";
362+
}
363+
}
364+
343365
// No member decorations take id parameters, so we don't bother checking if
344366
// we are using a member only decoration here.
345367

@@ -388,8 +410,7 @@ spv_result_t ValidateDecorationGroup(ValidationState_t& _,
388410
if (use->opcode() != spv::Op::OpDecorate &&
389411
use->opcode() != spv::Op::OpGroupDecorate &&
390412
use->opcode() != spv::Op::OpGroupMemberDecorate &&
391-
use->opcode() != spv::Op::OpName &&
392-
use->opcode() != spv::Op::OpDecorateId && !use->IsNonSemantic()) {
413+
use->opcode() != spv::Op::OpName && !use->IsNonSemantic()) {
393414
return _.diag(SPV_ERROR_INVALID_ID, inst)
394415
<< "Result id of OpDecorationGroup can only "
395416
<< "be targeted by OpName, OpGroupDecorate, "

test/val/val_decoration_test.cpp

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5445,6 +5445,97 @@ OpFunctionEnd
54455445
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
54465446
}
54475447

5448+
// OpDecorateId
5449+
5450+
TEST_F(ValidateDecorations, DecorateIdGood) {
5451+
const std::string spirv = R"(
5452+
OpCapability Shader
5453+
OpMemoryModel Logical Simple
5454+
OpEntryPoint GLCompute %main "main"
5455+
OpExecutionMode %main LocalSize 1 1 1
5456+
OpName %subgroupscope "subgroupscope"
5457+
OpName %int0 "int0"
5458+
OpName %fn "fn"
5459+
OpDecorateId %int0 UniformId %subgroupscope
5460+
%void = OpTypeVoid
5461+
%float = OpTypeFloat 32
5462+
%int = OpTypeInt 32 1
5463+
%subgroupscope = OpConstant %int 3
5464+
%int0 = OpConstantNull %int
5465+
%fn = OpTypeFunction %void
5466+
%main = OpFunction %void None %fn
5467+
%entry = OpLabel
5468+
OpReturn
5469+
OpFunctionEnd
5470+
)";
5471+
5472+
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
5473+
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
5474+
EXPECT_THAT(getDiagnosticString(), Eq(""));
5475+
}
5476+
5477+
TEST_F(ValidateDecorations, DecorateIdGroupBad) {
5478+
const std::string spirv = R"(
5479+
OpCapability Shader
5480+
OpMemoryModel Logical Simple
5481+
OpEntryPoint GLCompute %main "main"
5482+
OpExecutionMode %main LocalSize 1 1 1
5483+
OpName %subgroupscope "subgroupscope"
5484+
OpName %int0 "int0"
5485+
OpName %fn "fn"
5486+
OpName %group "group"
5487+
OpDecorateId %group UniformId %subgroupscope
5488+
%group = OpDecorationGroup
5489+
OpGroupDecorate %group %int0
5490+
%void = OpTypeVoid
5491+
%float = OpTypeFloat 32
5492+
%int = OpTypeInt 32 1
5493+
%subgroupscope = OpConstant %int 3
5494+
%int0 = OpConstantNull %int
5495+
%fn = OpTypeFunction %void
5496+
%main = OpFunction %void None %fn
5497+
%entry = OpLabel
5498+
OpReturn
5499+
OpFunctionEnd
5500+
)";
5501+
5502+
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
5503+
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
5504+
EXPECT_THAT(getDiagnosticString(),
5505+
HasSubstr("must not be an OpDecorationGroup instruction.\n"
5506+
" OpDecorateId %group UniformId %subgroupscope"));
5507+
}
5508+
5509+
TEST_F(ValidateDecorations, DecorateIdOutOfOrderBad) {
5510+
const std::string spirv = R"(
5511+
OpCapability Shader
5512+
OpMemoryModel Logical Simple
5513+
OpEntryPoint GLCompute %main "main"
5514+
OpExecutionMode %main LocalSize 1 1 1
5515+
OpName %subgroupscope "subgroupscope"
5516+
OpName %int0 "int0"
5517+
OpName %fn "fn"
5518+
OpDecorateId %int0 UniformId %subgroupscope
5519+
%void = OpTypeVoid
5520+
%float = OpTypeFloat 32
5521+
%int = OpTypeInt 32 1
5522+
%int0 = OpConstantNull %int
5523+
%subgroupscope = OpConstant %int 3
5524+
%fn = OpTypeFunction %void
5525+
%main = OpFunction %void None %fn
5526+
%entry = OpLabel
5527+
OpReturn
5528+
OpFunctionEnd
5529+
)";
5530+
5531+
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
5532+
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
5533+
EXPECT_THAT(getDiagnosticString(),
5534+
HasSubstr("[%subgroupscope]' must appear earlier in the"
5535+
" binary than the target\n"
5536+
" OpDecorateId %int0 UniformId %subgroupscope"));
5537+
}
5538+
54485539
// Uniform and UniformId decorations
54495540

54505541
TEST_F(ValidateDecorations, UniformDecorationGood) {
@@ -5486,17 +5577,19 @@ OpName %subgroupscope "subgroupscope"
54865577
OpName %call "call"
54875578
OpName %myfunc "myfunc"
54885579
OpName %int0 "int0"
5580+
OpName %int1 "int1"
54895581
OpName %float0 "float0"
54905582
OpName %fn "fn"
54915583
)") + inst +
54925584
R"(
54935585
%void = OpTypeVoid
54945586
%float = OpTypeFloat 32
54955587
%int = OpTypeInt 32 1
5496-
%int0 = OpConstantNull %int
5588+
%int1 = OpConstant %int 1
54975589
%int_99 = OpConstant %int 99
54985590
%subgroupscope = OpConstant %int 3
54995591
%float0 = OpConstantNull %float
5592+
%int0 = OpConstantNull %int
55005593
%fn = OpTypeFunction %void
55015594
%myfunc = OpFunction %void None %fn
55025595
%myfuncentry = OpLabel
@@ -5613,7 +5706,7 @@ TEST_F(ValidateDecorations,
56135706

56145707
TEST_F(ValidateDecorations, UniformDecorationWithScopeIdV14VulkanEnv) {
56155708
const std::string spirv =
5616-
ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int0");
5709+
ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int1");
56175710

56185711
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1_SPIRV_1_4);
56195712
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
@@ -10523,8 +10616,8 @@ const std::string kNodeShaderPostlude = R"(
1052310616
%node1 = OpConstantStringAMDX "node1"
1052410617
%node2 = OpConstantStringAMDX "node2"
1052510618
%S = OpTypeStruct
10526-
%_payloadarr_S = OpTypeNodePayloadArrayAMDX %S
1052710619
%_payloadarr_S_0 = OpTypeNodePayloadArrayAMDX %S
10620+
%_payloadarr_S = OpTypeNodePayloadArrayAMDX %S
1052810621
%bool = OpTypeBool
1052910622
%true = OpConstantTrue %bool
1053010623
%void = OpTypeVoid

test/val/val_modes_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2543,8 +2543,8 @@ const std::string kNodeShaderPostlude = R"(
25432543
%node1 = OpConstantStringAMDX "node1"
25442544
%node2 = OpConstantStringAMDX "node2"
25452545
%S = OpTypeStruct
2546-
%_payloadarr_S = OpTypeNodePayloadArrayAMDX %S
25472546
%_payloadarr_S_0 = OpTypeNodePayloadArrayAMDX %S
2547+
%_payloadarr_S = OpTypeNodePayloadArrayAMDX %S
25482548
%bool = OpTypeBool
25492549
%true = OpConstantTrue %bool
25502550
%void = OpTypeVoid

0 commit comments

Comments
 (0)