mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-30 06:50:06 +00:00
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:
parent
4e3cc2f57f
commit
cf85ad1429
@ -255,11 +255,12 @@ set(SPIRV_SOURCES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_arithmetics.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/validate_arithmetics.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_cfg.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/validate_cfg.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_capability.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_datarules.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_decorations.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_layout.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/validate_logicals.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_type_unique.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/validate_type_unique.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h
|
${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp
|
||||||
|
@ -181,6 +181,7 @@ spv_result_t ProcessInstruction(void* user_data,
|
|||||||
if (auto error = InstructionPass(_, inst)) return error;
|
if (auto error = InstructionPass(_, inst)) return error;
|
||||||
if (auto error = TypeUniquePass(_, inst)) return error;
|
if (auto error = TypeUniquePass(_, inst)) return error;
|
||||||
if (auto error = ArithmeticsPass(_, inst)) return error;
|
if (auto error = ArithmeticsPass(_, inst)) return error;
|
||||||
|
if (auto error = LogicalsPass(_, inst)) return error;
|
||||||
|
|
||||||
return SPV_SUCCESS;
|
return SPV_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,10 @@ spv_result_t TypeUniquePass(ValidationState_t& _,
|
|||||||
spv_result_t ArithmeticsPass(ValidationState_t& _,
|
spv_result_t ArithmeticsPass(ValidationState_t& _,
|
||||||
const spv_parsed_instruction_t* inst);
|
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
|
// Validates that capability declarations use operands allowed in the current
|
||||||
// context.
|
// context.
|
||||||
spv_result_t CapabilityPass(ValidationState_t& _,
|
spv_result_t CapabilityPass(ValidationState_t& _,
|
||||||
|
287
source/validate_logicals.cpp
Normal file
287
source/validate_logicals.cpp
Normal 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
|
@ -81,6 +81,12 @@ add_spvtools_unittest(TARGET val_arithmetics
|
|||||||
LIBS ${SPIRV_TOOLS}
|
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
|
add_spvtools_unittest(TARGET val_limits
|
||||||
SRCS val_limits_test.cpp
|
SRCS val_limits_test.cpp
|
||||||
${VAL_TEST_COMMON_SRCS}
|
${VAL_TEST_COMMON_SRCS}
|
||||||
|
@ -273,7 +273,7 @@ TEST_P(ValidateCFG, Simple) {
|
|||||||
Block cont("cont");
|
Block cont("cont");
|
||||||
Block merge("merge", SpvOpReturn);
|
Block merge("merge", SpvOpReturn);
|
||||||
|
|
||||||
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
|
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
|
||||||
if (is_shader) {
|
if (is_shader) {
|
||||||
loop.SetBody("OpLoopMerge %merge %cont None\n");
|
loop.SetBody("OpLoopMerge %merge %cont None\n");
|
||||||
}
|
}
|
||||||
@ -340,7 +340,7 @@ TEST_P(ValidateCFG, BlockSelfLoopIsOk) {
|
|||||||
Block loop("loop", SpvOpBranchConditional);
|
Block loop("loop", SpvOpBranchConditional);
|
||||||
Block merge("merge", SpvOpReturn);
|
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");
|
if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
@ -364,7 +364,7 @@ TEST_P(ValidateCFG, BlockAppearsBeforeDominatorBad) {
|
|||||||
Block branch("branch", SpvOpBranchConditional);
|
Block branch("branch", SpvOpBranchConditional);
|
||||||
Block merge("merge", 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.SetBody("OpSelectionMerge %merge None\n");
|
if (is_shader) branch.SetBody("OpSelectionMerge %merge None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
@ -391,7 +391,7 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksBad) {
|
|||||||
Block selection("selection", SpvOpBranchConditional);
|
Block selection("selection", SpvOpBranchConditional);
|
||||||
Block merge("merge", SpvOpReturn);
|
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");
|
if (is_shader) loop.SetBody(" OpLoopMerge %merge %loop None\n");
|
||||||
|
|
||||||
// cannot share the same merge
|
// cannot share the same merge
|
||||||
@ -425,7 +425,7 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksSelectionBad) {
|
|||||||
Block selection("selection", SpvOpBranchConditional);
|
Block selection("selection", SpvOpBranchConditional);
|
||||||
Block merge("merge", SpvOpReturn);
|
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");
|
if (is_shader) selection.SetBody(" OpSelectionMerge %merge None\n");
|
||||||
|
|
||||||
// cannot share the same merge
|
// cannot share the same merge
|
||||||
@ -477,7 +477,7 @@ TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) {
|
|||||||
Block bad("bad", SpvOpBranchConditional);
|
Block bad("bad", SpvOpBranchConditional);
|
||||||
Block exit("exit", SpvOpReturn);
|
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");
|
bad.SetBody(" OpLoopMerge %entry %exit None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
@ -503,7 +503,7 @@ TEST_P(ValidateCFG, BranchConditionalFalseTargetFirstBlockBad) {
|
|||||||
Block merge("merge");
|
Block merge("merge");
|
||||||
Block end("end", SpvOpReturn);
|
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");
|
bad.SetBody("OpLoopMerge %merge %cont None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
@ -533,7 +533,7 @@ TEST_P(ValidateCFG, SwitchTargetFirstBlockBad) {
|
|||||||
Block merge("merge");
|
Block merge("merge");
|
||||||
Block end("end", SpvOpReturn);
|
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");
|
bad.SetBody("OpSelectionMerge %merge None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
@ -562,7 +562,7 @@ TEST_P(ValidateCFG, BranchToBlockInOtherFunctionBad) {
|
|||||||
Block middle("middle", SpvOpBranchConditional);
|
Block middle("middle", SpvOpBranchConditional);
|
||||||
Block end("end", SpvOpReturn);
|
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");
|
middle.SetBody("OpSelectionMerge %end None\n");
|
||||||
|
|
||||||
Block entry2("entry2");
|
Block entry2("entry2");
|
||||||
@ -599,7 +599,7 @@ TEST_P(ValidateCFG, HeaderDoesntDominatesMergeBad) {
|
|||||||
Block f("f");
|
Block f("f");
|
||||||
Block merge("merge", SpvOpReturn);
|
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");
|
if (is_shader) head.AppendBody("OpSelectionMerge %merge None\n");
|
||||||
|
|
||||||
@ -633,7 +633,7 @@ TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) {
|
|||||||
Block head("head", SpvOpBranchConditional);
|
Block head("head", SpvOpBranchConditional);
|
||||||
Block exit("exit", SpvOpReturn);
|
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");
|
if (is_shader) head.AppendBody("OpSelectionMerge %head None\n");
|
||||||
|
|
||||||
@ -666,7 +666,7 @@ TEST_P(ValidateCFG, UnreachableMerge) {
|
|||||||
Block f("f", SpvOpReturn);
|
Block f("f", SpvOpReturn);
|
||||||
Block merge("merge", 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");
|
if (is_shader) branch.AppendBody("OpSelectionMerge %merge None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
@ -692,7 +692,7 @@ TEST_P(ValidateCFG, UnreachableMergeDefinedByOpUnreachable) {
|
|||||||
Block f("f", SpvOpReturn);
|
Block f("f", SpvOpReturn);
|
||||||
Block merge("merge", SpvOpUnreachable);
|
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");
|
if (is_shader) branch.AppendBody("OpSelectionMerge %merge None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
@ -737,7 +737,7 @@ TEST_P(ValidateCFG, UnreachableBranch) {
|
|||||||
Block merge("merge");
|
Block merge("merge");
|
||||||
Block exit("exit", SpvOpReturn);
|
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");
|
if (is_shader) unreachable.AppendBody("OpSelectionMerge %merge None\n");
|
||||||
string str = header(GetParam()) +
|
string str = header(GetParam()) +
|
||||||
nameOps("unreachable", "exit", make_pair("func", "Main")) +
|
nameOps("unreachable", "exit", make_pair("func", "Main")) +
|
||||||
@ -772,7 +772,7 @@ TEST_P(ValidateCFG, SingleBlockLoop) {
|
|||||||
Block loop("loop", SpvOpBranchConditional);
|
Block loop("loop", SpvOpBranchConditional);
|
||||||
Block exit("exit", 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.AppendBody("OpLoopMerge %exit %loop None\n");
|
if (is_shader) loop.AppendBody("OpLoopMerge %exit %loop None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) + string(types_consts()) +
|
string str = header(GetParam()) + string(types_consts()) +
|
||||||
@ -798,7 +798,7 @@ TEST_P(ValidateCFG, NestedLoops) {
|
|||||||
Block loop1_merge("loop1_merge");
|
Block loop1_merge("loop1_merge");
|
||||||
Block exit("exit", SpvOpReturn);
|
Block exit("exit", SpvOpReturn);
|
||||||
|
|
||||||
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
|
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
|
||||||
if (is_shader) {
|
if (is_shader) {
|
||||||
loop1.SetBody("OpLoopMerge %loop1_merge %loop2 None\n");
|
loop1.SetBody("OpLoopMerge %loop1_merge %loop2 None\n");
|
||||||
loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
|
loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
|
||||||
@ -828,7 +828,7 @@ TEST_P(ValidateCFG, NestedSelection) {
|
|||||||
vector<Block> merge_blocks;
|
vector<Block> merge_blocks;
|
||||||
Block inner("inner");
|
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);
|
if_blocks.emplace_back("if0", SpvOpBranchConditional);
|
||||||
|
|
||||||
@ -871,7 +871,7 @@ TEST_P(ValidateCFG, BackEdgeBlockDoesntPostDominateContinueTargetBad) {
|
|||||||
Block be_block("be_block");
|
Block be_block("be_block");
|
||||||
Block exit("exit", SpvOpReturn);
|
Block exit("exit", SpvOpReturn);
|
||||||
|
|
||||||
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
|
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
|
||||||
if (is_shader) {
|
if (is_shader) {
|
||||||
loop1.SetBody("OpLoopMerge %exit %loop2_merge None\n");
|
loop1.SetBody("OpLoopMerge %exit %loop2_merge None\n");
|
||||||
loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
|
loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
|
||||||
@ -909,7 +909,7 @@ TEST_P(ValidateCFG, BranchingToNonLoopHeaderBlockBad) {
|
|||||||
Block f("f");
|
Block f("f");
|
||||||
Block exit("exit", SpvOpReturn);
|
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");
|
if (is_shader) split.SetBody("OpSelectionMerge %exit None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) + nameOps("split", "f") + types_consts() +
|
string str = header(GetParam()) + nameOps("split", "f") + types_consts() +
|
||||||
@ -940,7 +940,7 @@ TEST_P(ValidateCFG, BranchingToSameNonLoopHeaderBlockBad) {
|
|||||||
Block split("split", SpvOpBranchConditional);
|
Block split("split", SpvOpBranchConditional);
|
||||||
Block exit("exit", SpvOpReturn);
|
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");
|
if (is_shader) split.SetBody("OpSelectionMerge %exit None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) + nameOps("split") + types_consts() +
|
string str = header(GetParam()) + nameOps("split") + types_consts() +
|
||||||
@ -971,7 +971,7 @@ TEST_P(ValidateCFG, MultipleBackEdgeBlocksToLoopHeaderBad) {
|
|||||||
Block back1("back1");
|
Block back1("back1");
|
||||||
Block merge("merge", SpvOpReturn);
|
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");
|
if (is_shader) loop.SetBody("OpLoopMerge %merge %back0 None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) + nameOps("loop", "back0", "back1") +
|
string str = header(GetParam()) + nameOps("loop", "back0", "back1") +
|
||||||
@ -1006,7 +1006,7 @@ TEST_P(ValidateCFG, ContinueTargetMustBePostDominatedByBackEdge) {
|
|||||||
Block merge("merge", SpvOpReturn);
|
Block merge("merge", SpvOpReturn);
|
||||||
Block exit("exit", 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");
|
if (is_shader) loop.SetBody("OpLoopMerge %merge %cheader None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) + nameOps("cheader", "be_block") +
|
string str = header(GetParam()) + nameOps("cheader", "be_block") +
|
||||||
@ -1039,7 +1039,7 @@ TEST_P(ValidateCFG, BranchOutOfConstructToMergeBad) {
|
|||||||
Block cont("cont", SpvOpBranchConditional);
|
Block cont("cont", SpvOpBranchConditional);
|
||||||
Block merge("merge", SpvOpReturn);
|
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");
|
if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) + nameOps("cont", "loop") + types_consts() +
|
string str = header(GetParam()) + nameOps("cont", "loop") + types_consts() +
|
||||||
@ -1072,7 +1072,7 @@ TEST_P(ValidateCFG, BranchOutOfConstructBad) {
|
|||||||
Block merge("merge");
|
Block merge("merge");
|
||||||
Block exit("exit", 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 %loop None\n");
|
if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
|
||||||
|
|
||||||
string str = header(GetParam()) + nameOps("cont", "loop") + types_consts() +
|
string str = header(GetParam()) + nameOps("cont", "loop") + types_consts() +
|
||||||
@ -1216,7 +1216,7 @@ TEST_P(ValidateCFG,
|
|||||||
Block inner_merge("inner_merge");
|
Block inner_merge("inner_merge");
|
||||||
Block exit("exit", SpvOpReturn);
|
Block exit("exit", SpvOpReturn);
|
||||||
|
|
||||||
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
|
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
|
||||||
if (is_shader) {
|
if (is_shader) {
|
||||||
entry.AppendBody("OpSelectionMerge %exit None\n");
|
entry.AppendBody("OpSelectionMerge %exit None\n");
|
||||||
inner_head.SetBody("OpSelectionMerge %inner_merge 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 if_merge("if_merge", SpvOpBranchConditional);
|
||||||
Block merge("merge", SpvOpReturn);
|
Block merge("merge", SpvOpReturn);
|
||||||
|
|
||||||
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
|
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
|
||||||
if (is_shader) {
|
if (is_shader) {
|
||||||
loop.SetBody("OpLoopMerge %merge %if_merge None\n");
|
loop.SetBody("OpLoopMerge %merge %if_merge None\n");
|
||||||
if_head.SetBody("OpSelectionMerge %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 latch("latch", SpvOpBranchConditional);
|
||||||
Block merge("merge", SpvOpReturn);
|
Block merge("merge", SpvOpReturn);
|
||||||
|
|
||||||
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
|
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
|
||||||
if (is_shader) {
|
if (is_shader) {
|
||||||
loop.SetBody("OpLoopMerge %merge %latch None\n");
|
loop.SetBody("OpLoopMerge %merge %latch None\n");
|
||||||
}
|
}
|
||||||
@ -1315,7 +1315,7 @@ TEST_P(ValidateCFG, SingleLatchBlockHeaderContinueTargetIsItselfGood) {
|
|||||||
Block latch("latch");
|
Block latch("latch");
|
||||||
Block merge("merge", SpvOpReturn);
|
Block merge("merge", SpvOpReturn);
|
||||||
|
|
||||||
entry.SetBody("%cond = OpSLessThan %intt %one %two\n");
|
entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
|
||||||
if (is_shader) {
|
if (is_shader) {
|
||||||
loop.SetBody("OpLoopMerge %merge %loop None\n");
|
loop.SetBody("OpLoopMerge %merge %loop None\n");
|
||||||
}
|
}
|
||||||
|
@ -1878,7 +1878,9 @@ TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpSelectGood) {
|
|||||||
|
|
||||||
// Without the VariablePointers Capability, OpLoad will not allow loading
|
// Without the VariablePointers Capability, OpLoad will not allow loading
|
||||||
// through a variable pointer.
|
// 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"(
|
std::string result_strategy = R"(
|
||||||
%isneg = OpSLessThan %bool %i %zero
|
%isneg = OpSLessThan %bool %i %zero
|
||||||
%varptr = OpSelect %f32ptr %isneg %ptr1 %ptr2
|
%varptr = OpSelect %f32ptr %isneg %ptr1 %ptr2
|
||||||
@ -2086,7 +2088,9 @@ TEST_F(ValidateIdWithMessage, OpStoreLogicalPointerBad) {
|
|||||||
|
|
||||||
// Without the VariablePointer Capability, OpStore should may not store
|
// Without the VariablePointer Capability, OpStore should may not store
|
||||||
// through a variable pointer.
|
// 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"(
|
std::string result_strategy = R"(
|
||||||
%isneg = OpSLessThan %bool %i %zero
|
%isneg = OpSLessThan %bool %i %zero
|
||||||
%varptr = OpSelect %f32ptr %isneg %ptr1 %ptr2
|
%varptr = OpSelect %f32ptr %isneg %ptr1 %ptr2
|
||||||
@ -3134,7 +3138,9 @@ OpFunctionEnd)";
|
|||||||
// However, the OpSelect validation does not catch this today. Therefore, it is
|
// However, the OpSelect validation does not catch this today. Therefore, it is
|
||||||
// caught by the OpSampledImage validation. If the OpSelect validation code is
|
// caught by the OpSampledImage validation. If the OpSelect validation code is
|
||||||
// updated, the error message for this test may change.
|
// 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"(
|
string spirv = kGLSL450MemoryModel + sampledImageSetup + R"(
|
||||||
%smpld_img = OpSampledImage %sampled_image_type %image_inst %sampler_inst
|
%smpld_img = OpSampledImage %sampled_image_type %image_inst %sampler_inst
|
||||||
%select_img = OpSelect %sampled_image_type %spec_true %smpld_img %smpld_img
|
%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
|
// Without the VariablePointer Capability, the return value of a function is
|
||||||
// *not* allowed to be a pointer.
|
// *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;
|
std::ostringstream spirv;
|
||||||
createVariablePointerSpirvProgram(&spirv,
|
createVariablePointerSpirvProgram(&spirv,
|
||||||
"" /* Instructions to add to "main" */,
|
"" /* Instructions to add to "main" */,
|
||||||
|
851
test/val/val_logicals_test.cpp
Normal file
851
test/val/val_logicals_test.cpp
Normal 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
|
@ -1080,7 +1080,7 @@ TEST_F(ValidateSSA, IdDominatesItsUseGood) {
|
|||||||
R"(
|
R"(
|
||||||
%func = OpFunction %voidt None %vfunct
|
%func = OpFunction %voidt None %vfunct
|
||||||
%entry = OpLabel
|
%entry = OpLabel
|
||||||
%cond = OpSLessThan %uintt %one %ten
|
%cond = OpSLessThan %boolt %one %ten
|
||||||
%eleven = OpIAdd %uintt %one %ten
|
%eleven = OpIAdd %uintt %one %ten
|
||||||
OpSelectionMerge %merge None
|
OpSelectionMerge %merge None
|
||||||
OpBranchConditional %cond %t %f
|
OpBranchConditional %cond %t %f
|
||||||
@ -1108,7 +1108,7 @@ TEST_F(ValidateSSA, IdDoesNotDominateItsUseBad) {
|
|||||||
R"(
|
R"(
|
||||||
%func = OpFunction %voidt None %vfunct
|
%func = OpFunction %voidt None %vfunct
|
||||||
%entry = OpLabel
|
%entry = OpLabel
|
||||||
%cond = OpSLessThan %uintt %one %ten
|
%cond = OpSLessThan %boolt %one %ten
|
||||||
OpSelectionMerge %merge None
|
OpSelectionMerge %merge None
|
||||||
OpBranchConditional %cond %true_block %false_block
|
OpBranchConditional %cond %true_block %false_block
|
||||||
%true_block = OpLabel
|
%true_block = OpLabel
|
||||||
@ -1140,7 +1140,7 @@ TEST_F(ValidateSSA, PhiUseDoesntDominateDefinitionGood) {
|
|||||||
OpBranch %loop
|
OpBranch %loop
|
||||||
%loop = OpLabel
|
%loop = OpLabel
|
||||||
%i = OpPhi %uintt %one_val %entry %inew %cont
|
%i = OpPhi %uintt %one_val %entry %inew %cont
|
||||||
%cond = OpSLessThan %uintt %one %ten
|
%cond = OpSLessThan %boolt %one %ten
|
||||||
OpLoopMerge %merge %cont None
|
OpLoopMerge %merge %cont None
|
||||||
OpBranchConditional %cond %body %merge
|
OpBranchConditional %cond %body %merge
|
||||||
%body = OpLabel
|
%body = OpLabel
|
||||||
@ -1169,7 +1169,7 @@ TEST_F(ValidateSSA,
|
|||||||
%loop = OpLabel
|
%loop = OpLabel
|
||||||
%i = OpPhi %uintt %one_val %entry %inew %cont
|
%i = OpPhi %uintt %one_val %entry %inew %cont
|
||||||
%bad = OpIAdd %uintt %inew %one
|
%bad = OpIAdd %uintt %inew %one
|
||||||
%cond = OpSLessThan %uintt %one %ten
|
%cond = OpSLessThan %boolt %one %ten
|
||||||
OpLoopMerge %merge %cont None
|
OpLoopMerge %merge %cont None
|
||||||
OpBranchConditional %cond %body %merge
|
OpBranchConditional %cond %body %merge
|
||||||
%body = OpLabel
|
%body = OpLabel
|
||||||
|
Loading…
Reference in New Issue
Block a user