return opcode == SpvOpUndef || spvOpcodeIsConstant(opcode);
}
+bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpSpecConstantTrue:
+ case SpvOpSpecConstantFalse:
+ case SpvOpSpecConstant:
+ return true;
+ default:
+ return false;
+ }
+}
+
int32_t spvOpcodeIsComposite(const SpvOp opcode) {
switch (opcode) {
case SpvOpTypeVector:
// Returns true if the given opcode is a constant or undef.
bool spvOpcodeIsConstantOrUndef(const SpvOp opcode);
+// Returns true if the given opcode is a scalar specialization constant.
+bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode);
+
// Determines if the given opcode is a composite type. Returns zero if false,
// non-zero otherwise.
int32_t spvOpcodeIsComposite(const SpvOp opcode);
}
template <>
+bool idUsage::isValid<SpvOpDecorate>(const spv_instruction_t* inst,
+ const spv_opcode_desc) {
+ auto decorationIndex = 2;
+ auto decoration = inst->words[decorationIndex];
+ if (decoration == SpvDecorationSpecId) {
+ auto targetIndex = 1;
+ auto target = module_.FindDef(inst->words[targetIndex]);
+ if (!target || !spvOpcodeIsScalarSpecConstant(target->opcode())) {
+ DIAG(targetIndex) << "OpDecorate SpectId decoration target <id> '"
+ << inst->words[decorationIndex]
+ << "' is not a scalar specialization constant.";
+ return false;
+ }
+ }
+ // TODO: Add validations for all decorations.
+ return true;
+}
+
+template <>
bool idUsage::isValid<SpvOpMemberDecorate>(const spv_instruction_t* inst,
const spv_opcode_desc) {
auto structTypeIndex = 1;
TODO(OpUndef)
CASE(OpMemberName)
CASE(OpLine)
+ CASE(OpDecorate)
CASE(OpMemberDecorate)
CASE(OpGroupDecorate)
CASE(OpGroupMemberDecorate)
DecorationSpecId, ValidateCapability,
Combine(ValuesIn(AllV10Capabilities()),
Values(make_pair(string(kOpenCLMemoryModel) +
- "OpEntryPoint Vertex %func \"shader\" \n" +
- "OpDecorate %intt SpecId 1\n"
- "%intt = OpTypeInt 32 0\n" + string(kVoidFVoid),
+ "OpEntryPoint Vertex %func \"shader\" \n" +
+ "OpDecorate %1 SpecId 1\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%1 = OpSpecConstant %intt 0\n" +
+ string(kVoidFVoid),
ShaderDependencies()))), );
INSTANTIATE_TEST_CASE_P(
// fixed.
make_pair(string("OpMemoryModel Logical OpenCL "
"OpEntryPoint Kernel %func \"compute\" \n"
- "OpDecorate %intt SpecId 1 "
- "%intt = OpTypeInt 32 0 ") +
+ "OpDecorate %1 SpecId 1 "
+ "%intt = OpTypeInt 32 0 "
+ "%1 = OpSpecConstant %intt 0") +
string(kVoidFVoid),
KernelDependencies()),
make_pair(string("OpMemoryModel Logical Simple "
"OpEntryPoint Vertex %func \"shader\" \n"
- "OpDecorate %intt SpecId 1 "
- "%intt = OpTypeInt 32 0 ") +
+ "OpDecorate %1 SpecId 1 "
+ "%intt = OpTypeInt 32 0 "
+ "%1 = OpSpecConstant %intt 0") +
string(kVoidFVoid),
ShaderDependencies()))), );
// clang-format off
"ID 7 defined in block 6 does not dominate its use in block 9"));
}
+TEST_F(ValidateIdWithMessage, SpecIdTargetNotSpecializationConstant) {
+ string spirv = kGLSL450MemoryModel + R"(
+OpDecorate %3 SpecId 200
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%int = OpTypeInt 32 0
+%3 = OpConstant %int 3
+%main = OpFunction %1 None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+ )";
+ CompileSuccessfully(spirv.c_str());
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpDecorate SpectId decoration target <id> '1' is not a "
+ "scalar specialization constant."));
+}
+
+TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantOpBad) {
+ string spirv = kGLSL450MemoryModel + R"(
+OpDecorate %5 SpecId 200
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%int = OpTypeInt 32 0
+%3 = OpConstant %int 1
+%4 = OpConstant %int 2
+%5 = OpSpecConstantOp %int IAdd %3 %4
+%main = OpFunction %1 None %2
+%6 = OpLabel
+OpReturn
+OpFunctionEnd
+ )";
+ CompileSuccessfully(spirv.c_str());
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpDecorate SpectId decoration target <id> '1' is not a "
+ "scalar specialization constant."));
+}
+
+TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantCompositeBad) {
+ string spirv = kGLSL450MemoryModel + R"(
+OpDecorate %3 SpecId 200
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%int = OpTypeInt 32 0
+%3 = OpSpecConstantComposite %int
+%main = OpFunction %1 None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+ )";
+ CompileSuccessfully(spirv.c_str());
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpDecorate SpectId decoration target <id> '1' is not a "
+ "scalar specialization constant."));
+}
+
+TEST_F(ValidateIdWithMessage, SpecIdTargetGood) {
+ string spirv = kGLSL450MemoryModel + R"(
+OpDecorate %3 SpecId 200
+OpDecorate %4 SpecId 201
+OpDecorate %5 SpecId 202
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%int = OpTypeInt 32 0
+%bool = OpTypeBool
+%3 = OpSpecConstant %int 3
+%4 = OpSpecConstantTrue %bool
+%5 = OpSpecConstantFalse %bool
+%main = OpFunction %1 None %2
+%6 = OpLabel
+OpReturn
+OpFunctionEnd
+ )";
+ CompileSuccessfully(spirv.c_str());
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+}
+
// TODO: OpLifetimeStart
// TODO: OpLifetimeStop
// TODO: OpAtomicInit