mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-27 05:40:06 +00:00
Add validation for OpBranchConditional
This commit is contained in:
parent
7299fb5b7c
commit
d861ceffd4
@ -2038,11 +2038,47 @@ bool idUsage::isValid<OpBranch>(const spv_instruction_t *inst,
|
||||
const spv_opcode_desc opcodeEntry) {}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
template <>
|
||||
bool idUsage::isValid<OpBranchConditional>(
|
||||
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
|
||||
#endif
|
||||
bool idUsage::isValid<SpvOpBranchConditional>(
|
||||
const spv_instruction_t *inst, const spv_opcode_desc) {
|
||||
const size_t numOperands = inst->words.size() - 1;
|
||||
const size_t condOperandIndex = 1;
|
||||
const size_t targetTrueIndex = 2;
|
||||
const size_t targetFalseIndex = 3;
|
||||
|
||||
// num_operands is either 3 or 5 --- if 5, the last two need to be literal integers
|
||||
if (numOperands != 3 &&
|
||||
numOperands != 5) {
|
||||
DIAG(0) << "OpBranchConditional requires either 3 or 5 parameters";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
|
||||
// grab the condition operand and check that it is a bool
|
||||
const auto condOp = module_.FindDef(inst->words[condOperandIndex]);
|
||||
if (!condOp || !module_.IsBoolScalarType(condOp->type_id())) {
|
||||
DIAG(0) << "Condition operand for OpBranchConditional must be of boolean type";
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// target operands must be OpLabel
|
||||
// note that we don't need to check that the target labels are in the same function,
|
||||
// PerformCfgChecks already checks for that
|
||||
const auto targetOpTrue = module_.FindDef(inst->words[targetTrueIndex]);
|
||||
if (!targetOpTrue || SpvOpLabel != targetOpTrue->opcode()) {
|
||||
DIAG(0) << "The 'True Label' operand for OpBranchConditional must be the ID of an OpLabel instruction";
|
||||
ret = false;
|
||||
}
|
||||
|
||||
const auto targetOpFalse = module_.FindDef(inst->words[targetFalseIndex]);
|
||||
if (!targetOpFalse || SpvOpLabel != targetOpFalse->opcode()) {
|
||||
DIAG(0) << "The 'False Label' operand for OpBranchConditional must be the ID of an OpLabel instruction";
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <>
|
||||
@ -2558,7 +2594,7 @@ bool idUsage::isValid(const spv_instruction_t* inst) {
|
||||
TODO(OpLoopMerge)
|
||||
TODO(OpSelectionMerge)
|
||||
TODO(OpBranch)
|
||||
TODO(OpBranchConditional)
|
||||
CASE(OpBranchConditional)
|
||||
TODO(OpSwitch)
|
||||
CASE(OpReturnValue)
|
||||
TODO(OpLifetimeStart)
|
||||
|
@ -94,6 +94,52 @@ string sampledImageSetup = R"(
|
||||
%sampler_inst = OpLoad %sampler_type %s
|
||||
)";
|
||||
|
||||
string BranchConditionalSetup = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 140
|
||||
OpName %main "main"
|
||||
|
||||
; type definitions
|
||||
%bool = OpTypeBool
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
|
||||
; constants
|
||||
%i0 = OpConstant %int 0
|
||||
%i1 = OpConstant %int 1
|
||||
%f0 = OpConstant %float 0
|
||||
%f1 = OpConstant %float 1
|
||||
|
||||
|
||||
; main function header
|
||||
%void = OpTypeVoid
|
||||
%voidfunc = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfunc
|
||||
%lmain = OpLabel
|
||||
|
||||
OpSelectionMerge %end None
|
||||
)";
|
||||
|
||||
string BranchConditionalTail = R"(
|
||||
%target_t = OpLabel
|
||||
OpNop
|
||||
OpBranch %end
|
||||
%target_f = OpLabel
|
||||
OpNop
|
||||
OpBranch %end
|
||||
|
||||
%end = OpLabel
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// TODO: OpUndef
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpName) {
|
||||
@ -4161,7 +4207,101 @@ TEST_F(ValidateIdWithMessage, OpVectorShuffleLiterals) {
|
||||
// TODO: OpLoopMerge
|
||||
// TODO: OpSelectionMerge
|
||||
// TODO: OpBranch
|
||||
// TODO: OpBranchConditional
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpBranchConditionalGood) {
|
||||
string spirv = BranchConditionalSetup + R"(
|
||||
%branch_cond = OpINotEqual %bool %i0 %i1
|
||||
OpBranchConditional %branch_cond %target_t %target_f
|
||||
)" + BranchConditionalTail;
|
||||
|
||||
CompileSuccessfully(spirv.c_str());
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||
}
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpBranchConditionalWithWeightsGood) {
|
||||
string spirv = BranchConditionalSetup + R"(
|
||||
%branch_cond = OpINotEqual %bool %i0 %i1
|
||||
OpBranchConditional %branch_cond %target_t %target_f 1 1
|
||||
)" + BranchConditionalTail;
|
||||
|
||||
CompileSuccessfully(spirv.c_str());
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||
}
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpBranchConditional_CondIsScalarInt) {
|
||||
string spirv = BranchConditionalSetup + R"(
|
||||
OpBranchConditional %i0 %target_t %target_f
|
||||
)" + BranchConditionalTail;
|
||||
|
||||
CompileSuccessfully(spirv.c_str());
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Condition operand for OpBranchConditional must be of boolean type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpBranchConditional_TrueTargetIsNotLabel) {
|
||||
string spirv = BranchConditionalSetup + R"(
|
||||
OpBranchConditional %i0 %i0 %target_f
|
||||
)" + BranchConditionalTail;
|
||||
|
||||
CompileSuccessfully(spirv.c_str());
|
||||
// EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
// EXPECT_THAT(
|
||||
// getDiagnosticString(),
|
||||
// HasSubstr("The 'True Label' operand for OpBranchConditional must be the ID of an OpLabel instruction"));
|
||||
|
||||
// xxxnsubtil: this is actually caught by the ID validation instead
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("are referenced but not defined in function"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpBranchConditional_FalseTargetIsNotLabel) {
|
||||
string spirv = BranchConditionalSetup + R"(
|
||||
OpBranchConditional %i0 %target_t %i0
|
||||
)" + BranchConditionalTail;
|
||||
|
||||
CompileSuccessfully(spirv.c_str());
|
||||
// EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
// EXPECT_THAT(
|
||||
// getDiagnosticString(),
|
||||
// HasSubstr("The 'False Label' operand for OpBranchConditional must be the ID of an OpLabel instruction"));
|
||||
|
||||
// xxxnsubtil: this is actually caught by the ID validation
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("are referenced but not defined in function"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpBranchConditional_NotEnoughWeights) {
|
||||
string spirv = BranchConditionalSetup + R"(
|
||||
%branch_cond = OpINotEqual %bool %i0 %i1
|
||||
OpBranchConditional %branch_cond %target_t %target_f 1
|
||||
)" + BranchConditionalTail;
|
||||
|
||||
CompileSuccessfully(spirv.c_str());
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpBranchConditional requires either 3 or 5 parameters"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpBranchConditional_TooManyWeights) {
|
||||
string spirv = BranchConditionalSetup + R"(
|
||||
%branch_cond = OpINotEqual %bool %i0 %i1
|
||||
OpBranchConditional %branch_cond %target_t %target_f 1 2 3
|
||||
)" + BranchConditionalTail;
|
||||
|
||||
CompileSuccessfully(spirv.c_str());
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpBranchConditional requires either 3 or 5 parameters"));
|
||||
}
|
||||
|
||||
// TODO: OpSwitch
|
||||
|
||||
TEST_F(ValidateIdWithMessage, OpReturnValueConstantGood) {
|
||||
|
Loading…
Reference in New Issue
Block a user