mirror of
https://gitee.com/openharmony/third_party_spirv-tools
synced 2024-11-23 07:20:28 +00:00
validate & test of literal's upper bits
Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/660
This commit is contained in:
parent
f35963588b
commit
4dbcef62ee
@ -47,6 +47,7 @@ SPVTOOLS_SRC_FILES := \
|
||||
source/validate_image.cpp \
|
||||
source/validate_instruction.cpp \
|
||||
source/validate_layout.cpp \
|
||||
source/validate_literals.cpp \
|
||||
source/validate_logicals.cpp \
|
||||
source/validate_primitives.cpp \
|
||||
source/validate_type_unique.cpp
|
||||
|
@ -270,6 +270,7 @@ set(SPIRV_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_image.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_instruction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_layout.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_literals.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_logicals.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_primitives.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_type_unique.cpp
|
||||
|
@ -53,6 +53,7 @@ using libspirv::DataRulesPass;
|
||||
using libspirv::Extension;
|
||||
using libspirv::IdPass;
|
||||
using libspirv::InstructionPass;
|
||||
using libspirv::LiteralsPass;
|
||||
using libspirv::ModuleLayoutPass;
|
||||
using libspirv::ValidationState_t;
|
||||
|
||||
@ -188,6 +189,7 @@ spv_result_t ProcessInstruction(void* user_data,
|
||||
if (auto error = ImagePass(_, inst)) return error;
|
||||
if (auto error = AtomicsPass(_, inst)) return error;
|
||||
if (auto error = PrimitivesPass(_, inst)) return error;
|
||||
if (auto error = LiteralsPass(_, inst)) return error;
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
@ -143,6 +143,10 @@ spv_result_t ImagePass(ValidationState_t& _,
|
||||
spv_result_t AtomicsPass(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst);
|
||||
|
||||
/// Validates correctness of literal numbers.
|
||||
spv_result_t LiteralsPass(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& _,
|
||||
|
99
source/validate_literals.cpp
Normal file
99
source/validate_literals.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// 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 literal numbers.
|
||||
|
||||
#include "validate.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "diagnostic.h"
|
||||
#include "opcode.h"
|
||||
#include "val/instruction.h"
|
||||
#include "val/validation_state.h"
|
||||
|
||||
namespace libspirv {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns true if the operand holds a literal number
|
||||
bool IsLiteralNumber(const spv_parsed_operand_t* operand) {
|
||||
switch (operand->number_kind) {
|
||||
case SPV_NUMBER_SIGNED_INT:
|
||||
case SPV_NUMBER_UNSIGNED_INT:
|
||||
case SPV_NUMBER_FLOATING:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that the upper bits of the given upper |word| with given
|
||||
// lower |width| are zero- or sign-extended when |signed_int| is true
|
||||
bool VerifyUpperBits(uint32_t word, uint32_t width, bool signed_int) {
|
||||
assert(width < 32);
|
||||
assert(0 < width);
|
||||
const uint32_t upper_mask = 0xFFFFFFFFu << width;
|
||||
const uint32_t upper_bits = word & upper_mask;
|
||||
|
||||
bool result = false;
|
||||
if (signed_int) {
|
||||
const uint32_t sign_bit = word & (1u << (width - 1));
|
||||
if (sign_bit) {
|
||||
result = upper_bits == upper_mask;
|
||||
} else {
|
||||
result = upper_bits == 0;
|
||||
}
|
||||
} else {
|
||||
result = upper_bits == 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Validates that literal numbers are represented according to the spec
|
||||
spv_result_t LiteralsPass(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst) {
|
||||
// For every operand that is a literal number
|
||||
for (uint16_t i = 0; i < inst->num_operands; i++) {
|
||||
const spv_parsed_operand_t* operand = inst->operands + i;
|
||||
if (!IsLiteralNumber(operand)) continue;
|
||||
|
||||
// The upper bits are always in the last word (little-endian)
|
||||
int last_index = operand->offset + operand->num_words - 1;
|
||||
const uint32_t upper_word = inst->words[last_index];
|
||||
|
||||
// TODO(jcaraban): is the |word size| defined in some header?
|
||||
const uint32_t word_size = 32;
|
||||
uint32_t bit_width = operand->number_bit_width;
|
||||
|
||||
// Bit widths that are a multiple of the word size have no upper bits
|
||||
const auto remaining_value_bits = bit_width % word_size;
|
||||
if (remaining_value_bits == 0) continue;
|
||||
|
||||
const bool signedness = operand->number_kind == SPV_NUMBER_SIGNED_INT;
|
||||
|
||||
if (!VerifyUpperBits(upper_word, remaining_value_bits, signedness)) {
|
||||
return _.diag(SPV_ERROR_INVALID_VALUE)
|
||||
<< "The high-order bits of a literal number in instruction <id> "
|
||||
<< inst->result_id << " must be 0 for a floating-point type, "
|
||||
<< "or 0 for an integer type with Signedness of 0, "
|
||||
<< "or sign extended when Signedness is 1";
|
||||
}
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace libspirv
|
@ -152,6 +152,12 @@ add_spvtools_unittest(TARGET val_instructions
|
||||
LIBS ${SPIRV_TOOLS}
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET val_literals
|
||||
SRCS val_literals_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
LIBS ${SPIRV_TOOLS}
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET val_extensions
|
||||
SRCS val_extensions_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
|
138
test/val/val_literals_test.cpp
Normal file
138
test/val/val_literals_test.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
// 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.
|
||||
|
||||
// Validation tests for ilegal literals
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "val_fixtures.h"
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
using ValidateLiterals = spvtest::ValidateBase<std::string>;
|
||||
using ValidateLiteralsShader = spvtest::ValidateBase<std::string>;
|
||||
using ValidateLiteralsKernel = spvtest::ValidateBase<std::string>;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GenerateShaderCode() {
|
||||
std::string str = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability Int16
|
||||
OpCapability Int64
|
||||
OpCapability Float16
|
||||
OpCapability Float64
|
||||
OpMemoryModel Logical GLSL450
|
||||
%int16 = OpTypeInt 16 1
|
||||
%uint16 = OpTypeInt 16 0
|
||||
%int32 = OpTypeInt 32 1
|
||||
%uint32 = OpTypeInt 32 0
|
||||
%int64 = OpTypeInt 64 1
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%half = OpTypeFloat 16
|
||||
%float = OpTypeFloat 32
|
||||
%double = OpTypeFloat 64
|
||||
%10 = OpTypeVoid
|
||||
)";
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string GenerateKernelCode() {
|
||||
std::string str = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Addresses
|
||||
OpCapability Linkage
|
||||
OpCapability Int8
|
||||
OpMemoryModel Physical64 OpenCL
|
||||
%uint8 = OpTypeInt 8 0
|
||||
)";
|
||||
return str;
|
||||
}
|
||||
|
||||
TEST_F(ValidateLiterals, LiteralsShaderGood) {
|
||||
std::string str = GenerateShaderCode() + R"(
|
||||
%11 = OpConstant %int16 !0x00007FFF
|
||||
%12 = OpConstant %int16 !0xFFFF8000
|
||||
%13 = OpConstant %int16 !0xFFFFABCD
|
||||
%14 = OpConstant %uint16 !0x0000ABCD
|
||||
%15 = OpConstant %int16 -32768
|
||||
%16 = OpConstant %uint16 65535
|
||||
%17 = OpConstant %int32 -2147483648
|
||||
%18 = OpConstant %uint32 4294967295
|
||||
%19 = OpConstant %int64 -9223372036854775808
|
||||
%20 = OpConstant %uint64 18446744073709551615
|
||||
%21 = OpConstant %half !0x0000FFFF
|
||||
%22 = OpConstant %float !0xFFFFFFFF
|
||||
%23 = OpConstant %double !0xFFFFFFFF !0xFFFFFFFF
|
||||
)";
|
||||
CompileSuccessfully(str);
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_P(ValidateLiteralsShader, LiteralsShaderBad) {
|
||||
std::string str = GenerateShaderCode() + GetParam();
|
||||
std::string inst_id = "11";
|
||||
CompileSuccessfully(str);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_VALUE, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("The high-order bits of a literal number in instruction <id> " +
|
||||
inst_id +
|
||||
" must be 0 for a floating-point type, "
|
||||
"or 0 for an integer type with Signedness of 0, "
|
||||
"or sign extended when Signedness is 1"));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
LiteralsShaderCases, ValidateLiteralsShader,
|
||||
::testing::Values("%11 = OpConstant %int16 !0xFFFF0000", // Sign bit is 0
|
||||
"%11 = OpConstant %int16 !0x00008000", // Sign bit is 1
|
||||
"%11 = OpConstant %int16 !0xABCD8000", // Sign bit is 1
|
||||
"%11 = OpConstant %int16 !0xABCD0000",
|
||||
"%11 = OpConstant %uint16 !0xABCD0000",
|
||||
"%11 = OpConstant %half !0xABCD0000",
|
||||
"%11 = OpConstant %half !0x00010000"));
|
||||
|
||||
TEST_F(ValidateLiterals, LiteralsKernelGood) {
|
||||
std::string str = GenerateKernelCode() + R"(
|
||||
%4 = OpConstant %uint8 !0x000000AB
|
||||
%6 = OpConstant %uint8 255
|
||||
)";
|
||||
CompileSuccessfully(str);
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_P(ValidateLiteralsKernel, LiteralsKernelBad) {
|
||||
std::string str = GenerateKernelCode() + GetParam();
|
||||
std::string inst_id = "2";
|
||||
CompileSuccessfully(str);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_VALUE, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("The high-order bits of a literal number in instruction <id> " +
|
||||
inst_id +
|
||||
" must be 0 for a floating-point type, "
|
||||
"or 0 for an integer type with Signedness of 0, "
|
||||
"or sign extended when Signedness is 1"));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
LiteralsKernelCases, ValidateLiteralsKernel,
|
||||
::testing::Values("%2 = OpConstant %uint8 !0xABCDEF00",
|
||||
"%2 = OpConstant %uint8 !0xABCDEFFF"));
|
||||
|
||||
} // namespace
|
Loading…
Reference in New Issue
Block a user