mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-13 18:00:05 +00:00
36d675a404
When doing the validator checks, an instruction is currently registered at the end of IdPass. This creates an inconsistency. In IdPass, an instruction that uses its own result will treat that use as a forward reference. Then in the following passes it will not because the definition can be found. It seems best to update the state after all of the check have been done for the current instruction. This makes it consistent for all of the passes. This makes a different when trying to verify OpTypeStruct. Fixes https://crbug.com/874372.
643 lines
20 KiB
C++
643 lines
20 KiB
C++
// Copyright (c) 2016 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 Data Rules.
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "test/unit_spirv.h"
|
|
#include "test/val/val_fixtures.h"
|
|
|
|
namespace spvtools {
|
|
namespace val {
|
|
namespace {
|
|
|
|
using ::testing::HasSubstr;
|
|
using ::testing::MatchesRegex;
|
|
|
|
using ValidateData = spvtest::ValidateBase<std::pair<std::string, bool>>;
|
|
|
|
std::string HeaderWith(std::string cap) {
|
|
return std::string("OpCapability Shader OpCapability Linkage OpCapability ") +
|
|
cap + " OpMemoryModel Logical GLSL450 ";
|
|
}
|
|
|
|
std::string header = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
std::string header_with_addresses = R"(
|
|
OpCapability Addresses
|
|
OpCapability Kernel
|
|
OpCapability GenericPointer
|
|
OpCapability Linkage
|
|
OpMemoryModel Physical32 OpenCL
|
|
)";
|
|
std::string header_with_vec16_cap = R"(
|
|
OpCapability Shader
|
|
OpCapability Vector16
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
std::string header_with_int8 = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability Int8
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
std::string header_with_int16 = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability Int16
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
std::string header_with_int64 = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability Int64
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
std::string header_with_float16 = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability Float16
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
std::string header_with_float16_buffer = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability Float16Buffer
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
std::string header_with_float64 = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability Float64
|
|
OpMemoryModel Logical GLSL450
|
|
)";
|
|
|
|
std::string invalid_comp_error = "Illegal number of components";
|
|
std::string missing_cap_error = "requires the Vector16 capability";
|
|
std::string missing_int8_cap_error = "requires the Int8 capability";
|
|
std::string missing_int16_cap_error =
|
|
"requires the Int16 capability,"
|
|
" or an extension that explicitly enables 16-bit integers.";
|
|
std::string missing_int64_cap_error = "requires the Int64 capability";
|
|
std::string missing_float16_cap_error =
|
|
"requires the Float16 or Float16Buffer capability,"
|
|
" or an extension that explicitly enables 16-bit floating point.";
|
|
std::string missing_float64_cap_error = "requires the Float64 capability";
|
|
std::string invalid_num_bits_error = "Invalid number of bits";
|
|
|
|
TEST_F(ValidateData, vec0) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 0
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, vec1) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 1
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, vec2) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 2
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, vec3) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 3
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, vec4) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 4
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, vec5) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 5
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, vec8) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 8
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, vec8_with_capability) {
|
|
std::string str = header_with_vec16_cap + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 8
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, vec16) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 8
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, vec16_with_capability) {
|
|
std::string str = header_with_vec16_cap + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 16
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, vec15) {
|
|
std::string str = header + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpTypeVector %1 15
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, int8_good) {
|
|
std::string str = header_with_int8 + "%2 = OpTypeInt 8 0";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, int8_bad) {
|
|
std::string str = header + "%2 = OpTypeInt 8 1";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int8_cap_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, int8_with_storage_buffer_8bit_access_good) {
|
|
std::string str = HeaderWith(
|
|
"StorageBuffer8BitAccess "
|
|
"OpExtension \"SPV_KHR_8bit_storage\"") +
|
|
" %2 = OpTypeInt 8 0";
|
|
CompileSuccessfully(str.c_str());
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateData, int8_with_uniform_and_storage_buffer_8bit_access_good) {
|
|
std::string str = HeaderWith(
|
|
"UniformAndStorageBuffer8BitAccess "
|
|
"OpExtension \"SPV_KHR_8bit_storage\"") +
|
|
" %2 = OpTypeInt 8 0";
|
|
CompileSuccessfully(str.c_str());
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateData, int8_with_storage_push_constant_8_good) {
|
|
std::string str = HeaderWith(
|
|
"StoragePushConstant8 "
|
|
"OpExtension \"SPV_KHR_8bit_storage\"") +
|
|
" %2 = OpTypeInt 8 0";
|
|
CompileSuccessfully(str.c_str());
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateData, int16_good) {
|
|
std::string str = header_with_int16 + "%2 = OpTypeInt 16 1";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, storage_uniform_buffer_block_16_good) {
|
|
std::string str = HeaderWith(
|
|
"StorageUniformBufferBlock16 "
|
|
"OpExtension \"SPV_KHR_16bit_storage\"") +
|
|
"%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, storage_uniform_16_good) {
|
|
std::string str =
|
|
HeaderWith("StorageUniform16 OpExtension \"SPV_KHR_16bit_storage\"") +
|
|
"%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, storage_push_constant_16_good) {
|
|
std::string str = HeaderWith(
|
|
"StoragePushConstant16 "
|
|
"OpExtension \"SPV_KHR_16bit_storage\"") +
|
|
"%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, storage_input_output_16_good) {
|
|
std::string str = HeaderWith(
|
|
"StorageInputOutput16 "
|
|
"OpExtension \"SPV_KHR_16bit_storage\"") +
|
|
"%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, int16_bad) {
|
|
std::string str = header + "%2 = OpTypeInt 16 1";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, int64_good) {
|
|
std::string str = header_with_int64 + "%2 = OpTypeInt 64 1";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, int64_bad) {
|
|
std::string str = header + "%2 = OpTypeInt 64 1";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error));
|
|
}
|
|
|
|
// Number of bits in an integer may be only one of: {8,16,32,64}
|
|
TEST_F(ValidateData, int_invalid_num_bits) {
|
|
std::string str = header + "%2 = OpTypeInt 48 1";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_num_bits_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, float16_good) {
|
|
std::string str = header_with_float16 + "%2 = OpTypeFloat 16";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, float16_buffer_good) {
|
|
std::string str = header_with_float16_buffer + "%2 = OpTypeFloat 16";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, float16_bad) {
|
|
std::string str = header + "%2 = OpTypeFloat 16";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, float64_good) {
|
|
std::string str = header_with_float64 + "%2 = OpTypeFloat 64";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, float64_bad) {
|
|
std::string str = header + "%2 = OpTypeFloat 64";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error));
|
|
}
|
|
|
|
// Number of bits in a float may be only one of: {16,32,64}
|
|
TEST_F(ValidateData, float_invalid_num_bits) {
|
|
std::string str = header + "%2 = OpTypeFloat 48";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_num_bits_error));
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_data_type_float) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %f32 3
|
|
%mat33 = OpTypeMatrix %vec3 3
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, ids_should_be_validated_before_data) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%mat33 = OpTypeMatrix %vec3 3
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 3 has not been defined"));
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_bad_column_type) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%mat33 = OpTypeMatrix %f32 3
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Columns in a matrix must be of type vector"));
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_data_type_int) {
|
|
std::string str = header + R"(
|
|
%int32 = OpTypeInt 32 1
|
|
%vec3 = OpTypeVector %int32 3
|
|
%mat33 = OpTypeMatrix %vec3 3
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("can only be parameterized with floating-point types"));
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_data_type_bool) {
|
|
std::string str = header + R"(
|
|
%boolt = OpTypeBool
|
|
%vec3 = OpTypeVector %boolt 3
|
|
%mat33 = OpTypeMatrix %vec3 3
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("can only be parameterized with floating-point types"));
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_with_0_columns) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %f32 3
|
|
%mat33 = OpTypeMatrix %vec3 0
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_with_1_column) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %f32 3
|
|
%mat33 = OpTypeMatrix %vec3 1
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_with_2_columns) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %f32 3
|
|
%mat33 = OpTypeMatrix %vec3 2
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_with_3_columns) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %f32 3
|
|
%mat33 = OpTypeMatrix %vec3 3
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_with_4_columns) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %f32 3
|
|
%mat33 = OpTypeMatrix %vec3 4
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, matrix_with_5_column) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %f32 3
|
|
%mat33 = OpTypeMatrix %vec3 5
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
|
|
}
|
|
|
|
TEST_F(ValidateData, specialize_int) {
|
|
std::string str = header + R"(
|
|
%i32 = OpTypeInt 32 1
|
|
%len = OpSpecConstant %i32 2)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, specialize_float) {
|
|
std::string str = header + R"(
|
|
%f32 = OpTypeFloat 32
|
|
%len = OpSpecConstant %f32 2)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, specialize_boolean) {
|
|
std::string str = header + R"(
|
|
%2 = OpTypeBool
|
|
%3 = OpSpecConstantTrue %2
|
|
%4 = OpSpecConstantFalse %2)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, specialize_boolean_to_int) {
|
|
std::string str = header + R"(
|
|
%2 = OpTypeInt 32 1
|
|
%3 = OpSpecConstantTrue %2
|
|
%4 = OpSpecConstantFalse %2)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Specialization constant must be a boolean"));
|
|
}
|
|
|
|
TEST_F(ValidateData, missing_forward_pointer_decl) {
|
|
std::string str = header_with_addresses + R"(
|
|
%uintt = OpTypeInt 32 0
|
|
%3 = OpTypeStruct %fwd_ptrt %uintt
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must first be declared using OpTypeForwardPointer"));
|
|
}
|
|
|
|
TEST_F(ValidateData, missing_forward_pointer_decl_self_reference) {
|
|
std::string str = header_with_addresses + R"(
|
|
%uintt = OpTypeInt 32 0
|
|
%3 = OpTypeStruct %3 %uintt
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must first be declared using OpTypeForwardPointer"));
|
|
}
|
|
|
|
TEST_F(ValidateData, forward_pointer_missing_definition) {
|
|
std::string str = header_with_addresses + R"(
|
|
OpTypeForwardPointer %_ptr_Generic_struct_A Generic
|
|
%uintt = OpTypeInt 32 0
|
|
%struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("forward referenced IDs have not been defined"));
|
|
}
|
|
|
|
TEST_F(ValidateData, forward_ref_bad_type) {
|
|
std::string str = header_with_addresses + R"(
|
|
OpTypeForwardPointer %_ptr_Generic_struct_A Generic
|
|
%uintt = OpTypeInt 32 0
|
|
%struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
|
|
%_ptr_Generic_struct_A = OpTypeFloat 32
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Found a forward reference to a non-pointer type in "
|
|
"OpTypeStruct instruction."));
|
|
}
|
|
|
|
TEST_F(ValidateData, forward_ref_points_to_non_struct) {
|
|
std::string str = header_with_addresses + R"(
|
|
OpTypeForwardPointer %_ptr_Generic_struct_A Generic
|
|
%uintt = OpTypeInt 32 0
|
|
%struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
|
|
%_ptr_Generic_struct_A = OpTypePointer Generic %uintt
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("A forward reference operand in an OpTypeStruct must "
|
|
"be an OpTypePointer that points to an OpTypeStruct. "
|
|
"Found OpTypePointer that points to OpTypeInt."));
|
|
}
|
|
|
|
TEST_F(ValidateData, struct_forward_pointer_good) {
|
|
std::string str = header_with_addresses + R"(
|
|
OpTypeForwardPointer %_ptr_Generic_struct_A Generic
|
|
%uintt = OpTypeInt 32 0
|
|
%struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
|
|
%struct_C = OpTypeStruct %uintt %struct_B
|
|
%struct_A = OpTypeStruct %uintt %struct_C
|
|
%_ptr_Generic_struct_A = OpTypePointer Generic %struct_C
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateData, ext_16bit_storage_caps_allow_free_fp_rounding_mode) {
|
|
for (const char* cap : {"StorageUniform16", "StorageUniformBufferBlock16",
|
|
"StoragePushConstant16", "StorageInputOutput16"}) {
|
|
for (const char* mode : {"RTE", "RTZ", "RTP", "RTN"}) {
|
|
std::string str = std::string(R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability )") +
|
|
cap + R"(
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %2 FPRoundingMode )" + mode + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpConstant %1 1.25
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(ValidateData, vulkan_disallow_free_fp_rounding_mode) {
|
|
for (const char* mode : {"RTE", "RTZ"}) {
|
|
for (const auto env : {SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
|
|
std::string str = std::string(R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %2 FPRoundingMode )") +
|
|
mode + R"(
|
|
%1 = OpTypeFloat 32
|
|
%2 = OpConstant %1 1.25
|
|
)";
|
|
CompileSuccessfully(str.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(env));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Operand 2 of Decorate requires one of these capabilities: "
|
|
"StorageBuffer16BitAccess StorageUniform16 "
|
|
"StoragePushConstant16 StorageInputOutput16"));
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace val
|
|
} // namespace spvtools
|