mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-13 18:00:05 +00:00
Validate correct opcode uses of OpFunction
Fixes https://crbug.com/873457 * Filed Khronos SPIR-V issue 352 * Updated bad tests * Added new test
This commit is contained in:
parent
5fc011b453
commit
8cb949ad34
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "source/val/validate.h"
|
#include "source/val/validate.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "source/opcode.h"
|
#include "source/opcode.h"
|
||||||
#include "source/val/instruction.h"
|
#include "source/val/instruction.h"
|
||||||
#include "source/val/validation_state.h"
|
#include "source/val/validation_state.h"
|
||||||
@ -38,6 +40,27 @@ spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) {
|
|||||||
<< "' does not match the Function Type's return type <id> '"
|
<< "' does not match the Function Type's return type <id> '"
|
||||||
<< _.getIdName(return_id) << "'.";
|
<< _.getIdName(return_id) << "'.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& pair : inst->uses()) {
|
||||||
|
const auto* use = pair.first;
|
||||||
|
const std::vector<SpvOp> acceptable = {
|
||||||
|
SpvOpFunctionCall,
|
||||||
|
SpvOpEntryPoint,
|
||||||
|
SpvOpEnqueueKernel,
|
||||||
|
SpvOpGetKernelNDrangeSubGroupCount,
|
||||||
|
SpvOpGetKernelNDrangeMaxSubGroupSize,
|
||||||
|
SpvOpGetKernelWorkGroupSize,
|
||||||
|
SpvOpGetKernelPreferredWorkGroupSizeMultiple,
|
||||||
|
SpvOpGetKernelLocalSizeForSubgroupCount,
|
||||||
|
SpvOpGetKernelMaxNumSubgroups};
|
||||||
|
if (std::find(acceptable.begin(), acceptable.end(), use->opcode()) ==
|
||||||
|
acceptable.end()) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_ID, use)
|
||||||
|
<< "Invalid use of function result id " << _.getIdName(inst->id())
|
||||||
|
<< ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SPV_SUCCESS;
|
return SPV_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,9 +477,10 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceEntryBlock) {
|
|||||||
|
|
||||||
TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) {
|
TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) {
|
||||||
Block entry("entry");
|
Block entry("entry");
|
||||||
|
entry.SetBody("%undef = OpUndef %voidt\n");
|
||||||
Block bad("bad");
|
Block bad("bad");
|
||||||
Block end("end", SpvOpReturn);
|
Block end("end", SpvOpReturn);
|
||||||
Block badvalue("func"); // This referenes the function name.
|
Block badvalue("undef"); // This referenes the OpUndef.
|
||||||
std::string str = header(GetParam()) +
|
std::string str = header(GetParam()) +
|
||||||
nameOps("entry", "bad", std::make_pair("func", "Main")) +
|
nameOps("entry", "bad", std::make_pair("func", "Main")) +
|
||||||
types_consts() +
|
types_consts() +
|
||||||
@ -493,9 +494,8 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) {
|
|||||||
|
|
||||||
CompileSuccessfully(str);
|
CompileSuccessfully(str);
|
||||||
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
|
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
getDiagnosticString(),
|
MatchesRegex("Block\\(s\\) \\{..\\} are referenced but not "
|
||||||
MatchesRegex("Block\\(s\\) \\{.\\[Main\\]\\} are referenced but not "
|
|
||||||
"defined in function .\\[Main\\]\n"
|
"defined in function .\\[Main\\]\n"
|
||||||
" %Main = OpFunction %void None %10\n"))
|
" %Main = OpFunction %void None %10\n"))
|
||||||
<< str;
|
<< str;
|
||||||
|
@ -2192,13 +2192,14 @@ TEST_F(ValidateIdWithMessage, OpStoreObjectGood) {
|
|||||||
%6 = OpVariable %3 UniformConstant
|
%6 = OpVariable %3 UniformConstant
|
||||||
%7 = OpFunction %1 None %4
|
%7 = OpFunction %1 None %4
|
||||||
%8 = OpLabel
|
%8 = OpLabel
|
||||||
OpStore %6 %7
|
%9 = OpUndef %1
|
||||||
|
OpStore %6 %9
|
||||||
OpReturn
|
OpReturn
|
||||||
OpFunctionEnd)";
|
OpFunctionEnd)";
|
||||||
CompileSuccessfully(spirv.c_str());
|
CompileSuccessfully(spirv.c_str());
|
||||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||||
EXPECT_THAT(getDiagnosticString(),
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
HasSubstr("OpStore Object <id> '7's type is void."));
|
HasSubstr("OpStore Object <id> '9's type is void."));
|
||||||
}
|
}
|
||||||
TEST_F(ValidateIdWithMessage, OpStoreTypeBad) {
|
TEST_F(ValidateIdWithMessage, OpStoreTypeBad) {
|
||||||
std::string spirv = kGLSL450MemoryModel + R"(
|
std::string spirv = kGLSL450MemoryModel + R"(
|
||||||
@ -3577,6 +3578,22 @@ OpFunctionEnd)";
|
|||||||
HasSubstr("OpFunction Function Type <id> '2' is not a function type."));
|
HasSubstr("OpFunction Function Type <id> '2' is not a function type."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateIdWithMessage, OpFunctionUseBad) {
|
||||||
|
const std::string spirv = kGLSL450MemoryModel + R"(
|
||||||
|
%1 = OpTypeFloat 32
|
||||||
|
%2 = OpTypeFunction %1
|
||||||
|
%3 = OpFunction %1 None %2
|
||||||
|
%4 = OpLabel
|
||||||
|
OpReturnValue %3
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Invalid use of function result id 3."));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ValidateIdWithMessage, OpFunctionParameterGood) {
|
TEST_F(ValidateIdWithMessage, OpFunctionParameterGood) {
|
||||||
std::string spirv = kGLSL450MemoryModel + R"(
|
std::string spirv = kGLSL450MemoryModel + R"(
|
||||||
%1 = OpTypeVoid
|
%1 = OpTypeVoid
|
||||||
|
Loading…
Reference in New Issue
Block a user