mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
Add bitwise operations validator pass
The pass checks correctness of operand types of all bitwise instructions (opcode range from SpvOpShiftRightLogical to SpvOpBitCount).
This commit is contained in:
parent
dcf42433a6
commit
64d5e5214f
1
CHANGES
1
CHANGES
@ -6,6 +6,7 @@ v2017.1-dev 2017-09-01
|
||||
- Validator:
|
||||
- Type check basic arithmetic operations
|
||||
- Type check Relational and Logical instructions
|
||||
- Type check Bit instructions
|
||||
- OpModuleProcessed is only allowed after debug names section and before annotations
|
||||
section.
|
||||
- Recognize extensions listed on SPIR-V registry,
|
||||
|
@ -253,6 +253,7 @@ set(SPIRV_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_arithmetics.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_bitwise.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_cfg.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_capability.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_datarules.cpp
|
||||
|
@ -182,6 +182,7 @@ spv_result_t ProcessInstruction(void* user_data,
|
||||
if (auto error = TypeUniquePass(_, inst)) return error;
|
||||
if (auto error = ArithmeticsPass(_, inst)) return error;
|
||||
if (auto error = LogicalsPass(_, inst)) return error;
|
||||
if (auto error = BitwisePass(_, inst)) return error;
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
@ -119,6 +119,10 @@ spv_result_t ArithmeticsPass(ValidationState_t& _,
|
||||
spv_result_t LogicalsPass(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst);
|
||||
|
||||
/// Validates correctness of bitwise instructions.
|
||||
spv_result_t BitwisePass(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& _,
|
||||
|
254
source/validate_bitwise.cpp
Normal file
254
source/validate_bitwise.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
// 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 bitwise 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 bitwise instructions.
|
||||
spv_result_t BitwisePass(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 SpvOpShiftRightLogical:
|
||||
case SpvOpShiftRightArithmetic:
|
||||
case SpvOpShiftLeftLogical: {
|
||||
if (!_.IsIntScalarType(result_type) &&
|
||||
!_.IsIntVectorType(result_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected int scalar or vector type as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
const uint32_t result_dimension = _.GetDimension(result_type);
|
||||
const uint32_t base_type = GetOperandTypeId(_, inst, 2);
|
||||
const uint32_t shift_type = GetOperandTypeId(_, inst, 3);
|
||||
|
||||
if (!base_type ||
|
||||
(!_.IsIntScalarType(base_type) && !_.IsIntVectorType(base_type)))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base to be int scalar or vector: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (_.GetDimension(base_type) != result_dimension)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base to have the same dimension "
|
||||
<< "as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (_.GetBitWidth(base_type) != _.GetBitWidth(result_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base to have the same bit width "
|
||||
<< "as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (!shift_type ||
|
||||
(!_.IsIntScalarType(shift_type) && !_.IsIntVectorType(shift_type)))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Shift to be int scalar or vector: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (_.GetDimension(shift_type) != result_dimension)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Shift to have the same dimension "
|
||||
<< "as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case SpvOpBitwiseOr:
|
||||
case SpvOpBitwiseXor:
|
||||
case SpvOpBitwiseAnd:
|
||||
case SpvOpNot: {
|
||||
if (!_.IsIntScalarType(result_type) &&
|
||||
!_.IsIntVectorType(result_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected int scalar or vector type as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
const uint32_t result_dimension = _.GetDimension(result_type);
|
||||
const uint32_t result_bit_width = _.GetBitWidth(result_type);
|
||||
|
||||
for (size_t operand_index = 2; operand_index < inst->num_operands;
|
||||
++operand_index) {
|
||||
|
||||
const uint32_t type_id = GetOperandTypeId(_, inst, operand_index);
|
||||
if (!type_id ||
|
||||
(!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id)))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected int scalar or vector as operand: "
|
||||
<< spvOpcodeString(opcode) << " operand index " << operand_index;
|
||||
|
||||
if (_.GetDimension(type_id) != result_dimension)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected operands to have the same dimension "
|
||||
<< "as Result Type: "
|
||||
<< spvOpcodeString(opcode) << " operand index " << operand_index;
|
||||
|
||||
if (_.GetBitWidth(type_id) != result_bit_width)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected operands to have the same bit width "
|
||||
<< "as Result Type: "
|
||||
<< spvOpcodeString(opcode) << " operand index " << operand_index;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SpvOpBitFieldInsert: {
|
||||
if (!_.IsIntScalarType(result_type) &&
|
||||
!_.IsIntVectorType(result_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected int scalar or vector type as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
const uint32_t base_type = GetOperandTypeId(_, inst, 2);
|
||||
const uint32_t insert_type = GetOperandTypeId(_, inst, 3);
|
||||
const uint32_t offset_type = GetOperandTypeId(_, inst, 4);
|
||||
const uint32_t count_type = GetOperandTypeId(_, inst, 5);
|
||||
|
||||
if (base_type != result_type)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base Type to be equal to Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (insert_type != result_type)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Insert Type to be equal to Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (!offset_type || !_.IsIntScalarType(offset_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Offset Type to be int scalar: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (!count_type || !_.IsIntScalarType(count_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Count Type to be int scalar: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case SpvOpBitFieldSExtract:
|
||||
case SpvOpBitFieldUExtract: {
|
||||
if (!_.IsIntScalarType(result_type) &&
|
||||
!_.IsIntVectorType(result_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected int scalar or vector type as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
const uint32_t base_type = GetOperandTypeId(_, inst, 2);
|
||||
const uint32_t offset_type = GetOperandTypeId(_, inst, 3);
|
||||
const uint32_t count_type = GetOperandTypeId(_, inst, 4);
|
||||
|
||||
if (base_type != result_type)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base Type to be equal to Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (!offset_type || !_.IsIntScalarType(offset_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Offset Type to be int scalar: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (!count_type || !_.IsIntScalarType(count_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Count Type to be int scalar: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case SpvOpBitReverse: {
|
||||
if (!_.IsIntScalarType(result_type) &&
|
||||
!_.IsIntVectorType(result_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected int scalar or vector type as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
const uint32_t base_type = GetOperandTypeId(_, inst, 2);
|
||||
|
||||
if (base_type != result_type)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base Type to be equal to Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case SpvOpBitCount: {
|
||||
if (!_.IsIntScalarType(result_type) &&
|
||||
!_.IsIntVectorType(result_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected int scalar or vector type as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
const uint32_t base_type = GetOperandTypeId(_, inst, 2);
|
||||
if (!base_type ||
|
||||
(!_.IsIntScalarType(base_type) && !_.IsIntVectorType(base_type)))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base Type to be int scalar or vector: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
const uint32_t base_dimension = _.GetDimension(base_type);
|
||||
const uint32_t result_dimension = _.GetDimension(result_type);
|
||||
|
||||
if (base_dimension != result_dimension)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< "Expected Base dimension to be equal to Result Type dimension: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
//TODO(dneto): Add a check for:
|
||||
// "The components must be wide enough to hold the unsigned Width of Base
|
||||
// as an unsigned value. That is, no sign bit is needed or counted when
|
||||
// checking for a wide enough result width."
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace libspirv
|
@ -15,7 +15,6 @@
|
||||
set(VAL_TEST_COMMON_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../test_fixture.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../unit_spirv.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../unit_spirv.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/val_fixtures.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/val_fixtures.cpp
|
||||
)
|
||||
@ -87,6 +86,12 @@ add_spvtools_unittest(TARGET val_logicals
|
||||
LIBS ${SPIRV_TOOLS}
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET val_bitwise
|
||||
SRCS val_bitwise_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
LIBS ${SPIRV_TOOLS}
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET val_limits
|
||||
SRCS val_limits_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
|
512
test/val/val_bitwise_test.cpp
Normal file
512
test/val/val_bitwise_test.cpp
Normal file
@ -0,0 +1,512 @@
|
||||
// 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 ValidateBitwise = 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"(
|
||||
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
|
||||
|
||||
%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(ValidateBitwise, ShiftAllSuccess) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpShiftRightLogical %u64 %u64_1 %s32_2
|
||||
%val2 = OpShiftRightArithmetic %s32vec2 %s32vec2_12 %s32vec2_12
|
||||
%val3 = OpShiftLeftLogical %u32vec2 %s32vec2_12 %u32vec2_12
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpShiftRightLogicalWrongResultType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpShiftRightLogical %bool %u64_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector type as Result Type: ShiftRightLogical"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpShiftRightLogicalBaseNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpShiftRightLogical %u32 %f32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base to be int scalar or vector: ShiftRightLogical"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpShiftRightLogicalBaseWrongDimension) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpShiftRightLogical %u32 %u32vec2_12 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base to have the same dimension as Result Type: "
|
||||
"ShiftRightLogical"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpShiftRightLogicalBaseWrongBitWidth) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpShiftRightLogical %u64 %u32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base to have the same bit width as Result Type: "
|
||||
"ShiftRightLogical"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpShiftRightLogicalShiftNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpShiftRightLogical %u32 %u32_1 %f32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Shift to be int scalar or vector: ShiftRightLogical"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpShiftRightLogicalShiftWrongDimension) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpShiftRightLogical %u32 %u32_1 %s32vec2_12
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Shift to have the same dimension as Result Type: "
|
||||
"ShiftRightLogical"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, LogicAllSuccess) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseOr %u64 %u64_1 %s64_0
|
||||
%val2 = OpBitwiseAnd %s64 %s64_1 %u64_0
|
||||
%val3 = OpBitwiseXor %s32vec2 %s32vec2_12 %u32vec2_01
|
||||
%val4 = OpNot %s32vec2 %u32vec2_01
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitwiseAndWrongResultType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseAnd %bool %u64_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector type as Result Type: BitwiseAnd"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitwiseAndLeftNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseAnd %u32 %f32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector as operand: BitwiseAnd "
|
||||
"operand index 2"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitwiseAndRightNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseAnd %u32 %u32_1 %f32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector as operand: BitwiseAnd "
|
||||
"operand index 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitwiseAndLeftWrongDimension) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseAnd %u32 %u32vec2_12 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected operands to have the same dimension as Result Type: "
|
||||
"BitwiseAnd operand index 2"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitwiseAndRightWrongDimension) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseAnd %u32 %s32_2 %u32vec2_12
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected operands to have the same dimension as Result Type: "
|
||||
"BitwiseAnd operand index 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitwiseAndLeftWrongBitWidth) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseAnd %u64 %u32_1 %s64_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected operands to have the same bit width as Result Type: "
|
||||
"BitwiseAnd operand index 2"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitwiseAndRightWrongBitWidth) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitwiseAnd %u64 %u64_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected operands to have the same bit width as Result Type: "
|
||||
"BitwiseAnd operand index 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldInsertSuccess) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldInsert %u64 %u64_1 %u64_2 %s32_1 %s32_2
|
||||
%val2 = OpBitFieldInsert %s32vec2 %s32vec2_12 %s32vec2_12 %s32_1 %u32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldInsertWrongResultType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldInsert %bool %u64_1 %u64_2 %s32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector type as Result Type: BitFieldInsert"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldInsertWrongBaseType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldInsert %u64 %s64_1 %u64_2 %s32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base Type to be equal to Result Type: BitFieldInsert"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldInsertWrongInsertType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldInsert %u64 %u64_1 %s64_2 %s32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Insert Type to be equal to Result Type: BitFieldInsert"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldInsertOffsetNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldInsert %u64 %u64_1 %u64_2 %f32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Offset Type to be int scalar: BitFieldInsert"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldInsertCountNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldInsert %u64 %u64_1 %u64_2 %u32_1 %f32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Count Type to be int scalar: BitFieldInsert"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldSExtractSuccess) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldSExtract %u64 %u64_1 %s32_1 %s32_2
|
||||
%val2 = OpBitFieldSExtract %s32vec2 %s32vec2_12 %s32_1 %u32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldSExtractWrongResultType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldSExtract %bool %u64_1 %s32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector type as Result Type: BitFieldSExtract"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldSExtractWrongBaseType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldSExtract %u64 %s64_1 %s32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base Type to be equal to Result Type: BitFieldSExtract"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldSExtractOffsetNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldSExtract %u64 %u64_1 %f32_1 %s32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Offset Type to be int scalar: BitFieldSExtract"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitFieldSExtractCountNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitFieldSExtract %u64 %u64_1 %u32_1 %f32_2
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Count Type to be int scalar: BitFieldSExtract"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitReverseSuccess) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitReverse %u64 %u64_1
|
||||
%val2 = OpBitReverse %s32vec2 %s32vec2_12
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitReverseWrongResultType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitReverse %bool %u64_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector type as Result Type: BitReverse"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitReverseWrongBaseType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitReverse %u64 %s64_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base Type to be equal to Result Type: BitReverse"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitCountSuccess) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitCount %s32 %u64_1
|
||||
%val2 = OpBitCount %u32vec2 %s32vec2_12
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitCountWrongResultType) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitCount %bool %u64_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected int scalar or vector type as Result Type: BitCount"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitCountBaseNotInt) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitCount %u32 %f64_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base Type to be int scalar or vector: BitCount"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBitwise, OpBitCountBaseWrongDimension) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpBitCount %u32 %u32vec2_12
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(
|
||||
"Expected Base dimension to be equal to Result Type dimension: "
|
||||
"BitCount"));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
Loading…
Reference in New Issue
Block a user