Add validate logicals pass to the validator

New pass checks operands of all instructions listed under
3.32.15. Relational and Logical Instructions
This commit is contained in:
Andrey Tuganov 2017-09-07 17:27:57 -04:00 committed by David Neto
parent 4e3cc2f57f
commit cf85ad1429
9 changed files with 1196 additions and 38 deletions

View File

@ -255,11 +255,12 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/validate_arithmetics.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_cfg.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_capability.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_id.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_instruction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_datarules.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_decorations.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_id.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_instruction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_layout.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_logicals.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_type_unique.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h
${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp

View File

@ -181,6 +181,7 @@ spv_result_t ProcessInstruction(void* user_data,
if (auto error = InstructionPass(_, inst)) return error;
if (auto error = TypeUniquePass(_, inst)) return error;
if (auto error = ArithmeticsPass(_, inst)) return error;
if (auto error = LogicalsPass(_, inst)) return error;
return SPV_SUCCESS;
}

View File

@ -115,6 +115,10 @@ spv_result_t TypeUniquePass(ValidationState_t& _,
spv_result_t ArithmeticsPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst);
/// Validates correctness of logical instructions.
spv_result_t LogicalsPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst);
// Validates that capability declarations use operands allowed in the current
// context.
spv_result_t CapabilityPass(ValidationState_t& _,

View File

@ -0,0 +1,287 @@
// Copyright (c) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Validates correctness of logical SPIR-V instructions.
#include "validate.h"
#include "diagnostic.h"
#include "opcode.h"
#include "val/instruction.h"
#include "val/validation_state.h"
namespace libspirv {
namespace {
// Returns operand word for given instruction and operand index.
// The operand is expected to only have one word.
inline uint32_t GetOperandWord(const spv_parsed_instruction_t* inst,
size_t operand_index) {
assert(operand_index < inst->num_operands);
const spv_parsed_operand_t& operand = inst->operands[operand_index];
assert(operand.num_words == 1);
return inst->words[operand.offset];
}
// Returns the type id of instruction operand at |operand_index|.
// The operand is expected to be an id.
inline uint32_t GetOperandTypeId(ValidationState_t& _,
const spv_parsed_instruction_t* inst,
size_t operand_index) {
return _.GetTypeId(GetOperandWord(inst, operand_index));
}
}
// Validates correctness of logical instructions.
spv_result_t LogicalsPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
const uint32_t result_type = inst->type_id;
switch (opcode) {
case SpvOpAny:
case SpvOpAll: {
if (!_.IsBoolScalarType(result_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected bool scalar type as Result Type: "
<< spvOpcodeString(opcode);
const uint32_t vector_type = GetOperandTypeId(_, inst, 2);
if (!vector_type || !_.IsBoolVectorType(vector_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected operand to be vector bool: "
<< spvOpcodeString(opcode);
break;
}
case SpvOpIsNan:
case SpvOpIsInf:
case SpvOpIsFinite:
case SpvOpIsNormal:
case SpvOpSignBitSet: {
if (!_.IsBoolScalarType(result_type) &&
!_.IsBoolVectorType(result_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected bool scalar or vector type as Result Type: "
<< spvOpcodeString(opcode);
const uint32_t operand_type = GetOperandTypeId(_, inst, 2);
if (!operand_type || (!_.IsFloatScalarType(operand_type) &&
!_.IsFloatVectorType(operand_type)))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected operand to be scalar or vector float: "
<< spvOpcodeString(opcode);
if (_.GetDimension(result_type) != _.GetDimension(operand_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected vector sizes of Result Type and the operand to be equal: "
<< spvOpcodeString(opcode);
break;
}
case SpvOpFOrdEqual:
case SpvOpFUnordEqual:
case SpvOpFOrdNotEqual:
case SpvOpFUnordNotEqual:
case SpvOpFOrdLessThan:
case SpvOpFUnordLessThan:
case SpvOpFOrdGreaterThan:
case SpvOpFUnordGreaterThan:
case SpvOpFOrdLessThanEqual:
case SpvOpFUnordLessThanEqual:
case SpvOpFOrdGreaterThanEqual:
case SpvOpFUnordGreaterThanEqual:
case SpvOpLessOrGreater:
case SpvOpOrdered:
case SpvOpUnordered: {
if (!_.IsBoolScalarType(result_type) &&
!_.IsBoolVectorType(result_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected bool scalar or vector type as Result Type: "
<< spvOpcodeString(opcode);
const uint32_t left_operand_type = GetOperandTypeId(_, inst, 2);
if (!left_operand_type || (!_.IsFloatScalarType(left_operand_type) &&
!_.IsFloatVectorType(left_operand_type)))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected operands to be scalar or vector float: "
<< spvOpcodeString(opcode);
if (_.GetDimension(result_type) != _.GetDimension(left_operand_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected vector sizes of Result Type and the operands to be equal: "
<< spvOpcodeString(opcode);
if (left_operand_type != GetOperandTypeId(_, inst, 3))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected left and right operands to have the same type: "
<< spvOpcodeString(opcode);
break;
}
case SpvOpLogicalEqual:
case SpvOpLogicalNotEqual:
case SpvOpLogicalOr:
case SpvOpLogicalAnd: {
if (!_.IsBoolScalarType(result_type) &&
!_.IsBoolVectorType(result_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected bool scalar or vector type as Result Type: "
<< spvOpcodeString(opcode);
if (result_type != GetOperandTypeId(_, inst, 2) ||
result_type != GetOperandTypeId(_, inst, 3))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected both operands to be of Result Type: "
<< spvOpcodeString(opcode);
break;
}
case SpvOpLogicalNot: {
if (!_.IsBoolScalarType(result_type) &&
!_.IsBoolVectorType(result_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected bool scalar or vector type as Result Type: "
<< spvOpcodeString(opcode);
if (result_type != GetOperandTypeId(_, inst, 2))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected operand to be of Result Type: "
<< spvOpcodeString(opcode);
break;
}
case SpvOpSelect: {
uint32_t dimension = 1;
{
const Instruction* type_inst = _.FindDef(result_type);
assert(type_inst);
const SpvOp type_opcode = type_inst->opcode();
switch (type_opcode) {
case SpvOpTypePointer: {
if (!_.features().variable_pointers)
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Using pointers with OpSelect requires capability "
<< "VariablePointers";
break;
}
case SpvOpTypeVector: {
dimension = type_inst->word(3);
break;
}
case SpvOpTypeBool:
case SpvOpTypeInt:
case SpvOpTypeFloat: {
break;
}
default: {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected scalar or vector type as Result Type: "
<< spvOpcodeString(opcode);
}
}
}
const uint32_t condition_type = GetOperandTypeId(_, inst, 2);
const uint32_t left_type = GetOperandTypeId(_, inst, 3);
const uint32_t right_type = GetOperandTypeId(_, inst, 4);
if (!condition_type || (!_.IsBoolScalarType(condition_type) &&
!_.IsBoolVectorType(condition_type)))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected bool scalar or vector type as condition: "
<< spvOpcodeString(opcode);
if (_.GetDimension(condition_type) != dimension)
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected vector sizes of Result Type and the condition to be"
<< " equal: " << spvOpcodeString(opcode);
if (result_type != left_type || result_type != right_type)
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected both objects to be of Result Type: "
<< spvOpcodeString(opcode);
break;
}
case SpvOpIEqual:
case SpvOpINotEqual:
case SpvOpUGreaterThan:
case SpvOpUGreaterThanEqual:
case SpvOpULessThan:
case SpvOpULessThanEqual:
case SpvOpSGreaterThan:
case SpvOpSGreaterThanEqual:
case SpvOpSLessThan:
case SpvOpSLessThanEqual: {
if (!_.IsBoolScalarType(result_type) &&
!_.IsBoolVectorType(result_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected bool scalar or vector type as Result Type: "
<< spvOpcodeString(opcode);
const uint32_t left_type = GetOperandTypeId(_, inst, 2);
const uint32_t right_type = GetOperandTypeId(_, inst, 3);
if (!left_type || (!_.IsIntScalarType(left_type) &&
!_.IsIntVectorType(left_type)))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected operands to be scalar or vector int: "
<< spvOpcodeString(opcode);
if (_.GetDimension(result_type) != _.GetDimension(left_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected vector sizes of Result Type and the operands to be"
<< " equal: " << spvOpcodeString(opcode);
if (!right_type || (!_.IsIntScalarType(right_type) &&
!_.IsIntVectorType(right_type)))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected operands to be scalar or vector int: "
<< spvOpcodeString(opcode);
if (_.GetDimension(result_type) != _.GetDimension(right_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected vector sizes of Result Type and the operands to be"
<< " equal: " << spvOpcodeString(opcode);
if (_.GetBitWidth(left_type) != _.GetBitWidth(right_type))
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected both operands to have the same component bit width: "
<< spvOpcodeString(opcode);
break;
}
default:
break;
}
return SPV_SUCCESS;
}
} // namespace libspirv

View File

@ -81,6 +81,12 @@ add_spvtools_unittest(TARGET val_arithmetics
LIBS ${SPIRV_TOOLS}
)
add_spvtools_unittest(TARGET val_logicals
SRCS val_logicals_test.cpp
${VAL_TEST_COMMON_SRCS}
LIBS ${SPIRV_TOOLS}
)
add_spvtools_unittest(TARGET val_limits
SRCS val_limits_test.cpp
${VAL_TEST_COMMON_SRCS}

View File

@ -273,7 +273,7 @@ TEST_P(ValidateCFG, Simple) {
Block cont("cont");
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) {
loop.SetBody("OpLoopMerge %merge %cont None\n");
}
@ -340,7 +340,7 @@ TEST_P(ValidateCFG, BlockSelfLoopIsOk) {
Block loop("loop", SpvOpBranchConditional);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
string str = header(GetParam()) +
@ -364,7 +364,7 @@ TEST_P(ValidateCFG, BlockAppearsBeforeDominatorBad) {
Block branch("branch", SpvOpBranchConditional);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) branch.SetBody("OpSelectionMerge %merge None\n");
string str = header(GetParam()) +
@ -391,7 +391,7 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksBad) {
Block selection("selection", SpvOpBranchConditional);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) loop.SetBody(" OpLoopMerge %merge %loop None\n");
// cannot share the same merge
@ -425,7 +425,7 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksSelectionBad) {
Block selection("selection", SpvOpBranchConditional);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) selection.SetBody(" OpSelectionMerge %merge None\n");
// cannot share the same merge
@ -477,7 +477,7 @@ TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) {
Block bad("bad", SpvOpBranchConditional);
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
bad.SetBody(" OpLoopMerge %entry %exit None\n");
string str = header(GetParam()) +
@ -503,7 +503,7 @@ TEST_P(ValidateCFG, BranchConditionalFalseTargetFirstBlockBad) {
Block merge("merge");
Block end("end", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
bad.SetBody("OpLoopMerge %merge %cont None\n");
string str = header(GetParam()) +
@ -533,7 +533,7 @@ TEST_P(ValidateCFG, SwitchTargetFirstBlockBad) {
Block merge("merge");
Block end("end", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
bad.SetBody("OpSelectionMerge %merge None\n");
string str = header(GetParam()) +
@ -562,7 +562,7 @@ TEST_P(ValidateCFG, BranchToBlockInOtherFunctionBad) {
Block middle("middle", SpvOpBranchConditional);
Block end("end", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
middle.SetBody("OpSelectionMerge %end None\n");
Block entry2("entry2");
@ -599,7 +599,7 @@ TEST_P(ValidateCFG, HeaderDoesntDominatesMergeBad) {
Block f("f");
Block merge("merge", SpvOpReturn);
head.SetBody("%cond = OpSLessThan %intt %one %two\n");
head.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) head.AppendBody("OpSelectionMerge %merge None\n");
@ -633,7 +633,7 @@ TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) {
Block head("head", SpvOpBranchConditional);
Block exit("exit", SpvOpReturn);
head.SetBody("%cond = OpSLessThan %intt %one %two\n");
head.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) head.AppendBody("OpSelectionMerge %head None\n");
@ -666,7 +666,7 @@ TEST_P(ValidateCFG, UnreachableMerge) {
Block f("f", SpvOpReturn);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) branch.AppendBody("OpSelectionMerge %merge None\n");
string str = header(GetParam()) +
@ -692,7 +692,7 @@ TEST_P(ValidateCFG, UnreachableMergeDefinedByOpUnreachable) {
Block f("f", SpvOpReturn);
Block merge("merge", SpvOpUnreachable);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) branch.AppendBody("OpSelectionMerge %merge None\n");
string str = header(GetParam()) +
@ -737,7 +737,7 @@ TEST_P(ValidateCFG, UnreachableBranch) {
Block merge("merge");
Block exit("exit", SpvOpReturn);
unreachable.SetBody("%cond = OpSLessThan %intt %one %two\n");
unreachable.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) unreachable.AppendBody("OpSelectionMerge %merge None\n");
string str = header(GetParam()) +
nameOps("unreachable", "exit", make_pair("func", "Main")) +
@ -772,7 +772,7 @@ TEST_P(ValidateCFG, SingleBlockLoop) {
Block loop("loop", SpvOpBranchConditional);
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) loop.AppendBody("OpLoopMerge %exit %loop None\n");
string str = header(GetParam()) + string(types_consts()) +
@ -798,7 +798,7 @@ TEST_P(ValidateCFG, NestedLoops) {
Block loop1_merge("loop1_merge");
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) {
loop1.SetBody("OpLoopMerge %loop1_merge %loop2 None\n");
loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
@ -828,7 +828,7 @@ TEST_P(ValidateCFG, NestedSelection) {
vector<Block> merge_blocks;
Block inner("inner");
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if_blocks.emplace_back("if0", SpvOpBranchConditional);
@ -871,7 +871,7 @@ TEST_P(ValidateCFG, BackEdgeBlockDoesntPostDominateContinueTargetBad) {
Block be_block("be_block");
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) {
loop1.SetBody("OpLoopMerge %exit %loop2_merge None\n");
loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
@ -909,7 +909,7 @@ TEST_P(ValidateCFG, BranchingToNonLoopHeaderBlockBad) {
Block f("f");
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) split.SetBody("OpSelectionMerge %exit None\n");
string str = header(GetParam()) + nameOps("split", "f") + types_consts() +
@ -940,7 +940,7 @@ TEST_P(ValidateCFG, BranchingToSameNonLoopHeaderBlockBad) {
Block split("split", SpvOpBranchConditional);
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) split.SetBody("OpSelectionMerge %exit None\n");
string str = header(GetParam()) + nameOps("split") + types_consts() +
@ -971,7 +971,7 @@ TEST_P(ValidateCFG, MultipleBackEdgeBlocksToLoopHeaderBad) {
Block back1("back1");
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) loop.SetBody("OpLoopMerge %merge %back0 None\n");
string str = header(GetParam()) + nameOps("loop", "back0", "back1") +
@ -1006,7 +1006,7 @@ TEST_P(ValidateCFG, ContinueTargetMustBePostDominatedByBackEdge) {
Block merge("merge", SpvOpReturn);
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) loop.SetBody("OpLoopMerge %merge %cheader None\n");
string str = header(GetParam()) + nameOps("cheader", "be_block") +
@ -1039,7 +1039,7 @@ TEST_P(ValidateCFG, BranchOutOfConstructToMergeBad) {
Block cont("cont", SpvOpBranchConditional);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
string str = header(GetParam()) + nameOps("cont", "loop") + types_consts() +
@ -1072,7 +1072,7 @@ TEST_P(ValidateCFG, BranchOutOfConstructBad) {
Block merge("merge");
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
string str = header(GetParam()) + nameOps("cont", "loop") + types_consts() +
@ -1216,7 +1216,7 @@ TEST_P(ValidateCFG,
Block inner_merge("inner_merge");
Block exit("exit", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) {
entry.AppendBody("OpSelectionMerge %exit None\n");
inner_head.SetBody("OpSelectionMerge %inner_merge None\n");
@ -1252,7 +1252,7 @@ TEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructureGood) {
Block if_merge("if_merge", SpvOpBranchConditional);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) {
loop.SetBody("OpLoopMerge %merge %if_merge None\n");
if_head.SetBody("OpSelectionMerge %if_merge None\n");
@ -1283,7 +1283,7 @@ TEST_P(ValidateCFG, SingleLatchBlockMultipleBranchesToLoopHeader) {
Block latch("latch", SpvOpBranchConditional);
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) {
loop.SetBody("OpLoopMerge %merge %latch None\n");
}
@ -1315,7 +1315,7 @@ TEST_P(ValidateCFG, SingleLatchBlockHeaderContinueTargetIsItselfGood) {
Block latch("latch");
Block merge("merge", SpvOpReturn);
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
if (is_shader) {
loop.SetBody("OpLoopMerge %merge %loop None\n");
}

View File

@ -1878,7 +1878,9 @@ TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpSelectGood) {
// Without the VariablePointers Capability, OpLoad will not allow loading
// through a variable pointer.
TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpSelectBad) {
// Disabled since using OpSelect with pointers without VariablePointers will
// fail LogicalsPass.
TEST_F(ValidateIdWithMessage, DISABLED_OpLoadVarPtrOpSelectBad) {
std::string result_strategy = R"(
%isneg = OpSLessThan %bool %i %zero
%varptr = OpSelect %f32ptr %isneg %ptr1 %ptr2
@ -2086,7 +2088,9 @@ TEST_F(ValidateIdWithMessage, OpStoreLogicalPointerBad) {
// Without the VariablePointer Capability, OpStore should may not store
// through a variable pointer.
TEST_F(ValidateIdWithMessage, OpStoreVarPtrBad) {
// Disabled since using OpSelect with pointers without VariablePointers will
// fail LogicalsPass.
TEST_F(ValidateIdWithMessage, DISABLED_OpStoreVarPtrBad) {
std::string result_strategy = R"(
%isneg = OpSLessThan %bool %i %zero
%varptr = OpSelect %f32ptr %isneg %ptr1 %ptr2
@ -3134,7 +3138,9 @@ OpFunctionEnd)";
// However, the OpSelect validation does not catch this today. Therefore, it is
// caught by the OpSampledImage validation. If the OpSelect validation code is
// updated, the error message for this test may change.
TEST_F(ValidateIdWithMessage, OpSampledImageUsedInOpSelectBad) {
//
// Disabled since OpSelect catches this now.
TEST_F(ValidateIdWithMessage, DISABLED_OpSampledImageUsedInOpSelectBad) {
string spirv = kGLSL450MemoryModel + sampledImageSetup + R"(
%smpld_img = OpSampledImage %sampled_image_type %image_inst %sampler_inst
%select_img = OpSelect %sampled_image_type %spec_true %smpld_img %smpld_img
@ -3820,7 +3826,9 @@ TEST_F(ValidateIdWithMessage, OpReturnValueVarPtrGood) {
// Without the VariablePointer Capability, the return value of a function is
// *not* allowed to be a pointer.
TEST_F(ValidateIdWithMessage, OpReturnValueVarPtrBad) {
// Disabled since using OpSelect with pointers without VariablePointers will
// fail LogicalsPass.
TEST_F(ValidateIdWithMessage, DISABLED_OpReturnValueVarPtrBad) {
std::ostringstream spirv;
createVariablePointerSpirvProgram(&spirv,
"" /* Instructions to add to "main" */,

View File

@ -0,0 +1,851 @@
// Copyright (c) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Tests for unique type declaration rules validator.
#include <string>
#include "gmock/gmock.h"
#include "unit_spirv.h"
#include "val_fixtures.h"
namespace {
using ::testing::HasSubstr;
using ::testing::Not;
using ValidateLogicals = spvtest::ValidateBase<bool>;
std::string GenerateShaderCode(
const std::string& body,
const std::string& capabilities_and_extensions = "") {
const std::string capabilities =
R"(
OpCapability Shader
OpCapability Int64
OpCapability Float64)";
const std::string after_extension_before_body =
R"(
%ext_inst = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool
%f32 = OpTypeFloat 32
%u32 = OpTypeInt 32 0
%s32 = OpTypeInt 32 1
%f64 = OpTypeFloat 64
%u64 = OpTypeInt 64 0
%s64 = OpTypeInt 64 1
%boolvec2 = OpTypeVector %bool 2
%s32vec2 = OpTypeVector %s32 2
%u32vec2 = OpTypeVector %u32 2
%u64vec2 = OpTypeVector %u64 2
%f32vec2 = OpTypeVector %f32 2
%f64vec2 = OpTypeVector %f64 2
%boolvec3 = OpTypeVector %bool 3
%u32vec3 = OpTypeVector %u32 3
%u64vec3 = OpTypeVector %u64 3
%s32vec3 = OpTypeVector %s32 3
%f32vec3 = OpTypeVector %f32 3
%f64vec3 = OpTypeVector %f64 3
%boolvec4 = OpTypeVector %bool 4
%u32vec4 = OpTypeVector %u32 4
%u64vec4 = OpTypeVector %u64 4
%s32vec4 = OpTypeVector %s32 4
%f32vec4 = OpTypeVector %f32 4
%f64vec4 = OpTypeVector %f64 4
%f32_0 = OpConstant %f32 0
%f32_1 = OpConstant %f32 1
%f32_2 = OpConstant %f32 2
%f32_3 = OpConstant %f32 3
%f32_4 = OpConstant %f32 4
%s32_0 = OpConstant %s32 0
%s32_1 = OpConstant %s32 1
%s32_2 = OpConstant %s32 2
%s32_3 = OpConstant %s32 3
%s32_4 = OpConstant %s32 4
%s32_m1 = OpConstant %s32 -1
%u32_0 = OpConstant %u32 0
%u32_1 = OpConstant %u32 1
%u32_2 = OpConstant %u32 2
%u32_3 = OpConstant %u32 3
%u32_4 = OpConstant %u32 4
%f64_0 = OpConstant %f64 0
%f64_1 = OpConstant %f64 1
%f64_2 = OpConstant %f64 2
%f64_3 = OpConstant %f64 3
%f64_4 = OpConstant %f64 4
%s64_0 = OpConstant %s64 0
%s64_1 = OpConstant %s64 1
%s64_2 = OpConstant %s64 2
%s64_3 = OpConstant %s64 3
%s64_4 = OpConstant %s64 4
%s64_m1 = OpConstant %s64 -1
%u64_0 = OpConstant %u64 0
%u64_1 = OpConstant %u64 1
%u64_2 = OpConstant %u64 2
%u64_3 = OpConstant %u64 3
%u64_4 = OpConstant %u64 4
%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2
%u32vec3_012 = OpConstantComposite %u32vec3 %u32_0 %u32_1 %u32_2
%u32vec3_123 = OpConstantComposite %u32vec3 %u32_1 %u32_2 %u32_3
%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
%u32vec4_1234 = OpConstantComposite %u32vec4 %u32_1 %u32_2 %u32_3 %u32_4
%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1
%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2
%s32vec3_012 = OpConstantComposite %s32vec3 %s32_0 %s32_1 %s32_2
%s32vec3_123 = OpConstantComposite %s32vec3 %s32_1 %s32_2 %s32_3
%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3
%s32vec4_1234 = OpConstantComposite %s32vec4 %s32_1 %s32_2 %s32_3 %s32_4
%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1
%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2
%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2
%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3
%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4
%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1
%f64vec2_12 = OpConstantComposite %f64vec2 %f64_1 %f64_2
%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2
%f64vec3_123 = OpConstantComposite %f64vec3 %f64_1 %f64_2 %f64_3
%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3
%f64vec4_1234 = OpConstantComposite %f64vec4 %f64_1 %f64_2 %f64_3 %f64_4
%true = OpConstantTrue %bool
%false = OpConstantFalse %bool
%boolvec2_tf = OpConstantComposite %boolvec2 %true %false
%boolvec3_tft = OpConstantComposite %boolvec3 %true %false %true
%boolvec4_tftf = OpConstantComposite %boolvec4 %true %false %true %false
%f32vec4ptr = OpTypePointer Function %f32vec4
%main = OpFunction %void None %func
%main_entry = OpLabel)";
const std::string after_body =
R"(
OpReturn
OpFunctionEnd)";
return capabilities + capabilities_and_extensions +
after_extension_before_body + body + after_body;
}
std::string GenerateKernelCode(
const std::string& body,
const std::string& capabilities_and_extensions = "") {
const std::string capabilities =
R"(
OpCapability Addresses
OpCapability Kernel
OpCapability Linkage
OpCapability Int64
OpCapability Float64)";
const std::string after_extension_before_body =
R"(
OpMemoryModel Physical32 OpenCL
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool
%f32 = OpTypeFloat 32
%u32 = OpTypeInt 32 0
%f64 = OpTypeFloat 64
%u64 = OpTypeInt 64 0
%boolvec2 = OpTypeVector %bool 2
%u32vec2 = OpTypeVector %u32 2
%u64vec2 = OpTypeVector %u64 2
%f32vec2 = OpTypeVector %f32 2
%f64vec2 = OpTypeVector %f64 2
%boolvec3 = OpTypeVector %bool 3
%u32vec3 = OpTypeVector %u32 3
%u64vec3 = OpTypeVector %u64 3
%f32vec3 = OpTypeVector %f32 3
%f64vec3 = OpTypeVector %f64 3
%boolvec4 = OpTypeVector %bool 4
%u32vec4 = OpTypeVector %u32 4
%u64vec4 = OpTypeVector %u64 4
%f32vec4 = OpTypeVector %f32 4
%f64vec4 = OpTypeVector %f64 4
%f32_0 = OpConstant %f32 0
%f32_1 = OpConstant %f32 1
%f32_2 = OpConstant %f32 2
%f32_3 = OpConstant %f32 3
%f32_4 = OpConstant %f32 4
%u32_0 = OpConstant %u32 0
%u32_1 = OpConstant %u32 1
%u32_2 = OpConstant %u32 2
%u32_3 = OpConstant %u32 3
%u32_4 = OpConstant %u32 4
%f64_0 = OpConstant %f64 0
%f64_1 = OpConstant %f64 1
%f64_2 = OpConstant %f64 2
%f64_3 = OpConstant %f64 3
%f64_4 = OpConstant %f64 4
%u64_0 = OpConstant %u64 0
%u64_1 = OpConstant %u64 1
%u64_2 = OpConstant %u64 2
%u64_3 = OpConstant %u64 3
%u64_4 = OpConstant %u64 4
%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2
%u32vec3_012 = OpConstantComposite %u32vec3 %u32_0 %u32_1 %u32_2
%u32vec3_123 = OpConstantComposite %u32vec3 %u32_1 %u32_2 %u32_3
%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
%u32vec4_1234 = OpConstantComposite %u32vec4 %u32_1 %u32_2 %u32_3 %u32_4
%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1
%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2
%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2
%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3
%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4
%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1
%f64vec2_12 = OpConstantComposite %f64vec2 %f64_1 %f64_2
%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2
%f64vec3_123 = OpConstantComposite %f64vec3 %f64_1 %f64_2 %f64_3
%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3
%f64vec4_1234 = OpConstantComposite %f64vec4 %f64_1 %f64_2 %f64_3 %f64_4
%true = OpConstantTrue %bool
%false = OpConstantFalse %bool
%boolvec2_tf = OpConstantComposite %boolvec2 %true %false
%boolvec3_tft = OpConstantComposite %boolvec3 %true %false %true
%boolvec4_tftf = OpConstantComposite %boolvec4 %true %false %true %false
%f32vec4ptr = OpTypePointer Function %f32vec4
%main = OpFunction %void None %func
%main_entry = OpLabel)";
const std::string after_body =
R"(
OpReturn
OpFunctionEnd)";
return capabilities + capabilities_and_extensions +
after_extension_before_body + body + after_body;
}
TEST_F(ValidateLogicals, OpAnySuccess) {
const std::string body = R"(
%val1 = OpAny %bool %boolvec2_tf
%val2 = OpAny %bool %boolvec3_tft
%val3 = OpAny %bool %boolvec4_tftf
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpAnyWrongTypeId) {
const std::string body = R"(
%val = OpAny %u32 %boolvec2_tf
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar type as Result Type: Any"));
}
TEST_F(ValidateLogicals, OpAnyWrongOperand) {
const std::string body = R"(
%val = OpAny %bool %u32vec3_123
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operand to be vector bool: Any"));
}
TEST_F(ValidateLogicals, OpIsNanSuccess) {
const std::string body = R"(
%val1 = OpIsNan %bool %f32_1
%val2 = OpIsNan %bool %f64_0
%val3 = OpIsNan %boolvec2 %f32vec2_12
%val4 = OpIsNan %boolvec3 %f32vec3_123
%val5 = OpIsNan %boolvec4 %f32vec4_1234
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpIsNanWrongTypeId) {
const std::string body = R"(
%val1 = OpIsNan %u32 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: IsNan"));
}
TEST_F(ValidateLogicals, OpIsNanOperandNotFloat) {
const std::string body = R"(
%val1 = OpIsNan %bool %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operand to be scalar or vector float: IsNan"));
}
TEST_F(ValidateLogicals, OpIsNanOperandWrongSize) {
const std::string body = R"(
%val1 = OpIsNan %bool %f32vec2_12
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected vector sizes of Result Type and the operand to be equal: "
"IsNan"));
}
TEST_F(ValidateLogicals, OpLessOrGreaterSuccess) {
const std::string body = R"(
%val1 = OpLessOrGreater %bool %f32_0 %f32_1
%val2 = OpLessOrGreater %bool %f64_0 %f64_0
%val3 = OpLessOrGreater %boolvec2 %f32vec2_12 %f32vec2_12
%val4 = OpLessOrGreater %boolvec3 %f32vec3_123 %f32vec3_123
%val5 = OpLessOrGreater %boolvec4 %f32vec4_1234 %f32vec4_1234
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpLessOrGreaterWrongTypeId) {
const std::string body = R"(
%val1 = OpLessOrGreater %u32 %f32_1 %f32_1
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: LessOrGreater"));
}
TEST_F(ValidateLogicals, OpLessOrGreaterLeftOperandNotFloat) {
const std::string body = R"(
%val1 = OpLessOrGreater %bool %u32_1 %f32_1
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector float: LessOrGreater"));
}
TEST_F(ValidateLogicals, OpLessOrGreaterLeftOperandWrongSize) {
const std::string body = R"(
%val1 = OpLessOrGreater %bool %f32vec2_12 %f32_1
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected vector sizes of Result Type and the operands to be equal: "
"LessOrGreater"));
}
TEST_F(ValidateLogicals, OpLessOrGreaterOperandsDifferentType) {
const std::string body = R"(
%val1 = OpLessOrGreater %bool %f32_1 %f64_1
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected left and right operands to have the same type: "
"LessOrGreater"));
}
TEST_F(ValidateLogicals, OpFOrdEqualSuccess) {
const std::string body = R"(
%val1 = OpFOrdEqual %bool %f32_0 %f32_1
%val2 = OpFOrdEqual %bool %f64_0 %f64_0
%val3 = OpFOrdEqual %boolvec2 %f32vec2_12 %f32vec2_12
%val4 = OpFOrdEqual %boolvec3 %f32vec3_123 %f32vec3_123
%val5 = OpFOrdEqual %boolvec4 %f32vec4_1234 %f32vec4_1234
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpFOrdEqualWrongTypeId) {
const std::string body = R"(
%val1 = OpFOrdEqual %u32 %f32_1 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: FOrdEqual"));
}
TEST_F(ValidateLogicals, OpFOrdEqualLeftOperandNotFloat) {
const std::string body = R"(
%val1 = OpFOrdEqual %bool %u32_1 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector float: FOrdEqual"));
}
TEST_F(ValidateLogicals, OpFOrdEqualLeftOperandWrongSize) {
const std::string body = R"(
%val1 = OpFOrdEqual %bool %f32vec2_12 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected vector sizes of Result Type and the operands to be equal: "
"FOrdEqual"));
}
TEST_F(ValidateLogicals, OpFOrdEqualOperandsDifferentType) {
const std::string body = R"(
%val1 = OpFOrdEqual %bool %f32_1 %f64_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected left and right operands to have the same type: "
"FOrdEqual"));
}
TEST_F(ValidateLogicals, OpLogicalEqualSuccess) {
const std::string body = R"(
%val1 = OpLogicalEqual %bool %true %false
%val2 = OpLogicalEqual %boolvec2 %boolvec2_tf %boolvec2_tf
%val3 = OpLogicalEqual %boolvec3 %boolvec3_tft %boolvec3_tft
%val4 = OpLogicalEqual %boolvec4 %boolvec4_tftf %boolvec4_tftf
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpLogicalEqualWrongTypeId) {
const std::string body = R"(
%val1 = OpLogicalEqual %u32 %true %false
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: LogicalEqual"));
}
TEST_F(ValidateLogicals, OpLogicalEqualWrongLeftOperand) {
const std::string body = R"(
%val1 = OpLogicalEqual %bool %boolvec2_tf %false
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected both operands to be of Result Type: LogicalEqual"));
}
TEST_F(ValidateLogicals, OpLogicalEqualWrongRightOperand) {
const std::string body = R"(
%val1 = OpLogicalEqual %boolvec2 %boolvec2_tf %false
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected both operands to be of Result Type: LogicalEqual"));
}
TEST_F(ValidateLogicals, OpLogicalNotSuccess) {
const std::string body = R"(
%val1 = OpLogicalNot %bool %true
%val2 = OpLogicalNot %boolvec2 %boolvec2_tf
%val3 = OpLogicalNot %boolvec3 %boolvec3_tft
%val4 = OpLogicalNot %boolvec4 %boolvec4_tftf
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpLogicalNotWrongTypeId) {
const std::string body = R"(
%val1 = OpLogicalNot %u32 %true
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: LogicalNot"));
}
TEST_F(ValidateLogicals, OpLogicalNotWrongOperand) {
const std::string body = R"(
%val1 = OpLogicalNot %bool %boolvec2_tf
)";
CompileSuccessfully(GenerateKernelCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operand to be of Result Type: LogicalNot"));
}
TEST_F(ValidateLogicals, OpSelectSuccess) {
const std::string body = R"(
%val1 = OpSelect %u32 %true %u32_0 %u32_1
%val2 = OpSelect %f32 %true %f32_0 %f32_1
%val3 = OpSelect %f64 %true %f64_0 %f64_1
%val4 = OpSelect %f32vec2 %boolvec2_tf %f32vec2_01 %f32vec2_12
%val5 = OpSelect %f32vec4 %boolvec4_tftf %f32vec4_0123 %f32vec4_1234
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpSelectWrongTypeId) {
const std::string body = R"(
%val1 = OpSelect %void %true %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected scalar or vector type as Result Type: Select"));
}
TEST_F(ValidateLogicals, OpSelectPointerNoCapability) {
const std::string body = R"(
%x = OpVariable %f32vec4ptr Function
%y = OpVariable %f32vec4ptr Function
OpStore %x %f32vec4_0123
OpStore %y %f32vec4_1234
%val1 = OpSelect %f32vec4ptr %true %x %y
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Using pointers with OpSelect requires capability VariablePointers"));
}
TEST_F(ValidateLogicals, OpSelectPointerWithCapability) {
const std::string body = R"(
%x = OpVariable %f32vec4ptr Function
%y = OpVariable %f32vec4ptr Function
OpStore %x %f32vec4_0123
OpStore %y %f32vec4_1234
%val1 = OpSelect %f32vec4ptr %true %x %y
)";
const std::string extra_cap_ext = R"(
OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
)";
CompileSuccessfully(GenerateShaderCode(body, extra_cap_ext).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpSelectWrongCondition) {
const std::string body = R"(
%val1 = OpSelect %u32 %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as condition: Select"));
}
TEST_F(ValidateLogicals, OpSelectWrongConditionDimension) {
const std::string body = R"(
%val1 = OpSelect %u32vec2 %true %u32vec2_01 %u32vec2_12
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected vector sizes of Result Type and the condition to be equal: "
"Select"));
}
TEST_F(ValidateLogicals, OpSelectWrongLeftObject) {
const std::string body = R"(
%val1 = OpSelect %bool %true %u32vec2_01 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected both objects to be of Result Type: Select"));
}
TEST_F(ValidateLogicals, OpSelectWrongRightObject) {
const std::string body = R"(
%val1 = OpSelect %bool %true %u32_1 %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected both objects to be of Result Type: Select"));
}
TEST_F(ValidateLogicals, OpIEqualSuccess) {
const std::string body = R"(
%val1 = OpIEqual %bool %u32_0 %s32_1
%val2 = OpIEqual %bool %s64_0 %u64_0
%val3 = OpIEqual %boolvec2 %s32vec2_12 %u32vec2_12
%val4 = OpIEqual %boolvec3 %s32vec3_123 %u32vec3_123
%val5 = OpIEqual %boolvec4 %s32vec4_1234 %u32vec4_1234
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpIEqualWrongTypeId) {
const std::string body = R"(
%val1 = OpIEqual %u32 %s32_1 %s32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: IEqual"));
}
TEST_F(ValidateLogicals, OpIEqualLeftOperandNotInt) {
const std::string body = R"(
%val1 = OpIEqual %bool %f32_1 %s32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector int: IEqual"));
}
TEST_F(ValidateLogicals, OpIEqualLeftOperandWrongSize) {
const std::string body = R"(
%val1 = OpIEqual %bool %s32vec2_12 %s32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected vector sizes of Result Type and the operands to be equal: "
"IEqual"));
}
TEST_F(ValidateLogicals, OpIEqualRightOperandNotInt) {
const std::string body = R"(
%val1 = OpIEqual %bool %u32_1 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector int: IEqual"));
}
TEST_F(ValidateLogicals, OpIEqualDifferentBitWidth) {
const std::string body = R"(
%val1 = OpIEqual %bool %u32_1 %u64_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected both operands to have the same component bit width: IEqual"));
}
TEST_F(ValidateLogicals, OpUGreaterThanSuccess) {
const std::string body = R"(
%val1 = OpUGreaterThan %bool %u32_0 %u32_1
%val2 = OpUGreaterThan %bool %s32_0 %u32_1
%val3 = OpUGreaterThan %bool %u64_0 %u64_0
%val4 = OpUGreaterThan %bool %u64_0 %s64_0
%val5 = OpUGreaterThan %boolvec2 %u32vec2_12 %u32vec2_12
%val6 = OpUGreaterThan %boolvec3 %s32vec3_123 %u32vec3_123
%val7 = OpUGreaterThan %boolvec4 %u32vec4_1234 %u32vec4_1234
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpUGreaterThanWrongTypeId) {
const std::string body = R"(
%val1 = OpUGreaterThan %u32 %u32_1 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: UGreaterThan"));
}
TEST_F(ValidateLogicals, OpUGreaterThanLeftOperandNotInt) {
const std::string body = R"(
%val1 = OpUGreaterThan %bool %f32_1 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector int: UGreaterThan"));
}
TEST_F(ValidateLogicals, OpUGreaterThanLeftOperandWrongSize) {
const std::string body = R"(
%val1 = OpUGreaterThan %bool %u32vec2_12 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected vector sizes of Result Type and the operands to be equal: "
"UGreaterThan"));
}
TEST_F(ValidateLogicals, OpUGreaterThanRightOperandNotInt) {
const std::string body = R"(
%val1 = OpUGreaterThan %bool %u32_1 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector int: UGreaterThan"));
}
TEST_F(ValidateLogicals, OpUGreaterThanDifferentBitWidth) {
const std::string body = R"(
%val1 = OpUGreaterThan %bool %u32_1 %u64_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected both operands to have the same component bit width: "
"UGreaterThan"));
}
TEST_F(ValidateLogicals, OpSGreaterThanSuccess) {
const std::string body = R"(
%val1 = OpSGreaterThan %bool %s32_0 %s32_1
%val2 = OpSGreaterThan %bool %u32_0 %s32_1
%val3 = OpSGreaterThan %bool %s64_0 %s64_0
%val4 = OpSGreaterThan %bool %s64_0 %u64_0
%val5 = OpSGreaterThan %boolvec2 %s32vec2_12 %s32vec2_12
%val6 = OpSGreaterThan %boolvec3 %s32vec3_123 %u32vec3_123
%val7 = OpSGreaterThan %boolvec4 %s32vec4_1234 %s32vec4_1234
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLogicals, OpSGreaterThanWrongTypeId) {
const std::string body = R"(
%val1 = OpSGreaterThan %s32 %s32_1 %s32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected bool scalar or vector type as Result Type: SGreaterThan"));
}
TEST_F(ValidateLogicals, OpSGreaterThanLeftOperandNotInt) {
const std::string body = R"(
%val1 = OpSGreaterThan %bool %f32_1 %s32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector int: SGreaterThan"));
}
TEST_F(ValidateLogicals, OpSGreaterThanLeftOperandWrongSize) {
const std::string body = R"(
%val1 = OpSGreaterThan %bool %s32vec2_12 %s32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected vector sizes of Result Type and the operands to be equal: "
"SGreaterThan"));
}
TEST_F(ValidateLogicals, OpSGreaterThanRightOperandNotInt) {
const std::string body = R"(
%val1 = OpSGreaterThan %bool %s32_1 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected operands to be scalar or vector int: SGreaterThan"));
}
TEST_F(ValidateLogicals, OpSGreaterThanDifferentBitWidth) {
const std::string body = R"(
%val1 = OpSGreaterThan %bool %s32_1 %s64_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Expected both operands to have the same component bit width: SGreaterThan"));
}
} // anonymous namespace

View File

@ -1080,7 +1080,7 @@ TEST_F(ValidateSSA, IdDominatesItsUseGood) {
R"(
%func = OpFunction %voidt None %vfunct
%entry = OpLabel
%cond = OpSLessThan %uintt %one %ten
%cond = OpSLessThan %boolt %one %ten
%eleven = OpIAdd %uintt %one %ten
OpSelectionMerge %merge None
OpBranchConditional %cond %t %f
@ -1108,7 +1108,7 @@ TEST_F(ValidateSSA, IdDoesNotDominateItsUseBad) {
R"(
%func = OpFunction %voidt None %vfunct
%entry = OpLabel
%cond = OpSLessThan %uintt %one %ten
%cond = OpSLessThan %boolt %one %ten
OpSelectionMerge %merge None
OpBranchConditional %cond %true_block %false_block
%true_block = OpLabel
@ -1140,7 +1140,7 @@ TEST_F(ValidateSSA, PhiUseDoesntDominateDefinitionGood) {
OpBranch %loop
%loop = OpLabel
%i = OpPhi %uintt %one_val %entry %inew %cont
%cond = OpSLessThan %uintt %one %ten
%cond = OpSLessThan %boolt %one %ten
OpLoopMerge %merge %cont None
OpBranchConditional %cond %body %merge
%body = OpLabel
@ -1169,7 +1169,7 @@ TEST_F(ValidateSSA,
%loop = OpLabel
%i = OpPhi %uintt %one_val %entry %inew %cont
%bad = OpIAdd %uintt %inew %one
%cond = OpSLessThan %uintt %one %ten
%cond = OpSLessThan %boolt %one %ten
OpLoopMerge %merge %cont None
OpBranchConditional %cond %body %merge
%body = OpLabel