mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-25 01:01:04 +00:00
100 lines
3.1 KiB
C++
100 lines
3.1 KiB
C++
// 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
|