spirv-val: Add Vulkan FP Mode VUID (#4088)
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index d381276..01b0eca 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp
@@ -1260,7 +1260,8 @@ // decorations. Otherwise emits a diagnostic and returns something other than // SPV_SUCCESS. spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate, - const Instruction& inst) { + const Instruction& inst, + const Decoration& decoration) { // Validates width-only conversion instruction for floating-point object // i.e., OpFConvert if (inst.opcode() != SpvOpFConvert) { @@ -1270,6 +1271,15 @@ "object."; } + if (spvIsVulkanEnv(vstate.context()->target_env)) { + const auto mode = decoration.params()[0]; + if ((mode != SpvFPRoundingModeRTE) && (mode != SpvFPRoundingModeRTZ)) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << vstate.VkErrorID(4675) + << "In Vulkan, the FPRoundingMode mode must only by RTE or RTZ."; + } + } + // Validates Object operand of an OpStore for (const auto& use : inst.uses()) { const auto store = use.first; @@ -1588,7 +1598,8 @@ break; case SpvDecorationFPRoundingMode: if (is_shader) - PASS_OR_BAIL(CheckFPRoundingModeForShaders(vstate, *inst)); + PASS_OR_BAIL( + CheckFPRoundingModeForShaders(vstate, *inst, decoration)); break; case SpvDecorationNonWritable: PASS_OR_BAIL(CheckNonWritableDecoration(vstate, *inst, decoration));
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index ae34185..f56d10f 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp
@@ -1671,6 +1671,8 @@ return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656); case 4658: return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); + case 4675: + return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); case 4685: return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); case 4711:
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index e646162..cacf999 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp
@@ -4679,6 +4679,95 @@ "Object operand of an OpStore.")); } +TEST_F(ValidateDecorations, VulkanFPRoundingModeGood) { + std::string spirv = R"( + OpCapability Shader + OpCapability StorageBuffer16BitAccess + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 1 1 1 + OpMemberDecorate %ssbo 0 Offset 0 + OpDecorate %ssbo Block + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %17 FPRoundingMode RTE + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float + %float_1 = OpConstant %float 1 + %half = OpTypeFloat 16 + %ssbo = OpTypeStruct %half +%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo + %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_float Function + OpStore %b %float_1 + %16 = OpLoad %float %b + %17 = OpFConvert %half %16 + %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0 + OpStore %19 %17 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateDecorations, VulkanFPRoundingModeBadMode) { + std::string spirv = R"( + OpCapability Shader + OpCapability StorageBuffer16BitAccess + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 1 1 1 + OpMemberDecorate %ssbo 0 Offset 0 + OpDecorate %ssbo Block + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %17 FPRoundingMode RTP + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float + %float_1 = OpConstant %float 1 + %half = OpTypeFloat 16 + %ssbo = OpTypeStruct %half +%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo + %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_float Function + OpStore %b %float_1 + %16 = OpLoad %float %b + %17 = OpFConvert %half %16 + %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0 + OpStore %19 %17 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-FPRoundingMode-04675")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In Vulkan, the FPRoundingMode mode must only by RTE or RTZ.")); +} + TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) { std::string spirv = R"( OpCapability Shader