Validate decorations from SPV_KHR_no_integer_wrap (#2271)

Validates NoSignedWrap, NoUnsignedWrap.

We are permissive by allowing any extended instruction.
This commit is contained in:
David Neto 2019-01-09 10:36:17 -05:00 committed by GitHub
parent df5bd2d05a
commit 6958d11bc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 313 additions and 4 deletions

View File

@ -1180,6 +1180,36 @@ spv_result_t CheckUniformDecoration(ValidationState_t& vstate,
return SPV_SUCCESS;
}
// Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or
// NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns
// something other than SPV_SUCCESS. Assumes each decoration on a group has been
// propagated down to the group members.
spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate,
const Instruction& inst,
const Decoration& decoration) {
switch (inst.opcode()) {
case SpvOpIAdd:
case SpvOpISub:
case SpvOpIMul:
case SpvOpShiftLeftLogical:
case SpvOpSNegate:
return SPV_SUCCESS;
case SpvOpExtInst:
// TODO(dneto): Only certain extended instructions allow these
// decorations. For now allow anything.
return SPV_SUCCESS;
default:
break;
}
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
<< (decoration.dec_type() == SpvDecorationNoSignedWrap
? "NoSignedWrap"
: "NoUnsignedWrap")
<< " decoration may not be applied to "
<< spvOpcodeString(inst.opcode());
}
#define PASS_OR_BAIL_AT_LINE(X, LINE) \
{ \
spv_result_t e##LINE = (X); \
@ -1216,6 +1246,10 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
case SpvDecorationUniform:
PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration));
break;
case SpvDecorationNoSignedWrap:
case SpvDecorationNoUnsignedWrap:
PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration));
break;
default:
break;
}

View File

@ -4810,6 +4810,282 @@ TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) {
"ID '2' decorated with both BufferBlock and Block is not allowed."));
}
std::string MakeIntegerShader(
const std::string& decoration, const std::string& inst,
const std::string& extension =
"OpExtension \"SPV_KHR_no_integer_wrap_decoration\"") {
return R"(
OpCapability Shader
OpCapability Linkage
)" + extension +
R"(
%glsl = OpExtInstImport "GLSL.std.450"
%opencl = OpExtInstImport "OpenCL.std"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpName %entry "entry"
)" + decoration +
R"(
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%int = OpTypeInt 32 1
%zero = OpConstantNull %int
%float = OpTypeFloat 32
%float0 = OpConstantNull %float
%main = OpFunction %void None %voidfn
%entry = OpLabel
)" + inst +
R"(
OpReturn
OpFunctionEnd)";
}
// NoSignedWrap
TEST_F(ValidateDecorations, NoSignedWrapOnTypeBad) {
std::string spirv = MakeIntegerShader("OpDecorate %void NoSignedWrap", "");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("NoSignedWrap decoration may not be applied to TypeVoid"));
}
TEST_F(ValidateDecorations, NoSignedWrapOnLabelBad) {
std::string spirv = MakeIntegerShader("OpDecorate %entry NoSignedWrap", "");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("NoSignedWrap decoration may not be applied to Label"));
}
TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionBad) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpIAdd %int %zero %zero", "");
CompileSuccessfully(spirv);
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("requires one of these extensions: "
"SPV_KHR_no_integer_wrap_decoration"));
}
TEST_F(ValidateDecorations, NoSignedWrapIAddGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpIAdd %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoSignedWrapISubGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpISub %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoSignedWrapIMulGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpIMul %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoSignedWrapShiftLeftLogicalGood) {
std::string spirv =
MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpShiftLeftLogical %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoSignedWrapSNegateGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpSNegate %int %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoSignedWrapSRemBad) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpSRem %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("NoSignedWrap decoration may not be applied to SRem"));
}
TEST_F(ValidateDecorations, NoSignedWrapFAddBad) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpFAdd %float %float0 %float0");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("NoSignedWrap decoration may not be applied to FAdd"));
}
TEST_F(ValidateDecorations, NoSignedWrapExtInstOpenCLGood) {
std::string spirv =
MakeIntegerShader("OpDecorate %val NoSignedWrap",
"%val = OpExtInst %int %opencl s_abs %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoSignedWrapExtInstGLSLGood) {
std::string spirv = MakeIntegerShader(
"OpDecorate %val NoSignedWrap", "%val = OpExtInst %int %glsl SAbs %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
// TODO(dneto): For NoSignedWrap and NoUnsignedWrap, permit
// "OpExtInst for instruction numbers specified in the extended
// instruction-set specifications as accepting this decoration."
// NoUnignedWrap
TEST_F(ValidateDecorations, NoUnsignedWrapOnTypeBad) {
std::string spirv = MakeIntegerShader("OpDecorate %void NoUnsignedWrap", "");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("NoUnsignedWrap decoration may not be applied to TypeVoid"));
}
TEST_F(ValidateDecorations, NoUnsignedWrapOnLabelBad) {
std::string spirv = MakeIntegerShader("OpDecorate %entry NoUnsignedWrap", "");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("NoUnsignedWrap decoration may not be applied to Label"));
}
TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionBad) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpIAdd %int %zero %zero", "");
CompileSuccessfully(spirv);
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("requires one of these extensions: "
"SPV_KHR_no_integer_wrap_decoration"));
}
TEST_F(ValidateDecorations, NoUnsignedWrapIAddGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpIAdd %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoUnsignedWrapISubGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpISub %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoUnsignedWrapIMulGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpIMul %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoUnsignedWrapShiftLeftLogicalGood) {
std::string spirv =
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpShiftLeftLogical %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoUnsignedWrapSNegateGood) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpSNegate %int %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoUnsignedWrapSRemBad) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpSRem %int %zero %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("NoUnsignedWrap decoration may not be applied to SRem"));
}
TEST_F(ValidateDecorations, NoUnsignedWrapFAddBad) {
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpFAdd %float %float0 %float0");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("NoUnsignedWrap decoration may not be applied to FAdd"));
}
TEST_F(ValidateDecorations, NoUnsignedWrapExtInstOpenCLGood) {
std::string spirv =
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpExtInst %int %opencl s_abs %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, NoUnsignedWrapExtInstGLSLGood) {
std::string spirv =
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
"%val = OpExtInst %int %glsl SAbs %zero");
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
// TODO(dneto): For NoUnsignedWrap and NoUnsignedWrap, permit
// "OpExtInst for instruction numbers specified in the extended
// instruction-set specifications as accepting this decoration."
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) {
const std::string body = R"(
OpCapability PhysicalStorageBufferAddressesEXT
@ -4952,10 +5228,9 @@ OpFunctionEnd
CompileSuccessfully(body.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"expected Aliased or Restrict for PhysicalStorageBufferEXT pointer"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("expected Aliased or Restrict for "
"PhysicalStorageBufferEXT pointer"));
}
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) {