| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- // 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/instruction.h"
- #include "val/validation_state.h"
- using libspirv::CapabilitySet;
- using libspirv::DiagnosticStream;
- using libspirv::ValidationState_t;
- namespace {
- // Validates that the number of components in the vector is valid.
- // 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 ValidateVecNumComponents(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // 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;
- }
- 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));
- }
- // Validates that the number of bits specifed for a float type is valid.
- // Scalar floating-point types can be parameterized only with 32-bits.
- // Float16 capability allows using a 16-bit OpTypeFloat.
- // Float16Buffer capability allows creation of a 16-bit OpTypeFloat.
- // Float64 capability allows using a 64-bit OpTypeFloat.
- spv_result_t ValidateFloatSize(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Operand 1 is the number of bits for this float
- const uint32_t num_bits = inst->words[inst->operands[1].offset];
- if (num_bits == 32) {
- return SPV_SUCCESS;
- }
- if (num_bits == 16) {
- if (_.features().declare_float16_type) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA)
- << "Using a 16-bit floating point "
- << "type requires the Float16 or Float16Buffer capability,"
- " or an extension that explicitly enables 16-bit floating point.";
- }
- if (num_bits == 64) {
- if (_.HasCapability(SpvCapabilityFloat64)) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA)
- << "Using a 64-bit floating point "
- << "type requires the Float64 capability.";
- }
- return _.diag(SPV_ERROR_INVALID_DATA)
- << "Invalid number of bits (" << num_bits << ") used for OpTypeFloat.";
- }
- // Validates that the number of bits specified for an Int type is valid.
- // Scalar integer types can be parameterized only with 32-bits.
- // Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit
- // integers, respectively.
- spv_result_t ValidateIntSize(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Operand 1 is the number of bits for this integer.
- const uint32_t num_bits = inst->words[inst->operands[1].offset];
- if (num_bits == 32) {
- return SPV_SUCCESS;
- }
- if (num_bits == 8) {
- if (_.HasCapability(SpvCapabilityInt8)) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA)
- << "Using an 8-bit integer type requires the Int8 capability.";
- }
- if (num_bits == 16) {
- if (_.features().declare_int16_type) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA)
- << "Using a 16-bit integer type requires the Int16 capability,"
- " or an extension that explicitly enables 16-bit integers.";
- }
- if (num_bits == 64) {
- if (_.HasCapability(SpvCapabilityInt64)) {
- return SPV_SUCCESS;
- }
- return _.diag(SPV_ERROR_INVALID_DATA)
- << "Using a 64-bit integer type requires the Int64 capability.";
- }
- return _.diag(SPV_ERROR_INVALID_DATA)
- << "Invalid number of bits (" << num_bits << ") used for OpTypeInt.";
- }
- // Validates that the matrix is parameterized with floating-point types.
- spv_result_t ValidateMatrixColumnType(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Find the component type of matrix columns (must be vector).
- // Operand 1 is the <id> of the type specified for matrix columns.
- auto type_id = inst->words[inst->operands[1].offset];
- auto col_type_instr = _.FindDef(type_id);
- if (col_type_instr->opcode() != SpvOpTypeVector) {
- return _.diag(SPV_ERROR_INVALID_ID)
- << "Columns in a matrix must be of type vector.";
- }
- // Trace back once more to find out the type of components in the vector.
- // Operand 1 is the <id> of the type of data in the vector.
- auto comp_type_id =
- col_type_instr->words()[col_type_instr->operands()[1].offset];
- auto comp_type_instruction = _.FindDef(comp_type_id);
- if (comp_type_instruction->opcode() != SpvOpTypeFloat) {
- return _.diag(SPV_ERROR_INVALID_DATA) << "Matrix types can only be "
- "parameterized with "
- "floating-point types.";
- }
- return SPV_SUCCESS;
- }
- // Validates that the matrix has 2,3, or 4 columns.
- spv_result_t ValidateMatrixNumCols(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Operand 2 is the number of columns in the matrix.
- const uint32_t num_cols = inst->words[inst->operands[2].offset];
- if (num_cols != 2 && num_cols != 3 && num_cols != 4) {
- return _.diag(SPV_ERROR_INVALID_DATA) << "Matrix types can only be "
- "parameterized as having only 2, "
- "3, or 4 columns.";
- }
- return SPV_SUCCESS;
- }
- // Validates that OpSpecConstant specializes to either int or float type.
- spv_result_t ValidateSpecConstNumerical(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Operand 0 is the <id> of the type that we're specializing to.
- auto type_id = inst->words[inst->operands[0].offset];
- auto type_instruction = _.FindDef(type_id);
- auto type_opcode = type_instruction->opcode();
- if (type_opcode != SpvOpTypeInt && type_opcode != SpvOpTypeFloat) {
- return _.diag(SPV_ERROR_INVALID_DATA) << "Specialization constant must be "
- "an integer or floating-point "
- "number.";
- }
- return SPV_SUCCESS;
- }
- // Validates that OpSpecConstantTrue and OpSpecConstantFalse specialize to bool.
- spv_result_t ValidateSpecConstBoolean(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Find out the type that we're specializing to.
- auto type_instruction = _.FindDef(inst->type_id);
- if (type_instruction->opcode() != SpvOpTypeBool) {
- return _.diag(SPV_ERROR_INVALID_ID) << "Specialization constant must be "
- "a boolean type.";
- }
- return SPV_SUCCESS;
- }
- // Records the <id> of the forward pointer to be used for validation.
- spv_result_t ValidateForwardPointer(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Record the <id> (which is operand 0) to ensure it's used properly.
- // OpTypeStruct can only include undefined pointers that are
- // previously declared as a ForwardPointer
- return (_.RegisterForwardPointer(inst->words[inst->operands[0].offset]));
- }
- // Validates that any undefined component of the struct is a forward pointer.
- // It is valid to declare a forward pointer, and use its <id> as one of the
- // components of a struct.
- spv_result_t ValidateStruct(ValidationState_t& _,
- const spv_parsed_instruction_t* inst) {
- // Struct components are operands 1, 2, etc.
- for (unsigned i = 1; i < inst->num_operands; i++) {
- auto type_id = inst->words[inst->operands[i].offset];
- auto type_instruction = _.FindDef(type_id);
- if (type_instruction == nullptr && !_.IsForwardPointer(type_id)) {
- return _.diag(SPV_ERROR_INVALID_ID)
- << "Forward reference operands in an OpTypeStruct must first be "
- "declared using OpTypeForwardPointer.";
- }
- }
- 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) {
- switch (inst->opcode) {
- case SpvOpTypeVector: {
- if (auto error = ValidateVecNumComponents(_, inst)) return error;
- break;
- }
- case SpvOpTypeFloat: {
- if (auto error = ValidateFloatSize(_, inst)) return error;
- break;
- }
- case SpvOpTypeInt: {
- if (auto error = ValidateIntSize(_, inst)) return error;
- break;
- }
- case SpvOpTypeMatrix: {
- if (auto error = ValidateMatrixColumnType(_, inst)) return error;
- if (auto error = ValidateMatrixNumCols(_, inst)) return error;
- break;
- }
- // TODO(ehsan): Add OpSpecConstantComposite validation code.
- // TODO(ehsan): Add OpSpecConstantOp validation code (if any).
- case SpvOpSpecConstant: {
- if (auto error = ValidateSpecConstNumerical(_, inst)) return error;
- break;
- }
- case SpvOpSpecConstantFalse:
- case SpvOpSpecConstantTrue: {
- if (auto error = ValidateSpecConstBoolean(_, inst)) return error;
- break;
- }
- case SpvOpTypeForwardPointer: {
- if (auto error = ValidateForwardPointer(_, inst)) return error;
- break;
- }
- case SpvOpTypeStruct: {
- if (auto error = ValidateStruct(_, inst)) return error;
- break;
- }
- // TODO(ehsan): add more data rules validation here.
- default: { break; }
- }
- return SPV_SUCCESS;
- }
- } // namespace libspirv
|