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 #ifndef LIBSPIRV_VAL_VALIDATIONSTATE_H_
     16 #define LIBSPIRV_VAL_VALIDATIONSTATE_H_
     17 
     18 #include <deque>
     19 #include <set>
     20 #include <string>
     21 #include <unordered_map>
     22 #include <unordered_set>
     23 #include <vector>
     24 
     25 #include "assembly_grammar.h"
     26 #include "decoration.h"
     27 #include "diagnostic.h"
     28 #include "enum_set.h"
     29 #include "spirv-tools/libspirv.h"
     30 #include "spirv/1.2/spirv.h"
     31 #include "spirv_definition.h"
     32 #include "val/function.h"
     33 #include "val/instruction.h"
     34 
     35 namespace libspirv {
     36 
     37 /// This enum represents the sections of a SPIRV module. See section 2.4
     38 /// of the SPIRV spec for additional details of the order. The enumerant values
     39 /// are in the same order as the vector returned by GetModuleOrder
     40 enum ModuleLayoutSection {
     41   kLayoutCapabilities,          /// < Section 2.4 #1
     42   kLayoutExtensions,            /// < Section 2.4 #2
     43   kLayoutExtInstImport,         /// < Section 2.4 #3
     44   kLayoutMemoryModel,           /// < Section 2.4 #4
     45   kLayoutEntryPoint,            /// < Section 2.4 #5
     46   kLayoutExecutionMode,         /// < Section 2.4 #6
     47   kLayoutDebug1,                /// < Section 2.4 #7 > 1
     48   kLayoutDebug2,                /// < Section 2.4 #7 > 2
     49   kLayoutAnnotations,           /// < Section 2.4 #8
     50   kLayoutTypes,                 /// < Section 2.4 #9
     51   kLayoutFunctionDeclarations,  /// < Section 2.4 #10
     52   kLayoutFunctionDefinitions    /// < Section 2.4 #11
     53 };
     54 
     55 /// This class manages the state of the SPIR-V validation as it is being parsed.
     56 class ValidationState_t {
     57  public:
     58   // Features that can optionally be turned on by a capability.
     59   struct Feature {
     60     bool declare_int16_type = false;     // Allow OpTypeInt with 16 bit width?
     61     bool declare_float16_type = false;   // Allow OpTypeFloat with 16 bit width?
     62     bool free_fp_rounding_mode = false;  // Allow the FPRoundingMode decoration
     63                                          // and its vaules to be used without
     64                                          // requiring any capability
     65 
     66     // Allow functionalities enabled by VariablePointers capability.
     67     bool variable_pointers = false;
     68     // Allow functionalities enabled by VariablePointersStorageBuffer
     69     // capability.
     70     bool variable_pointers_storage_buffer = false;
     71   };
     72 
     73   ValidationState_t(const spv_const_context context,
     74                     const spv_const_validator_options opt);
     75 
     76   /// Returns the context
     77   spv_const_context context() const { return context_; }
     78 
     79   /// Returns the command line options
     80   spv_const_validator_options options() const { return options_; }
     81 
     82   /// Forward declares the id in the module
     83   spv_result_t ForwardDeclareId(uint32_t id);
     84 
     85   /// Removes a forward declared ID if it has been defined
     86   spv_result_t RemoveIfForwardDeclared(uint32_t id);
     87 
     88   /// Registers an ID as a forward pointer
     89   spv_result_t RegisterForwardPointer(uint32_t id);
     90 
     91   /// Returns whether or not an ID is a forward pointer
     92   bool IsForwardPointer(uint32_t id) const;
     93 
     94   /// Assigns a name to an ID
     95   void AssignNameToId(uint32_t id, std::string name);
     96 
     97   /// Returns a string representation of the ID in the format <id>[Name] where
     98   /// the <id> is the numeric valid of the id and the Name is a name assigned by
     99   /// the OpName instruction
    100   std::string getIdName(uint32_t id) const;
    101 
    102   /// Accessor function for ID bound.
    103   uint32_t getIdBound() const;
    104 
    105   /// Mutator function for ID bound.
    106   void setIdBound(uint32_t bound);
    107 
    108   /// Like getIdName but does not display the id if the \p id has a name
    109   std::string getIdOrName(uint32_t id) const;
    110 
    111   /// Returns the number of ID which have been forward referenced but not
    112   /// defined
    113   size_t unresolved_forward_id_count() const;
    114 
    115   /// Returns a vector of unresolved forward ids.
    116   std::vector<uint32_t> UnresolvedForwardIds() const;
    117 
    118   /// Returns true if the id has been defined
    119   bool IsDefinedId(uint32_t id) const;
    120 
    121   /// Increments the instruction count. Used for diagnostic
    122   int increment_instruction_count();
    123 
    124   /// Returns the current layout section which is being processed
    125   ModuleLayoutSection current_layout_section() const;
    126 
    127   /// Increments the module_layout_order_section_
    128   void ProgressToNextLayoutSectionOrder();
    129 
    130   /// Determines if the op instruction is part of the current section
    131   bool IsOpcodeInCurrentLayoutSection(SpvOp op);
    132 
    133   libspirv::DiagnosticStream diag(spv_result_t error_code) const;
    134 
    135   /// Returns the function states
    136   std::deque<Function>& functions();
    137 
    138   /// Returns the function states
    139   Function& current_function();
    140 
    141   /// Returns true if the called after a function instruction but before the
    142   /// function end instruction
    143   bool in_function_body() const;
    144 
    145   /// Returns true if called after a label instruction but before a branch
    146   /// instruction
    147   bool in_block() const;
    148 
    149   /// Registers the given <id> as an Entry Point.
    150   void RegisterEntryPointId(const uint32_t id) {
    151     entry_points_.push_back(id);
    152     entry_point_interfaces_.insert(std::make_pair(id, std::vector<uint32_t>()));
    153   }
    154 
    155   /// Returns a list of entry point function ids
    156   const std::vector<uint32_t>& entry_points() const { return entry_points_; }
    157 
    158   /// Adds a new interface id to the interfaces of the given entry point.
    159   void RegisterInterfaceForEntryPoint(uint32_t entry_point,
    160                                       uint32_t interface) {
    161     entry_point_interfaces_[entry_point].push_back(interface);
    162   }
    163 
    164   /// Returns the interfaces of a given entry point. If the given id is not a
    165   /// valid Entry Point id, std::out_of_range exception is thrown.
    166   const std::vector<uint32_t>& entry_point_interfaces(
    167       uint32_t entry_point) const {
    168     return entry_point_interfaces_.at(entry_point);
    169   }
    170 
    171   /// Inserts an <id> to the set of functions that are target of OpFunctionCall.
    172   void AddFunctionCallTarget(const uint32_t id) {
    173     function_call_targets_.insert(id);
    174   }
    175 
    176   /// Returns whether or not a function<id> is the target of OpFunctionCall.
    177   bool IsFunctionCallTarget(const uint32_t id) {
    178     return (function_call_targets_.find(id) != function_call_targets_.end());
    179   }
    180 
    181   /// Registers the capability and its dependent capabilities
    182   void RegisterCapability(SpvCapability cap);
    183 
    184   /// Registers the extension.
    185   void RegisterExtension(Extension ext);
    186 
    187   /// Registers the function in the module. Subsequent instructions will be
    188   /// called against this function
    189   spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id,
    190                                 SpvFunctionControlMask function_control,
    191                                 uint32_t function_type_id);
    192 
    193   /// Register a function end instruction
    194   spv_result_t RegisterFunctionEnd();
    195 
    196   /// Returns true if the capability is enabled in the module.
    197   bool HasCapability(SpvCapability cap) const {
    198     return module_capabilities_.Contains(cap);
    199   }
    200 
    201   /// Returns true if the extension is enabled in the module.
    202   bool HasExtension(Extension ext) const {
    203     return module_extensions_.Contains(ext);
    204   }
    205 
    206   /// Returns true if any of the capabilities is enabled, or if |capabilities|
    207   /// is an empty set.
    208   bool HasAnyOfCapabilities(const libspirv::CapabilitySet& capabilities) const;
    209 
    210   /// Returns true if any of the extensions is enabled, or if |extensions|
    211   /// is an empty set.
    212   bool HasAnyOfExtensions(const libspirv::ExtensionSet& extensions) const;
    213 
    214   /// Sets the addressing model of this module (logical/physical).
    215   void set_addressing_model(SpvAddressingModel am);
    216 
    217   /// Returns the addressing model of this module, or Logical if uninitialized.
    218   SpvAddressingModel addressing_model() const;
    219 
    220   /// Sets the memory model of this module.
    221   void set_memory_model(SpvMemoryModel mm);
    222 
    223   /// Returns the memory model of this module, or Simple if uninitialized.
    224   SpvMemoryModel memory_model() const;
    225 
    226   const AssemblyGrammar& grammar() const { return grammar_; }
    227 
    228   /// Registers the instruction
    229   void RegisterInstruction(const spv_parsed_instruction_t& inst);
    230 
    231   /// Registers the decoration for the given <id>
    232   void RegisterDecorationForId(uint32_t id, const Decoration& dec) {
    233     id_decorations_[id].push_back(dec);
    234   }
    235 
    236   /// Registers the list of decorations for the given <id>
    237   template <class InputIt>
    238   void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) {
    239     std::vector<Decoration>& cur_decs = id_decorations_[id];
    240     cur_decs.insert(cur_decs.end(), begin, end);
    241   }
    242 
    243   /// Registers the list of decorations for the given member of the given
    244   /// structure.
    245   template <class InputIt>
    246   void RegisterDecorationsForStructMember(uint32_t struct_id,
    247                                           uint32_t member_index, InputIt begin,
    248                                           InputIt end) {
    249     RegisterDecorationsForId(struct_id, begin, end);
    250     for (auto& decoration : id_decorations_[struct_id]) {
    251       decoration.set_struct_member_index(member_index);
    252     }
    253   }
    254 
    255   /// Returns all the decorations for the given <id>. If no decorations exist
    256   /// for the <id>, it registers an empty vector for it in the map and
    257   /// returns the empty vector.
    258   std::vector<Decoration>& id_decorations(uint32_t id) {
    259     return id_decorations_[id];
    260   }
    261 
    262   /// Finds id's def, if it exists.  If found, returns the definition otherwise
    263   /// nullptr
    264   const Instruction* FindDef(uint32_t id) const;
    265 
    266   /// Finds id's def, if it exists.  If found, returns the definition otherwise
    267   /// nullptr
    268   Instruction* FindDef(uint32_t id);
    269 
    270   /// Returns a deque of instructions in the order they appear in the binary
    271   const std::deque<Instruction>& ordered_instructions() const {
    272     return ordered_instructions_;
    273   }
    274 
    275   /// Returns a map of instructions mapped by their result id
    276   const std::unordered_map<uint32_t, Instruction*>& all_definitions() const {
    277     return all_definitions_;
    278   }
    279 
    280   /// Returns a vector containing the Ids of instructions that consume the given
    281   /// SampledImage id.
    282   std::vector<uint32_t> getSampledImageConsumers(uint32_t id) const;
    283 
    284   /// Records cons_id as a consumer of sampled_image_id.
    285   void RegisterSampledImageConsumer(uint32_t sampled_image_id,
    286                                     uint32_t cons_id);
    287 
    288   /// Returns the set of Global Variables.
    289   std::unordered_set<uint32_t>& global_vars() { return global_vars_; }
    290 
    291   /// Returns the set of Local Variables.
    292   std::unordered_set<uint32_t>& local_vars() { return local_vars_; }
    293 
    294   /// Returns the number of Global Variables.
    295   size_t num_global_vars() { return global_vars_.size(); }
    296 
    297   /// Returns the number of Local Variables.
    298   size_t num_local_vars() { return local_vars_.size(); }
    299 
    300   /// Inserts a new <id> to the set of Global Variables.
    301   void registerGlobalVariable(const uint32_t id) { global_vars_.insert(id); }
    302 
    303   /// Inserts a new <id> to the set of Local Variables.
    304   void registerLocalVariable(const uint32_t id) { local_vars_.insert(id); }
    305 
    306   /// Sets the struct nesting depth for a given struct ID
    307   void set_struct_nesting_depth(uint32_t id, uint32_t depth) {
    308     struct_nesting_depth_[id] = depth;
    309   }
    310 
    311   /// Returns the nesting depth of a given structure ID
    312   uint32_t struct_nesting_depth(uint32_t id) {
    313     return struct_nesting_depth_[id];
    314   }
    315 
    316   /// Records that the structure type has a member decorated with a built-in.
    317   void RegisterStructTypeWithBuiltInMember(uint32_t id) {
    318     builtin_structs_.insert(id);
    319   }
    320 
    321   /// Returns true if the struct type with the given Id has a BuiltIn member.
    322   bool IsStructTypeWithBuiltInMember(uint32_t id) const {
    323     return (builtin_structs_.find(id) != builtin_structs_.end());
    324   }
    325 
    326   // Returns the state of optional features.
    327   const Feature& features() const { return features_; }
    328 
    329   /// Adds the instruction data to unique_type_declarations_.
    330   /// Returns false if an identical type declaration already exists.
    331   bool RegisterUniqueTypeDeclaration(const spv_parsed_instruction_t& inst);
    332 
    333  private:
    334   ValidationState_t(const ValidationState_t&);
    335 
    336   const spv_const_context context_;
    337 
    338   /// Stores the Validator command line options. Must be a valid options object.
    339   const spv_const_validator_options options_;
    340 
    341   /// Tracks the number of instructions evaluated by the validator
    342   int instruction_counter_;
    343 
    344   /// IDs which have been forward declared but have not been defined
    345   std::unordered_set<uint32_t> unresolved_forward_ids_;
    346 
    347   /// IDs that have been declared as forward pointers.
    348   std::unordered_set<uint32_t> forward_pointer_ids_;
    349 
    350   /// Stores a vector of instructions that use the result of a given
    351   /// OpSampledImage instruction.
    352   std::unordered_map<uint32_t, std::vector<uint32_t>> sampled_image_consumers_;
    353 
    354   /// A map of operand IDs and their names defined by the OpName instruction
    355   std::unordered_map<uint32_t, std::string> operand_names_;
    356 
    357   /// The section of the code being processed
    358   ModuleLayoutSection current_layout_section_;
    359 
    360   /// A list of functions in the module
    361   std::deque<Function> module_functions_;
    362 
    363   /// Capabilities declared in the module
    364   libspirv::CapabilitySet module_capabilities_;
    365 
    366   /// Extensions declared in the module
    367   libspirv::ExtensionSet module_extensions_;
    368 
    369   /// List of all instructions in the order they appear in the binary
    370   std::deque<Instruction> ordered_instructions_;
    371 
    372   /// Instructions that can be referenced by Ids
    373   std::unordered_map<uint32_t, Instruction*> all_definitions_;
    374 
    375   /// IDs that are entry points, ie, arguments to OpEntryPoint.
    376   std::vector<uint32_t> entry_points_;
    377 
    378   /// Maps an entry point id to its interfaces.
    379   std::unordered_map<uint32_t, std::vector<uint32_t>> entry_point_interfaces_;
    380 
    381   /// Functions IDs that are target of OpFunctionCall.
    382   std::unordered_set<uint32_t> function_call_targets_;
    383 
    384   /// ID Bound from the Header
    385   uint32_t id_bound_;
    386 
    387   /// Set of Global Variable IDs (Storage Class other than 'Function')
    388   std::unordered_set<uint32_t> global_vars_;
    389 
    390   /// Set of Local Variable IDs ('Function' Storage Class)
    391   std::unordered_set<uint32_t> local_vars_;
    392 
    393   /// Set of struct types that have members with a BuiltIn decoration.
    394   std::unordered_set<uint32_t> builtin_structs_;
    395 
    396   /// Structure Nesting Depth
    397   std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_;
    398 
    399   /// Stores the list of decorations for a given <id>
    400   std::unordered_map<uint32_t, std::vector<Decoration>> id_decorations_;
    401 
    402   /// Stores type declarations which need to be unique (i.e. non-aggregates),
    403   /// in the form [opcode, operand words], result_id is not stored.
    404   /// Using ordered set to avoid the need for a vector hash function.
    405   /// The size of this container is expected not to exceed double-digits.
    406   std::set<std::vector<uint32_t>> unique_type_declarations_;
    407 
    408   AssemblyGrammar grammar_;
    409 
    410   SpvAddressingModel addressing_model_;
    411   SpvMemoryModel memory_model_;
    412 
    413   /// NOTE: See correspoding getter functions
    414   bool in_function_;
    415 
    416   // The state of optional features.  These are determined by capabilities
    417   // declared by the module.
    418   Feature features_;
    419 };
    420 
    421 }  /// namespace libspirv
    422 
    423 #endif  /// LIBSPIRV_VAL_VALIDATIONSTATE_H_
    424