Home | History | Annotate | Download | only in val
      1 // Copyright (c) 2015-2016 The Khronos Group 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 #include "val/validation_state.h"
     16 
     17 #include <cassert>
     18 
     19 #include "opcode.h"
     20 #include "val/basic_block.h"
     21 #include "val/construct.h"
     22 #include "val/function.h"
     23 
     24 using std::deque;
     25 using std::make_pair;
     26 using std::pair;
     27 using std::string;
     28 using std::unordered_map;
     29 using std::vector;
     30 
     31 namespace libspirv {
     32 
     33 namespace {
     34 bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
     35   // See Section 2.4
     36   bool out = false;
     37   // clang-format off
     38   switch (layout) {
     39     case kLayoutCapabilities:  out = op == SpvOpCapability;    break;
     40     case kLayoutExtensions:    out = op == SpvOpExtension;     break;
     41     case kLayoutExtInstImport: out = op == SpvOpExtInstImport; break;
     42     case kLayoutMemoryModel:   out = op == SpvOpMemoryModel;   break;
     43     case kLayoutEntryPoint:    out = op == SpvOpEntryPoint;    break;
     44     case kLayoutExecutionMode: out = op == SpvOpExecutionMode; break;
     45     case kLayoutDebug1:
     46       switch (op) {
     47         case SpvOpSourceContinued:
     48         case SpvOpSource:
     49         case SpvOpSourceExtension:
     50         case SpvOpString:
     51           out = true;
     52           break;
     53         default: break;
     54       }
     55       break;
     56     case kLayoutDebug2:
     57       switch (op) {
     58         case SpvOpName:
     59         case SpvOpMemberName:
     60           out = true;
     61           break;
     62         default: break;
     63       }
     64       break;
     65     case kLayoutAnnotations:
     66       switch (op) {
     67         case SpvOpDecorate:
     68         case SpvOpMemberDecorate:
     69         case SpvOpGroupDecorate:
     70         case SpvOpGroupMemberDecorate:
     71         case SpvOpDecorationGroup:
     72           out = true;
     73           break;
     74         default: break;
     75       }
     76       break;
     77     case kLayoutTypes:
     78       if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op)) {
     79         out = true;
     80         break;
     81       }
     82       switch (op) {
     83         case SpvOpTypeForwardPointer:
     84         case SpvOpVariable:
     85         case SpvOpLine:
     86         case SpvOpNoLine:
     87         case SpvOpUndef:
     88           out = true;
     89           break;
     90         default: break;
     91       }
     92       break;
     93     case kLayoutFunctionDeclarations:
     94     case kLayoutFunctionDefinitions:
     95       // NOTE: These instructions should NOT be in these layout sections
     96       if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op)) {
     97         out = false;
     98         break;
     99       }
    100       switch (op) {
    101         case SpvOpCapability:
    102         case SpvOpExtension:
    103         case SpvOpExtInstImport:
    104         case SpvOpMemoryModel:
    105         case SpvOpEntryPoint:
    106         case SpvOpExecutionMode:
    107         case SpvOpSourceContinued:
    108         case SpvOpSource:
    109         case SpvOpSourceExtension:
    110         case SpvOpString:
    111         case SpvOpName:
    112         case SpvOpMemberName:
    113         case SpvOpDecorate:
    114         case SpvOpMemberDecorate:
    115         case SpvOpGroupDecorate:
    116         case SpvOpGroupMemberDecorate:
    117         case SpvOpDecorationGroup:
    118         case SpvOpTypeForwardPointer:
    119           out = false;
    120           break;
    121       default:
    122         out = true;
    123         break;
    124       }
    125   }
    126   // clang-format on
    127   return out;
    128 }
    129 
    130 }  // anonymous namespace
    131 
    132 ValidationState_t::ValidationState_t(const spv_const_context ctx,
    133                                      const spv_const_validator_options opt)
    134     : context_(ctx),
    135       options_(opt),
    136       instruction_counter_(0),
    137       unresolved_forward_ids_{},
    138       operand_names_{},
    139       current_layout_section_(kLayoutCapabilities),
    140       module_functions_(),
    141       module_capabilities_(),
    142       module_extensions_(),
    143       ordered_instructions_(),
    144       all_definitions_(),
    145       global_vars_(),
    146       local_vars_(),
    147       struct_nesting_depth_(),
    148       grammar_(ctx),
    149       addressing_model_(SpvAddressingModelLogical),
    150       memory_model_(SpvMemoryModelSimple),
    151       in_function_(false) {
    152   assert(opt && "Validator options may not be Null.");
    153 }
    154 
    155 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
    156   unresolved_forward_ids_.insert(id);
    157   return SPV_SUCCESS;
    158 }
    159 
    160 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
    161   unresolved_forward_ids_.erase(id);
    162   return SPV_SUCCESS;
    163 }
    164 
    165 spv_result_t ValidationState_t::RegisterForwardPointer(uint32_t id) {
    166   forward_pointer_ids_.insert(id);
    167   return SPV_SUCCESS;
    168 }
    169 
    170 bool ValidationState_t::IsForwardPointer(uint32_t id) const {
    171   return (forward_pointer_ids_.find(id) != forward_pointer_ids_.end());
    172 }
    173 
    174 void ValidationState_t::AssignNameToId(uint32_t id, string name) {
    175   operand_names_[id] = name;
    176 }
    177 
    178 string ValidationState_t::getIdName(uint32_t id) const {
    179   std::stringstream out;
    180   out << id;
    181   if (operand_names_.find(id) != end(operand_names_)) {
    182     out << "[" << operand_names_.at(id) << "]";
    183   }
    184   return out.str();
    185 }
    186 
    187 string ValidationState_t::getIdOrName(uint32_t id) const {
    188   std::stringstream out;
    189   if (operand_names_.find(id) != end(operand_names_)) {
    190     out << operand_names_.at(id);
    191   } else {
    192     out << id;
    193   }
    194   return out.str();
    195 }
    196 
    197 size_t ValidationState_t::unresolved_forward_id_count() const {
    198   return unresolved_forward_ids_.size();
    199 }
    200 
    201 vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
    202   vector<uint32_t> out(begin(unresolved_forward_ids_),
    203                        end(unresolved_forward_ids_));
    204   return out;
    205 }
    206 
    207 bool ValidationState_t::IsDefinedId(uint32_t id) const {
    208   return all_definitions_.find(id) != end(all_definitions_);
    209 }
    210 
    211 const Instruction* ValidationState_t::FindDef(uint32_t id) const {
    212   auto it = all_definitions_.find(id);
    213   if (it == all_definitions_.end())
    214     return nullptr;
    215   return it->second;
    216 }
    217 
    218 Instruction* ValidationState_t::FindDef(uint32_t id) {
    219   auto it = all_definitions_.find(id);
    220   if (it == all_definitions_.end())
    221     return nullptr;
    222   return it->second;
    223 }
    224 
    225 // Increments the instruction count. Used for diagnostic
    226 int ValidationState_t::increment_instruction_count() {
    227   return instruction_counter_++;
    228 }
    229 
    230 ModuleLayoutSection ValidationState_t::current_layout_section() const {
    231   return current_layout_section_;
    232 }
    233 
    234 void ValidationState_t::ProgressToNextLayoutSectionOrder() {
    235   // Guard against going past the last element(kLayoutFunctionDefinitions)
    236   if (current_layout_section_ <= kLayoutFunctionDefinitions) {
    237     current_layout_section_ =
    238         static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
    239   }
    240 }
    241 
    242 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) {
    243   return IsInstructionInLayoutSection(current_layout_section_, op);
    244 }
    245 
    246 DiagnosticStream ValidationState_t::diag(spv_result_t error_code) const {
    247   return libspirv::DiagnosticStream(
    248       {0, 0, static_cast<size_t>(instruction_counter_)}, context_->consumer,
    249       error_code);
    250 }
    251 
    252 deque<Function>& ValidationState_t::functions() { return module_functions_; }
    253 
    254 Function& ValidationState_t::current_function() {
    255   assert(in_function_body());
    256   return module_functions_.back();
    257 }
    258 
    259 bool ValidationState_t::in_function_body() const { return in_function_; }
    260 
    261 bool ValidationState_t::in_block() const {
    262   return module_functions_.empty() == false &&
    263          module_functions_.back().current_block() != nullptr;
    264 }
    265 
    266 void ValidationState_t::RegisterCapability(SpvCapability cap) {
    267   // Avoid redundant work.  Otherwise the recursion could induce work
    268   // quadrdatic in the capability dependency depth. (Ok, not much, but
    269   // it's something.)
    270   if (module_capabilities_.Contains(cap)) return;
    271 
    272   module_capabilities_.Add(cap);
    273   spv_operand_desc desc;
    274   if (SPV_SUCCESS ==
    275       grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) {
    276     desc->capabilities.ForEach(
    277         [this](SpvCapability c) { RegisterCapability(c); });
    278   }
    279 
    280   switch (cap) {
    281     case SpvCapabilityInt16:
    282       features_.declare_int16_type = true;
    283       break;
    284     case SpvCapabilityFloat16:
    285     case SpvCapabilityFloat16Buffer:
    286       features_.declare_float16_type = true;
    287       break;
    288     case SpvCapabilityStorageUniformBufferBlock16:
    289     case SpvCapabilityStorageUniform16:
    290     case SpvCapabilityStoragePushConstant16:
    291     case SpvCapabilityStorageInputOutput16:
    292       features_.declare_int16_type = true;
    293       features_.declare_float16_type = true;
    294       features_.free_fp_rounding_mode = true;
    295       break;
    296     case SpvCapabilityVariablePointers:
    297       features_.variable_pointers = true;
    298       features_.variable_pointers_storage_buffer = true;
    299       break;
    300     case SpvCapabilityVariablePointersStorageBuffer:
    301       features_.variable_pointers_storage_buffer = true;
    302       break;
    303     default:
    304       break;
    305   }
    306 }
    307 
    308 void ValidationState_t::RegisterExtension(Extension ext) {
    309   if (module_extensions_.Contains(ext)) return;
    310 
    311   module_extensions_.Add(ext);
    312 }
    313 
    314 bool ValidationState_t::HasAnyOfCapabilities(
    315     const CapabilitySet& capabilities) const {
    316   return module_capabilities_.HasAnyOf(capabilities);
    317 }
    318 
    319 bool ValidationState_t::HasAnyOfExtensions(
    320     const ExtensionSet& extensions) const {
    321   return module_extensions_.HasAnyOf(extensions);
    322 }
    323 
    324 void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
    325   addressing_model_ = am;
    326 }
    327 
    328 SpvAddressingModel ValidationState_t::addressing_model() const {
    329   return addressing_model_;
    330 }
    331 
    332 void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
    333   memory_model_ = mm;
    334 }
    335 
    336 SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; }
    337 
    338 spv_result_t ValidationState_t::RegisterFunction(
    339     uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
    340     uint32_t function_type_id) {
    341   assert(in_function_body() == false &&
    342          "RegisterFunction can only be called when parsing the binary outside "
    343          "of another function");
    344   in_function_ = true;
    345   module_functions_.emplace_back(id, ret_type_id, function_control,
    346                                  function_type_id);
    347 
    348   // TODO(umar): validate function type and type_id
    349 
    350   return SPV_SUCCESS;
    351 }
    352 
    353 spv_result_t ValidationState_t::RegisterFunctionEnd() {
    354   assert(in_function_body() == true &&
    355          "RegisterFunctionEnd can only be called when parsing the binary "
    356          "inside of another function");
    357   assert(in_block() == false &&
    358          "RegisterFunctionParameter can only be called when parsing the binary "
    359          "ouside of a block");
    360   current_function().RegisterFunctionEnd();
    361   in_function_ = false;
    362   return SPV_SUCCESS;
    363 }
    364 
    365 void ValidationState_t::RegisterInstruction(
    366     const spv_parsed_instruction_t& inst) {
    367   if (in_function_body()) {
    368     ordered_instructions_.emplace_back(&inst, &current_function(),
    369                                        current_function().current_block());
    370   } else {
    371     ordered_instructions_.emplace_back(&inst, nullptr, nullptr);
    372   }
    373   uint32_t id = ordered_instructions_.back().id();
    374   if (id) {
    375     all_definitions_.insert(make_pair(id, &ordered_instructions_.back()));
    376   }
    377 
    378   // If the instruction is using an OpTypeSampledImage as an operand, it should
    379   // be recorded. The validator will ensure that all usages of an
    380   // OpTypeSampledImage and its definition are in the same basic block.
    381   for (uint16_t i = 0; i < inst.num_operands; ++i) {
    382     const spv_parsed_operand_t& operand = inst.operands[i];
    383     if (SPV_OPERAND_TYPE_ID == operand.type) {
    384       const uint32_t operand_word = inst.words[operand.offset];
    385       Instruction* operand_inst = FindDef(operand_word);
    386       if (operand_inst && SpvOpSampledImage == operand_inst->opcode()) {
    387         RegisterSampledImageConsumer(operand_word, inst.result_id);
    388       }
    389     }
    390   }
    391 }
    392 
    393 std::vector<uint32_t> ValidationState_t::getSampledImageConsumers(
    394     uint32_t sampled_image_id) const {
    395   std::vector<uint32_t> result;
    396   auto iter = sampled_image_consumers_.find(sampled_image_id);
    397   if (iter != sampled_image_consumers_.end()) {
    398     result = iter->second;
    399   }
    400   return result;
    401 }
    402 
    403 void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id,
    404                                                      uint32_t consumer_id) {
    405   sampled_image_consumers_[sampled_image_id].push_back(consumer_id);
    406 }
    407 
    408 uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
    409 
    410 void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; }
    411 
    412 bool ValidationState_t::RegisterUniqueTypeDeclaration(
    413     const spv_parsed_instruction_t& inst) {
    414   std::vector<uint32_t> key;
    415   key.push_back(static_cast<uint32_t>(inst.opcode));
    416   for (int index = 0; index < inst.num_operands; ++index) {
    417     const spv_parsed_operand_t& operand = inst.operands[index];
    418 
    419     if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue;
    420 
    421     const int words_begin = operand.offset;
    422     const int words_end = words_begin + operand.num_words;
    423     assert(words_end <= static_cast<int>(inst.num_words));
    424 
    425     key.insert(key.end(), inst.words + words_begin, inst.words + words_end);
    426   }
    427 
    428   return unique_type_declarations_.insert(std::move(key)).second;
    429 }
    430 }  /// namespace libspirv
    431