diff --git a/source/opcode.cpp b/source/opcode.cpp index 6028c15d..78c23868 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -587,3 +587,19 @@ bool spvOpcodeIsScalarizable(SpvOp opcode) { return false; } } + +bool spvOpcodeIsDebug(SpvOp opcode) { + switch (opcode) { + case SpvOpName: + case SpvOpMemberName: + case SpvOpSource: + case SpvOpSourceContinued: + case SpvOpSourceExtension: + case SpvOpString: + case SpvOpLine: + case SpvOpNoLine: + return true; + default: + return false; + } +} diff --git a/source/opcode.h b/source/opcode.h index 2bbd4177..76f9a0e8 100644 --- a/source/opcode.h +++ b/source/opcode.h @@ -129,4 +129,8 @@ bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode); // Returns true if the opcode with vector inputs could be divided into a series // of independent scalar operations that would give the same result. bool spvOpcodeIsScalarizable(SpvOp opcode); + +// Returns true if the given opcode is a debug instruction. +bool spvOpcodeIsDebug(SpvOp opcode); + #endif // SOURCE_OPCODE_H_ diff --git a/source/val/validate_debug.cpp b/source/val/validate_debug.cpp index d84ed380..b49890f2 100644 --- a/source/val/validate_debug.cpp +++ b/source/val/validate_debug.cpp @@ -14,6 +14,8 @@ #include "source/val/validate.h" +#include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" @@ -54,6 +56,13 @@ spv_result_t ValidateLine(ValidationState_t& _, const Instruction* inst) { } // namespace spv_result_t DebugPass(ValidationState_t& _, const Instruction* inst) { + if (spvIsWebGPUEnv(_.context()->target_env) && + spvOpcodeIsDebug(inst->opcode())) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "Debugging instructions are not allowed in the WebGPU execution " + << "environment."; + } + switch (inst->opcode()) { case SpvOpMemberName: if (auto error = ValidateMemberName(_, inst)) return error; diff --git a/test/val/val_webgpu_test.cpp b/test/val/val_webgpu_test.cpp index b65d08fe..b3f7af9d 100644 --- a/test/val/val_webgpu_test.cpp +++ b/test/val/val_webgpu_test.cpp @@ -46,6 +46,113 @@ TEST_F(ValidateWebGPU, OpUndefIsDisallowed) { EXPECT_THAT(getDiagnosticString(), HasSubstr("OpUndef is disallowed")); } +TEST_F(ValidateWebGPU, OpNameIsDisallowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpName %1 "foo" +%1 = OpTypeFloat 32 +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Debugging instructions are not allowed in the WebGPU " + "execution environment.\n OpName %foo \"foo\"\n")); +} + +TEST_F(ValidateWebGPU, OpMemberNameIsDisallowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpMemberName %2 0 "foo" +%1 = OpTypeFloat 32 +%2 = OpTypeStruct %1 +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Debugging instructions are not allowed in the WebGPU " + "execution environment.\n OpMemberName %_struct_1 0 " + "\"foo\"\n")); +} + +TEST_F(ValidateWebGPU, OpSourceIsDisallowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpSource GLSL 450 +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Debugging instructions are not allowed in the WebGPU " + "execution environment.\n OpSource GLSL 450\n")); +} + +// OpSourceContinued does not have a test case, because it requires being +// preceded by OpSource, which will cause a validation error. + +TEST_F(ValidateWebGPU, OpSourceExtensionIsDisallowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpSourceExtension "bar" +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Debugging instructions are not allowed in the WebGPU " + "execution environment.\n OpSourceExtension " + "\"bar\"\n")); +} + +TEST_F(ValidateWebGPU, OpStringIsDisallowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 +%1 = OpString "foo" +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Debugging instructions are not allowed in the WebGPU " + "execution environment.\n %1 = OpString \"foo\"\n")); +} + +// OpLine does not have a test case, because it requires being preceded by +// OpString, which will cause a validation error. + +TEST_F(ValidateWebGPU, OpNoLineDisallowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpNoLine +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Debugging instructions are not allowed in the WebGPU " + "execution environment.\n OpNoLine\n")); +} + } // namespace } // namespace val } // namespace spvtools