Fail validation when RelaxedPrecision is applied to a type. (#4823)
* Fail validation when RelaxedPrecision is applied to a type.
Fixes #4723
Fixes #4725
* Fixup invalid test
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index b9448e3..907c184 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -1661,6 +1661,24 @@
"of a structure type";
}
+spv_result_t CheckRelaxPrecisionDecoration(ValidationState_t& vstate,
+ const Instruction& inst,
+ const Decoration& decoration) {
+ // This is not the most precise check, but the rules for RelaxPrecision are
+ // very general, and it will be difficult to implement precisely. For now,
+ // I will only check for the cases that cause problems for the optimizer.
+ if (!spvOpcodeGeneratesType(inst.opcode())) {
+ return SPV_SUCCESS;
+ }
+
+ if (decoration.struct_member_index() != Decoration::kInvalidMember &&
+ inst.opcode() == SpvOpTypeStruct) {
+ return SPV_SUCCESS;
+ }
+ return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
+ << "RelaxPrecision decoration cannot be applied to a type";
+}
+
#define PASS_OR_BAIL_AT_LINE(X, LINE) \
{ \
spv_result_t e##LINE = (X); \
@@ -1715,6 +1733,10 @@
case SpvDecorationLocation:
PASS_OR_BAIL(CheckLocationDecoration(vstate, *inst, decoration));
break;
+ case SpvDecorationRelaxedPrecision:
+ PASS_OR_BAIL(
+ CheckRelaxPrecisionDecoration(vstate, *inst, decoration));
+ break;
default:
break;
}
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index 3c68263..1af45dd 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -50,20 +50,20 @@
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
- OpDecorate %1 ArrayStride 4
- OpDecorate %1 RelaxedPrecision
+ OpDecorate %1 Location 4
+ OpDecorate %1 Centroid
%2 = OpTypeFloat 32
- %1 = OpTypeRuntimeArray %2
+ %3 = OpTypePointer Output %2
+ %1 = OpVariable %3 Output
; Since %1 is used first in Decoration, it gets id 1.
)";
const uint32_t id = 1;
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
// Must have 2 decorations.
- EXPECT_THAT(
- vstate_->id_decorations(id),
- Eq(std::set<Decoration>{Decoration(SpvDecorationArrayStride, {4}),
- Decoration(SpvDecorationRelaxedPrecision)}));
+ EXPECT_THAT(vstate_->id_decorations(id),
+ Eq(std::set<Decoration>{Decoration(SpvDecorationLocation, {4}),
+ Decoration(SpvDecorationCentroid)}));
}
TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) {
@@ -8363,6 +8363,52 @@
HasSubstr("PerVertexKHR must be declared as arrays"));
}
+TEST_F(ValidateDecorations, RelaxedPrecisionDecorationOnNumericTypeBad) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %float RelaxedPrecision
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("RelaxPrecision decoration cannot be applied to a type"));
+}
+
+TEST_F(ValidateDecorations, RelaxedPrecisionDecorationOnStructMember) {
+ const spv_target_env env = SPV_ENV_VULKAN_1_0;
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpMemberDecorate %struct 0 RelaxedPrecision
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %struct = OpTypeStruct %float
+ %main = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, env);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
+}
+
} // namespace
} // namespace val
} // namespace spvtools