Home | History | Annotate | Download | only in val
      1 // Copyright (c) 2017 Google Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // Validates literal numbers.
     16 
     17 #include "source/val/validate.h"
     18 
     19 #include <cassert>
     20 
     21 #include "source/diagnostic.h"
     22 #include "source/opcode.h"
     23 #include "source/val/instruction.h"
     24 #include "source/val/validation_state.h"
     25 
     26 namespace spvtools {
     27 namespace val {
     28 namespace {
     29 
     30 // Returns true if the operand holds a literal number
     31 bool IsLiteralNumber(const spv_parsed_operand_t& operand) {
     32   switch (operand.number_kind) {
     33     case SPV_NUMBER_SIGNED_INT:
     34     case SPV_NUMBER_UNSIGNED_INT:
     35     case SPV_NUMBER_FLOATING:
     36       return true;
     37     default:
     38       return false;
     39   }
     40 }
     41 
     42 // Verifies that the upper bits of the given upper |word| with given
     43 // lower |width| are zero- or sign-extended when |signed_int| is true
     44 bool VerifyUpperBits(uint32_t word, uint32_t width, bool signed_int) {
     45   assert(width < 32);
     46   assert(0 < width);
     47   const uint32_t upper_mask = 0xFFFFFFFFu << width;
     48   const uint32_t upper_bits = word & upper_mask;
     49 
     50   bool result = false;
     51   if (signed_int) {
     52     const uint32_t sign_bit = word & (1u << (width - 1));
     53     if (sign_bit) {
     54       result = upper_bits == upper_mask;
     55     } else {
     56       result = upper_bits == 0;
     57     }
     58   } else {
     59     result = upper_bits == 0;
     60   }
     61   return result;
     62 }
     63 
     64 }  // namespace
     65 
     66 // Validates that literal numbers are represented according to the spec
     67 spv_result_t LiteralsPass(ValidationState_t& _, const Instruction* inst) {
     68   // For every operand that is a literal number
     69   for (size_t i = 0; i < inst->operands().size(); i++) {
     70     const spv_parsed_operand_t& operand = inst->operand(i);
     71     if (!IsLiteralNumber(operand)) continue;
     72 
     73     // The upper bits are always in the last word (little-endian)
     74     int last_index = operand.offset + operand.num_words - 1;
     75     const uint32_t upper_word = inst->word(last_index);
     76 
     77     // TODO(jcaraban): is the |word size| defined in some header?
     78     const uint32_t word_size = 32;
     79     uint32_t bit_width = operand.number_bit_width;
     80 
     81     // Bit widths that are a multiple of the word size have no upper bits
     82     const auto remaining_value_bits = bit_width % word_size;
     83     if (remaining_value_bits == 0) continue;
     84 
     85     const bool signedness = operand.number_kind == SPV_NUMBER_SIGNED_INT;
     86 
     87     if (!VerifyUpperBits(upper_word, remaining_value_bits, signedness)) {
     88       return _.diag(SPV_ERROR_INVALID_VALUE, inst)
     89              << "The high-order bits of a literal number in instruction <id> "
     90              << inst->id() << " must be 0 for a floating-point type, "
     91              << "or 0 for an integer type with Signedness of 0, "
     92              << "or sign extended when Signedness is 1";
     93     }
     94   }
     95   return SPV_SUCCESS;
     96 }
     97 
     98 }  // namespace val
     99 }  // namespace spvtools
    100