Adding validation for vector data rule.

Number of components in a vector can be 2 or 3 or 4. If Vector16
capability is used, 8 and 16 components are also allowed.
Also added unit tests for vector data rule.
This commit is contained in:
Ehsan Nasiri 2016-11-04 18:31:21 -04:00 committed by David Neto
parent 4f57e140bf
commit 6c899a52f9
8 changed files with 216 additions and 2 deletions

View File

@ -53,6 +53,7 @@ typedef enum spv_result_t {
SPV_ERROR_INVALID_CFG = -11,
SPV_ERROR_INVALID_LAYOUT = -12,
SPV_ERROR_INVALID_CAPABILITY = -13,
SPV_ERROR_INVALID_DATA = -14, // Indicates data rules validation failure.
SPV_FORCE_32_BIT_ENUM(spv_result_t)
} spv_result_t;

View File

@ -158,6 +158,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/validate_cfg.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_layout.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/BasicBlock.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/Construct.cpp

View File

@ -47,6 +47,7 @@ using std::vector;
using libspirv::CfgPass;
using libspirv::InstructionPass;
using libspirv::ModuleLayoutPass;
using libspirv::DataRulesPass;
using libspirv::IdPass;
using libspirv::ValidationState_t;
@ -122,7 +123,7 @@ spv_result_t ProcessInstruction(void* user_data,
_.entry_points().push_back(inst->words[2]);
DebugInstructionPass(_, inst);
// TODO(umar): Perform data rules pass
if (auto error = DataRulesPass(_, inst)) return error;
if (auto error = IdPass(_, inst)) return error;
if (auto error = ModuleLayoutPass(_, inst)) return error;
if (auto error = CfgPass(_, inst)) return error;

View File

@ -141,6 +141,12 @@ spv_result_t CfgPass(ValidationState_t& _,
/// Performs Id and SSA validation of a module
spv_result_t IdPass(ValidationState_t& _, const spv_parsed_instruction_t* inst);
/// Performs validation of the Data Rules subsection of 2.16.1 Universal
/// Validation Rules.
/// TODO(ehsann): add more comments here as more validation code is added.
spv_result_t DataRulesPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst);
/// Performs instruction validation.
spv_result_t InstructionPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst);

View File

@ -0,0 +1,78 @@
// 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.
// Ensures Data Rules are followed according to the specifications.
#include "validate.h"
#include <cassert>
#include <sstream>
#include <string>
#include "diagnostic.h"
#include "opcode.h"
#include "operand.h"
#include "val/ValidationState.h"
using libspirv::CapabilitySet;
using libspirv::DiagnosticStream;
using libspirv::ValidationState_t;
namespace {
// Validates that the number of components in the vector type is legal.
// Vector types can only be parameterized as having 2, 3, or 4 components.
// If the Vector16 capability is added, 8 and 16 components are also allowed.
spv_result_t ValidateNumVecComponents(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
if (inst->opcode == SpvOpTypeVector) {
// operand 2 specifies the number of components in the vector.
const uint32_t num_components = inst->words[inst->operands[2].offset];
if (num_components == 2 || num_components == 3 || num_components == 4) {
return SPV_SUCCESS;
}
if (num_components == 8 || num_components == 16) {
if (_.HasCapability(SpvCapabilityVector16)) {
return SPV_SUCCESS;
} else {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Having " << num_components << " components for "
<< spvOpcodeString(static_cast<SpvOp>(inst->opcode))
<< " requires the Vector16 capability";
}
}
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Illegal number of components (" << num_components << ") for "
<< spvOpcodeString(static_cast<SpvOp>(inst->opcode));
}
return SPV_SUCCESS;
}
} // anonymous namespace
namespace libspirv {
// Validates that Data Rules are followed according to the specifications.
// (Data Rules subsection of 2.16.1 Universal Validation Rules)
spv_result_t DataRulesPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
if (auto error = ValidateNumVecComponents(_, inst)) return error;
// TODO(ehsan): add more data rules validation here.
return SPV_SUCCESS;
}
} // namespace libspirv

View File

@ -62,3 +62,10 @@ add_spvtools_unittest(TARGET val_state
${VAL_TEST_COMMON_SRCS}
LIBS ${SPIRV_TOOLS}
)
add_spvtools_unittest(TARGET val_data
SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Validate.Data.cpp
${VAL_TEST_COMMON_SRCS}
LIBS ${SPIRV_TOOLS}
)

119
test/val/Validate.Data.cpp Normal file
View File

@ -0,0 +1,119 @@
// 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 "unit_spirv.h"
#include "ValidateFixtures.h"
#include "gmock/gmock.h"
#include <sstream>
#include <string>
#include <utility>
using ::testing::HasSubstr;
using ::testing::MatchesRegex;
using std::string;
using std::pair;
using std::stringstream;
using ValidateData = spvtest::ValidateBase<pair<string, bool>>;
string header = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
%1 = OpTypeFloat 32
)";
string header_with_vec16_cap = R"(
OpCapability Shader
OpCapability Vector16
OpMemoryModel Logical GLSL450
%1 = OpTypeFloat 32
)";
string invalid_comp_error = "Illegal number of components";
string missing_cap_error = "requires the Vector16 capability";
TEST_F(ValidateData, vec0) {
string str = header + "%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) {
string str = header + "%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) {
string str = header + "%2 = OpTypeVector %1 2";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateData, vec3) {
string str = header + "%2 = OpTypeVector %1 3";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateData, vec4) {
string str = header + "%2 = OpTypeVector %1 4";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateData, vec5) {
string str = header + "%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) {
string str = header + "%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) {
string str = header_with_vec16_cap + "%2 = OpTypeVector %1 8";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateData, vec16) {
string str = header + "%2 = OpTypeVector %1 16";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
}
TEST_F(ValidateData, vec16_with_capability) {
string str = header_with_vec16_cap + "%2 = OpTypeVector %1 16";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateData, vec15) {
string str = header + "%2 = OpTypeVector %1 15";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
}

View File

@ -44,6 +44,7 @@ const char kGLSL450MemoryModel[] = R"(
OpCapability Pipes
OpCapability LiteralSampler
OpCapability DeviceEnqueue
OpCapability Vector16
OpMemoryModel Logical GLSL450
)";
@ -746,7 +747,7 @@ TEST_F(ValidateID, OpConstantCompositeArrayConstConstituentBad) {
%1 = OpTypeInt 32 0
%2 = OpConstant %1 4
%3 = OpTypeArray %1 %2
%4 = OpConstantComposite %3 %2 %2 %2 %1)"; // Uses a type as operand
%4 = OpConstantComposite %3 %2 %2 %2 %1)"; // Uses a type as operand
CHECK(spirv, SPV_ERROR_INVALID_ID);
}
TEST_F(ValidateID, OpConstantCompositeArrayConstituentTypeBad) {