Home | History | Annotate | Download | only in val
      1 // Copyright (c) 2015-2016 The Khronos Group Inc.
      2 //
      3 // Permission is hereby granted, free of charge, to any person obtaining a
      4 // copy of this software and/or associated documentation files (the
      5 // "Materials"), to deal in the Materials without restriction, including
      6 // without limitation the rights to use, copy, modify, merge, publish,
      7 // distribute, sublicense, and/or sell copies of the Materials, and to
      8 // permit persons to whom the Materials are furnished to do so, subject to
      9 // the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included
     12 // in all copies or substantial portions of the Materials.
     13 //
     14 // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
     15 // KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
     16 // SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
     17 //    https://www.khronos.org/registry/
     18 //
     19 // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     22 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     23 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25 // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
     26 
     27 #include "val/ValidationState.h"
     28 
     29 #include <cassert>
     30 
     31 #include "val/BasicBlock.h"
     32 #include "val/Construct.h"
     33 #include "val/Function.h"
     34 
     35 using std::list;
     36 using std::string;
     37 using std::vector;
     38 
     39 namespace libspirv {
     40 
     41 namespace {
     42 bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
     43   // See Section 2.4
     44   bool out = false;
     45   // clang-format off
     46   switch (layout) {
     47     case kLayoutCapabilities:  out = op == SpvOpCapability;    break;
     48     case kLayoutExtensions:    out = op == SpvOpExtension;     break;
     49     case kLayoutExtInstImport: out = op == SpvOpExtInstImport; break;
     50     case kLayoutMemoryModel:   out = op == SpvOpMemoryModel;   break;
     51     case kLayoutEntryPoint:    out = op == SpvOpEntryPoint;    break;
     52     case kLayoutExecutionMode: out = op == SpvOpExecutionMode; break;
     53     case kLayoutDebug1:
     54       switch (op) {
     55         case SpvOpSourceContinued:
     56         case SpvOpSource:
     57         case SpvOpSourceExtension:
     58         case SpvOpString:
     59           out = true;
     60           break;
     61         default: break;
     62       }
     63       break;
     64     case kLayoutDebug2:
     65       switch (op) {
     66         case SpvOpName:
     67         case SpvOpMemberName:
     68           out = true;
     69           break;
     70         default: break;
     71       }
     72       break;
     73     case kLayoutAnnotations:
     74       switch (op) {
     75         case SpvOpDecorate:
     76         case SpvOpMemberDecorate:
     77         case SpvOpGroupDecorate:
     78         case SpvOpGroupMemberDecorate:
     79         case SpvOpDecorationGroup:
     80           out = true;
     81           break;
     82         default: break;
     83       }
     84       break;
     85     case kLayoutTypes:
     86       switch (op) {
     87         case SpvOpTypeVoid:
     88         case SpvOpTypeBool:
     89         case SpvOpTypeInt:
     90         case SpvOpTypeFloat:
     91         case SpvOpTypeVector:
     92         case SpvOpTypeMatrix:
     93         case SpvOpTypeImage:
     94         case SpvOpTypeSampler:
     95         case SpvOpTypeSampledImage:
     96         case SpvOpTypeArray:
     97         case SpvOpTypeRuntimeArray:
     98         case SpvOpTypeStruct:
     99         case SpvOpTypeOpaque:
    100         case SpvOpTypePointer:
    101         case SpvOpTypeFunction:
    102         case SpvOpTypeEvent:
    103         case SpvOpTypeDeviceEvent:
    104         case SpvOpTypeReserveId:
    105         case SpvOpTypeQueue:
    106         case SpvOpTypePipe:
    107         case SpvOpTypeForwardPointer:
    108         case SpvOpConstantTrue:
    109         case SpvOpConstantFalse:
    110         case SpvOpConstant:
    111         case SpvOpConstantComposite:
    112         case SpvOpConstantSampler:
    113         case SpvOpConstantNull:
    114         case SpvOpSpecConstantTrue:
    115         case SpvOpSpecConstantFalse:
    116         case SpvOpSpecConstant:
    117         case SpvOpSpecConstantComposite:
    118         case SpvOpSpecConstantOp:
    119         case SpvOpVariable:
    120         case SpvOpLine:
    121         case SpvOpNoLine:
    122           out = true;
    123           break;
    124         default: break;
    125       }
    126       break;
    127     case kLayoutFunctionDeclarations:
    128     case kLayoutFunctionDefinitions:
    129       // NOTE: These instructions should NOT be in these layout sections
    130       switch (op) {
    131         case SpvOpCapability:
    132         case SpvOpExtension:
    133         case SpvOpExtInstImport:
    134         case SpvOpMemoryModel:
    135         case SpvOpEntryPoint:
    136         case SpvOpExecutionMode:
    137         case SpvOpSourceContinued:
    138         case SpvOpSource:
    139         case SpvOpSourceExtension:
    140         case SpvOpString:
    141         case SpvOpName:
    142         case SpvOpMemberName:
    143         case SpvOpDecorate:
    144         case SpvOpMemberDecorate:
    145         case SpvOpGroupDecorate:
    146         case SpvOpGroupMemberDecorate:
    147         case SpvOpDecorationGroup:
    148         case SpvOpTypeVoid:
    149         case SpvOpTypeBool:
    150         case SpvOpTypeInt:
    151         case SpvOpTypeFloat:
    152         case SpvOpTypeVector:
    153         case SpvOpTypeMatrix:
    154         case SpvOpTypeImage:
    155         case SpvOpTypeSampler:
    156         case SpvOpTypeSampledImage:
    157         case SpvOpTypeArray:
    158         case SpvOpTypeRuntimeArray:
    159         case SpvOpTypeStruct:
    160         case SpvOpTypeOpaque:
    161         case SpvOpTypePointer:
    162         case SpvOpTypeFunction:
    163         case SpvOpTypeEvent:
    164         case SpvOpTypeDeviceEvent:
    165         case SpvOpTypeReserveId:
    166         case SpvOpTypeQueue:
    167         case SpvOpTypePipe:
    168         case SpvOpTypeForwardPointer:
    169         case SpvOpConstantTrue:
    170         case SpvOpConstantFalse:
    171         case SpvOpConstant:
    172         case SpvOpConstantComposite:
    173         case SpvOpConstantSampler:
    174         case SpvOpConstantNull:
    175         case SpvOpSpecConstantTrue:
    176         case SpvOpSpecConstantFalse:
    177         case SpvOpSpecConstant:
    178         case SpvOpSpecConstantComposite:
    179         case SpvOpSpecConstantOp:
    180           out = false;
    181           break;
    182       default:
    183         out = true;
    184         break;
    185       }
    186   }
    187   // clang-format on
    188   return out;
    189 }
    190 
    191 }  // anonymous namespace
    192 
    193 ValidationState_t::ValidationState_t(spv_diagnostic* diagnostic,
    194                                      const spv_const_context context)
    195     : diagnostic_(diagnostic),
    196       instruction_counter_(0),
    197       unresolved_forward_ids_{},
    198       operand_names_{},
    199       current_layout_section_(kLayoutCapabilities),
    200       module_functions_(),
    201       module_capabilities_(0u),
    202       grammar_(context),
    203       addressing_model_(SpvAddressingModelLogical),
    204       memory_model_(SpvMemoryModelSimple),
    205       in_function_(false) {}
    206 
    207 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
    208   unresolved_forward_ids_.insert(id);
    209   return SPV_SUCCESS;
    210 }
    211 
    212 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
    213   unresolved_forward_ids_.erase(id);
    214   return SPV_SUCCESS;
    215 }
    216 
    217 void ValidationState_t::AssignNameToId(uint32_t id, string name) {
    218   operand_names_[id] = name;
    219 }
    220 
    221 string ValidationState_t::getIdName(uint32_t id) const {
    222   std::stringstream out;
    223   out << id;
    224   if (operand_names_.find(id) != end(operand_names_)) {
    225     out << "[" << operand_names_.at(id) << "]";
    226   }
    227   return out.str();
    228 }
    229 
    230 string ValidationState_t::getIdOrName(uint32_t id) const {
    231   std::stringstream out;
    232   if (operand_names_.find(id) != end(operand_names_)) {
    233     out << operand_names_.at(id);
    234   } else {
    235     out << id;
    236   }
    237   return out.str();
    238 }
    239 
    240 size_t ValidationState_t::unresolved_forward_id_count() const {
    241   return unresolved_forward_ids_.size();
    242 }
    243 
    244 vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
    245   vector<uint32_t> out(begin(unresolved_forward_ids_),
    246                        end(unresolved_forward_ids_));
    247   return out;
    248 }
    249 
    250 bool ValidationState_t::IsDefinedId(uint32_t id) const {
    251   return usedefs_.FindDef(id).first;
    252 }
    253 
    254 // Increments the instruction count. Used for diagnostic
    255 int ValidationState_t::increment_instruction_count() {
    256   return instruction_counter_++;
    257 }
    258 
    259 ModuleLayoutSection ValidationState_t::current_layout_section() const {
    260   return current_layout_section_;
    261 }
    262 
    263 void ValidationState_t::ProgressToNextLayoutSectionOrder() {
    264   // Guard against going past the last element(kLayoutFunctionDefinitions)
    265   if (current_layout_section_ <= kLayoutFunctionDefinitions) {
    266     current_layout_section_ =
    267         static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
    268   }
    269 }
    270 
    271 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) {
    272   return IsInstructionInLayoutSection(current_layout_section_, op);
    273 }
    274 
    275 DiagnosticStream ValidationState_t::diag(spv_result_t error_code) const {
    276   return libspirv::DiagnosticStream(
    277       {0, 0, static_cast<size_t>(instruction_counter_)}, diagnostic_,
    278       error_code);
    279 }
    280 
    281 list<Function>& ValidationState_t::functions() { return module_functions_; }
    282 
    283 Function& ValidationState_t::current_function() {
    284   assert(in_function_body());
    285   return module_functions_.back();
    286 }
    287 
    288 bool ValidationState_t::in_function_body() const { return in_function_; }
    289 
    290 bool ValidationState_t::in_block() const {
    291   return module_functions_.empty() == false &&
    292          module_functions_.back().current_block() != nullptr;
    293 }
    294 
    295 void ValidationState_t::RegisterCapability(SpvCapability cap) {
    296   module_capabilities_ |= SPV_CAPABILITY_AS_MASK(cap);
    297   spv_operand_desc desc;
    298   if (SPV_SUCCESS ==
    299       grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc))
    300     libspirv::ForEach(desc->capabilities,
    301                       [this](SpvCapability c) { RegisterCapability(c); });
    302 }
    303 
    304 bool ValidationState_t::has_capability(SpvCapability cap) const {
    305   return (module_capabilities_ & SPV_CAPABILITY_AS_MASK(cap)) != 0;
    306 }
    307 
    308 bool ValidationState_t::HasAnyOf(spv_capability_mask_t capabilities) const {
    309   if (!capabilities)
    310     return true;  // No capabilities requested: trivially satisfied.
    311   bool found = false;
    312   libspirv::ForEach(capabilities, [&found, this](SpvCapability c) {
    313     found |= has_capability(c);
    314   });
    315   return found;
    316 }
    317 
    318 void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
    319   addressing_model_ = am;
    320 }
    321 
    322 SpvAddressingModel ValidationState_t::addressing_model() const {
    323   return addressing_model_;
    324 }
    325 
    326 void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
    327   memory_model_ = mm;
    328 }
    329 
    330 SpvMemoryModel ValidationState_t::memory_model() const {
    331   return memory_model_;
    332 }
    333 
    334 spv_result_t ValidationState_t::RegisterFunction(
    335     uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
    336     uint32_t function_type_id) {
    337   assert(in_function_body() == false &&
    338          "RegisterFunction can only be called when parsing the binary outside "
    339          "of another function");
    340   in_function_ = true;
    341   module_functions_.emplace_back(id, ret_type_id, function_control,
    342                                  function_type_id, *this);
    343 
    344   // TODO(umar): validate function type and type_id
    345 
    346   return SPV_SUCCESS;
    347 }
    348 
    349 spv_result_t ValidationState_t::RegisterFunctionEnd() {
    350   assert(in_function_body() == true &&
    351          "RegisterFunctionEnd can only be called when parsing the binary "
    352          "inside of another function");
    353   assert(in_block() == false &&
    354          "RegisterFunctionParameter can only be called when parsing the binary "
    355          "ouside of a block");
    356   current_function().RegisterFunctionEnd();
    357   in_function_ = false;
    358   return SPV_SUCCESS;
    359 }
    360 
    361 }  /// namespace libspirv
    362