Home | History | Annotate | Download | only in opt
      1 // Copyright (c) 2016 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 #ifndef SOURCE_OPT_INSTRUCTION_H_
     16 #define SOURCE_OPT_INSTRUCTION_H_
     17 
     18 #include <cassert>
     19 #include <functional>
     20 #include <memory>
     21 #include <string>
     22 #include <utility>
     23 #include <vector>
     24 
     25 #include "source/opcode.h"
     26 #include "source/operand.h"
     27 #include "source/util/ilist_node.h"
     28 #include "source/util/small_vector.h"
     29 
     30 #include "source/latest_version_glsl_std_450_header.h"
     31 #include "source/latest_version_spirv_header.h"
     32 #include "source/opt/reflect.h"
     33 #include "spirv-tools/libspirv.h"
     34 
     35 namespace spvtools {
     36 namespace opt {
     37 
     38 class Function;
     39 class IRContext;
     40 class Module;
     41 class InstructionList;
     42 
     43 // Relaxed logical addressing:
     44 //
     45 // In the logical addressing model, pointers cannot be stored or loaded.  This
     46 // is a useful assumption because it simplifies the aliasing significantly.
     47 // However, for the purpose of legalizing code generated from HLSL, we will have
     48 // to allow storing and loading of pointers to opaque objects and runtime
     49 // arrays.  This relaxation of the rule still implies that function and private
     50 // scope variables do not have any aliasing, so we can treat them as before.
     51 // This will be call the relaxed logical addressing model.
     52 //
     53 // This relaxation of the rule will be allowed by |GetBaseAddress|, but it will
     54 // enforce that no other pointers are stored or loaded.
     55 
     56 // About operand:
     57 //
     58 // In the SPIR-V specification, the term "operand" is used to mean any single
     59 // SPIR-V word following the leading wordcount-opcode word. Here, the term
     60 // "operand" is used to mean a *logical* operand. A logical operand may consist
     61 // of multiple SPIR-V words, which together make up the same component. For
     62 // example, a logical operand of a 64-bit integer needs two words to express.
     63 //
     64 // Further, we categorize logical operands into *in* and *out* operands.
     65 // In operands are operands actually serve as input to operations, while out
     66 // operands are operands that represent ids generated from operations (result
     67 // type id or result id). For example, for "OpIAdd %rtype %rid %inop1 %inop2",
     68 // "%inop1" and "%inop2" are in operands, while "%rtype" and "%rid" are out
     69 // operands.
     70 
     71 // A *logical* operand to a SPIR-V instruction. It can be the type id, result
     72 // id, or other additional operands carried in an instruction.
     73 struct Operand {
     74   using OperandData = utils::SmallVector<uint32_t, 2>;
     75   Operand(spv_operand_type_t t, OperandData&& w)
     76       : type(t), words(std::move(w)) {}
     77 
     78   Operand(spv_operand_type_t t, const OperandData& w) : type(t), words(w) {}
     79 
     80   spv_operand_type_t type;  // Type of this logical operand.
     81   OperandData words;        // Binary segments of this logical operand.
     82 
     83   friend bool operator==(const Operand& o1, const Operand& o2) {
     84     return o1.type == o2.type && o1.words == o2.words;
     85   }
     86 
     87   // TODO(antiagainst): create fields for literal number kind, width, etc.
     88 };
     89 
     90 inline bool operator!=(const Operand& o1, const Operand& o2) {
     91   return !(o1 == o2);
     92 }
     93 
     94 // A SPIR-V instruction. It contains the opcode and any additional logical
     95 // operand, including the result id (if any) and result type id (if any). It
     96 // may also contain line-related debug instruction (OpLine, OpNoLine) directly
     97 // appearing before this instruction. Note that the result id of an instruction
     98 // should never change after the instruction being built. If the result id
     99 // needs to change, the user should create a new instruction instead.
    100 class Instruction : public utils::IntrusiveNodeBase<Instruction> {
    101  public:
    102   using OperandList = std::vector<Operand>;
    103   using iterator = OperandList::iterator;
    104   using const_iterator = OperandList::const_iterator;
    105 
    106   // Creates a default OpNop instruction.
    107   // This exists solely for containers that can't do without. Should be removed.
    108   Instruction()
    109       : utils::IntrusiveNodeBase<Instruction>(),
    110         context_(nullptr),
    111         opcode_(SpvOpNop),
    112         has_type_id_(false),
    113         has_result_id_(false),
    114         unique_id_(0) {}
    115 
    116   // Creates a default OpNop instruction.
    117   Instruction(IRContext*);
    118   // Creates an instruction with the given opcode |op| and no additional logical
    119   // operands.
    120   Instruction(IRContext*, SpvOp);
    121   // Creates an instruction using the given spv_parsed_instruction_t |inst|. All
    122   // the data inside |inst| will be copied and owned in this instance. And keep
    123   // record of line-related debug instructions |dbg_line| ahead of this
    124   // instruction, if any.
    125   Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
    126               std::vector<Instruction>&& dbg_line = {});
    127 
    128   // Creates an instruction with the given opcode |op|, type id: |ty_id|,
    129   // result id: |res_id| and input operands: |in_operands|.
    130   Instruction(IRContext* c, SpvOp op, uint32_t ty_id, uint32_t res_id,
    131               const OperandList& in_operands);
    132 
    133   // TODO: I will want to remove these, but will first have to remove the use of
    134   // std::vector<Instruction>.
    135   Instruction(const Instruction&) = default;
    136   Instruction& operator=(const Instruction&) = default;
    137 
    138   Instruction(Instruction&&);
    139   Instruction& operator=(Instruction&&);
    140 
    141   virtual ~Instruction() = default;
    142 
    143   // Returns a newly allocated instruction that has the same operands, result,
    144   // and type as |this|.  The new instruction is not linked into any list.
    145   // It is the responsibility of the caller to make sure that the storage is
    146   // removed. It is the caller's responsibility to make sure that there is only
    147   // one instruction for each result id.
    148   Instruction* Clone(IRContext* c) const;
    149 
    150   IRContext* context() const { return context_; }
    151 
    152   SpvOp opcode() const { return opcode_; }
    153   // Sets the opcode of this instruction to a specific opcode. Note this may
    154   // invalidate the instruction.
    155   // TODO(qining): Remove this function when instruction building and insertion
    156   // is well implemented.
    157   void SetOpcode(SpvOp op) { opcode_ = op; }
    158   uint32_t type_id() const {
    159     return has_type_id_ ? GetSingleWordOperand(0) : 0;
    160   }
    161   uint32_t result_id() const {
    162     return has_result_id_ ? GetSingleWordOperand(has_type_id_ ? 1 : 0) : 0;
    163   }
    164   uint32_t unique_id() const {
    165     assert(unique_id_ != 0);
    166     return unique_id_;
    167   }
    168   // Returns the vector of line-related debug instructions attached to this
    169   // instruction and the caller can directly modify them.
    170   std::vector<Instruction>& dbg_line_insts() { return dbg_line_insts_; }
    171   const std::vector<Instruction>& dbg_line_insts() const {
    172     return dbg_line_insts_;
    173   }
    174 
    175   // Same semantics as in the base class except the list the InstructionList
    176   // containing |pos| will now assume ownership of |this|.
    177   // inline void MoveBefore(Instruction* pos);
    178   // inline void InsertAfter(Instruction* pos);
    179 
    180   // Begin and end iterators for operands.
    181   iterator begin() { return operands_.begin(); }
    182   iterator end() { return operands_.end(); }
    183   const_iterator begin() const { return operands_.cbegin(); }
    184   const_iterator end() const { return operands_.cend(); }
    185   // Const begin and end iterators for operands.
    186   const_iterator cbegin() const { return operands_.cbegin(); }
    187   const_iterator cend() const { return operands_.cend(); }
    188 
    189   // Gets the number of logical operands.
    190   uint32_t NumOperands() const {
    191     return static_cast<uint32_t>(operands_.size());
    192   }
    193   // Gets the number of SPIR-V words occupied by all logical operands.
    194   uint32_t NumOperandWords() const {
    195     return NumInOperandWords() + TypeResultIdCount();
    196   }
    197   // Gets the |index|-th logical operand.
    198   inline Operand& GetOperand(uint32_t index);
    199   inline const Operand& GetOperand(uint32_t index) const;
    200   // Adds |operand| to the list of operands of this instruction.
    201   // It is the responsibility of the caller to make sure
    202   // that the instruction remains valid.
    203   inline void AddOperand(Operand&& operand);
    204   // Gets the |index|-th logical operand as a single SPIR-V word. This method is
    205   // not expected to be used with logical operands consisting of multiple SPIR-V
    206   // words.
    207   uint32_t GetSingleWordOperand(uint32_t index) const;
    208   // Sets the |index|-th in-operand's data to the given |data|.
    209   inline void SetInOperand(uint32_t index, Operand::OperandData&& data);
    210   // Sets the |index|-th operand's data to the given |data|.
    211   // This is for in-operands modification only, but with |index| expressed in
    212   // terms of operand index rather than in-operand index.
    213   inline void SetOperand(uint32_t index, Operand::OperandData&& data);
    214   // Replace all of the in operands with those in |new_operands|.
    215   inline void SetInOperands(OperandList&& new_operands);
    216   // Sets the result type id.
    217   inline void SetResultType(uint32_t ty_id);
    218   // Sets the result id
    219   inline void SetResultId(uint32_t res_id);
    220   inline bool HasResultId() const { return has_result_id_; }
    221   // Remove the |index|-th operand
    222   void RemoveOperand(uint32_t index) {
    223     operands_.erase(operands_.begin() + index);
    224   }
    225 
    226   // The following methods are similar to the above, but are for in operands.
    227   uint32_t NumInOperands() const {
    228     return static_cast<uint32_t>(operands_.size() - TypeResultIdCount());
    229   }
    230   uint32_t NumInOperandWords() const;
    231   Operand& GetInOperand(uint32_t index) {
    232     return GetOperand(index + TypeResultIdCount());
    233   }
    234   const Operand& GetInOperand(uint32_t index) const {
    235     return GetOperand(index + TypeResultIdCount());
    236   }
    237   uint32_t GetSingleWordInOperand(uint32_t index) const {
    238     return GetSingleWordOperand(index + TypeResultIdCount());
    239   }
    240   void RemoveInOperand(uint32_t index) {
    241     operands_.erase(operands_.begin() + index + TypeResultIdCount());
    242   }
    243 
    244   // Returns true if this instruction is OpNop.
    245   inline bool IsNop() const;
    246   // Turns this instruction to OpNop. This does not clear out all preceding
    247   // line-related debug instructions.
    248   inline void ToNop();
    249 
    250   // Runs the given function |f| on this instruction and optionally on the
    251   // preceding debug line instructions.  The function will always be run
    252   // if this is itself a debug line instruction.
    253   inline void ForEachInst(const std::function<void(Instruction*)>& f,
    254                           bool run_on_debug_line_insts = false);
    255   inline void ForEachInst(const std::function<void(const Instruction*)>& f,
    256                           bool run_on_debug_line_insts = false) const;
    257 
    258   // Runs the given function |f| on this instruction and optionally on the
    259   // preceding debug line instructions.  The function will always be run
    260   // if this is itself a debug line instruction. If |f| returns false,
    261   // iteration is terminated and this function returns false.
    262   inline bool WhileEachInst(const std::function<bool(Instruction*)>& f,
    263                             bool run_on_debug_line_insts = false);
    264   inline bool WhileEachInst(const std::function<bool(const Instruction*)>& f,
    265                             bool run_on_debug_line_insts = false) const;
    266 
    267   // Runs the given function |f| on all operand ids.
    268   //
    269   // |f| should not transform an ID into 0, as 0 is an invalid ID.
    270   inline void ForEachId(const std::function<void(uint32_t*)>& f);
    271   inline void ForEachId(const std::function<void(const uint32_t*)>& f) const;
    272 
    273   // Runs the given function |f| on all "in" operand ids.
    274   inline void ForEachInId(const std::function<void(uint32_t*)>& f);
    275   inline void ForEachInId(const std::function<void(const uint32_t*)>& f) const;
    276 
    277   // Runs the given function |f| on all "in" operand ids. If |f| returns false,
    278   // iteration is terminated and this function returns false.
    279   inline bool WhileEachInId(const std::function<bool(uint32_t*)>& f);
    280   inline bool WhileEachInId(
    281       const std::function<bool(const uint32_t*)>& f) const;
    282 
    283   // Runs the given function |f| on all "in" operands.
    284   inline void ForEachInOperand(const std::function<void(uint32_t*)>& f);
    285   inline void ForEachInOperand(
    286       const std::function<void(const uint32_t*)>& f) const;
    287 
    288   // Runs the given function |f| on all "in" operands. If |f| returns false,
    289   // iteration is terminated and this function return false.
    290   inline bool WhileEachInOperand(const std::function<bool(uint32_t*)>& f);
    291   inline bool WhileEachInOperand(
    292       const std::function<bool(const uint32_t*)>& f) const;
    293 
    294   // Returns true if any operands can be labels
    295   inline bool HasLabels() const;
    296 
    297   // Pushes the binary segments for this instruction into the back of *|binary|.
    298   void ToBinaryWithoutAttachedDebugInsts(std::vector<uint32_t>* binary) const;
    299 
    300   // Replaces the operands to the instruction with |new_operands|. The caller
    301   // is responsible for building a complete and valid list of operands for
    302   // this instruction.
    303   void ReplaceOperands(const OperandList& new_operands);
    304 
    305   // Returns true if the instruction annotates an id with a decoration.
    306   inline bool IsDecoration() const;
    307 
    308   // Returns true if the instruction is known to be a load from read-only
    309   // memory.
    310   bool IsReadOnlyLoad() const;
    311 
    312   // Returns the instruction that gives the base address of an address
    313   // calculation.  The instruction must be a load, as defined by |IsLoad|,
    314   // store, copy, or access chain instruction.  In logical addressing mode, will
    315   // return an OpVariable or OpFunctionParameter instruction. For relaxed
    316   // logical addressing, it would also return a load of a pointer to an opaque
    317   // object.  For physical addressing mode, could return other types of
    318   // instructions.
    319   Instruction* GetBaseAddress() const;
    320 
    321   // Returns true if the instruction loads from memory or samples an image, and
    322   // stores the result into an id. It considers only core instructions.
    323   // Memory-to-memory instructions are not considered loads.
    324   inline bool IsLoad() const;
    325 
    326   // Returns true if the instruction declares a variable that is read-only.
    327   bool IsReadOnlyVariable() const;
    328 
    329   // The following functions check for the various descriptor types defined in
    330   // the Vulkan specification section 13.1.
    331 
    332   // Returns true if the instruction defines a pointer type that points to a
    333   // storage image.
    334   bool IsVulkanStorageImage() const;
    335 
    336   // Returns true if the instruction defines a pointer type that points to a
    337   // sampled image.
    338   bool IsVulkanSampledImage() const;
    339 
    340   // Returns true if the instruction defines a pointer type that points to a
    341   // storage texel buffer.
    342   bool IsVulkanStorageTexelBuffer() const;
    343 
    344   // Returns true if the instruction defines a pointer type that points to a
    345   // storage buffer.
    346   bool IsVulkanStorageBuffer() const;
    347 
    348   // Returns true if the instruction defines a pointer type that points to a
    349   // uniform buffer.
    350   bool IsVulkanUniformBuffer() const;
    351 
    352   // Returns true if the instruction is an atom operation that uses original
    353   // value.
    354   inline bool IsAtomicWithLoad() const;
    355 
    356   // Returns true if the instruction is an atom operation.
    357   inline bool IsAtomicOp() const;
    358 
    359   // Returns true if this instruction is a branch or switch instruction (either
    360   // conditional or not).
    361   bool IsBranch() const { return spvOpcodeIsBranch(opcode()); }
    362 
    363   // Returns true if this instruction causes the function to finish execution
    364   // and return to its caller
    365   bool IsReturn() const { return spvOpcodeIsReturn(opcode()); }
    366 
    367   // Returns true if this instruction exits this function or aborts execution.
    368   bool IsReturnOrAbort() const { return spvOpcodeIsReturnOrAbort(opcode()); }
    369 
    370   // Returns the id for the |element|'th subtype. If the |this| is not a
    371   // composite type, this function returns 0.
    372   uint32_t GetTypeComponent(uint32_t element) const;
    373 
    374   // Returns true if this instruction is a basic block terminator.
    375   bool IsBlockTerminator() const {
    376     return spvOpcodeIsBlockTerminator(opcode());
    377   }
    378 
    379   // Returns true if |this| is an instruction that define an opaque type.  Since
    380   // runtime array have similar characteristics they are included as opaque
    381   // types.
    382   bool IsOpaqueType() const;
    383 
    384   // Returns true if |this| is an instruction which could be folded into a
    385   // constant value.
    386   bool IsFoldable() const;
    387 
    388   // Returns true if |this| is an instruction which could be folded into a
    389   // constant value by |FoldScalar|.
    390   bool IsFoldableByFoldScalar() const;
    391 
    392   // Returns true if we are allowed to fold or otherwise manipulate the
    393   // instruction that defines |id| in the given context. This includes not
    394   // handling NaN values.
    395   bool IsFloatingPointFoldingAllowed() const;
    396 
    397   inline bool operator==(const Instruction&) const;
    398   inline bool operator!=(const Instruction&) const;
    399   inline bool operator<(const Instruction&) const;
    400 
    401   Instruction* InsertBefore(std::vector<std::unique_ptr<Instruction>>&& list);
    402   Instruction* InsertBefore(std::unique_ptr<Instruction>&& i);
    403   using utils::IntrusiveNodeBase<Instruction>::InsertBefore;
    404 
    405   // Returns true if |this| is an instruction defining a constant, but not a
    406   // Spec constant.
    407   inline bool IsConstant() const;
    408 
    409   // Returns true if |this| is an instruction with an opcode safe to move
    410   bool IsOpcodeCodeMotionSafe() const;
    411 
    412   // Pretty-prints |inst|.
    413   //
    414   // Provides the disassembly of a specific instruction. Utilizes |inst|'s
    415   // context to provide the correct interpretation of types, constants, etc.
    416   //
    417   // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER
    418   // is always added to |options|.
    419   std::string PrettyPrint(uint32_t options = 0u) const;
    420 
    421   // Returns true if the result can be a vector and the result of each component
    422   // depends on the corresponding component of any vector inputs.
    423   bool IsScalarizable() const;
    424 
    425   // Return true if the only effect of this instructions is the result.
    426   bool IsOpcodeSafeToDelete() const;
    427 
    428   // Returns true if it is valid to use the result of |inst| as the base
    429   // pointer for a load or store.  In this case, valid is defined by the relaxed
    430   // logical addressing rules when using logical addressing.  Normal validation
    431   // rules for physical addressing.
    432   bool IsValidBasePointer() const;
    433 
    434   // Dump this instruction on stderr.  Useful when running interactive
    435   // debuggers.
    436   void Dump() const;
    437 
    438  private:
    439   // Returns the total count of result type id and result id.
    440   uint32_t TypeResultIdCount() const {
    441     if (has_type_id_ && has_result_id_) return 2;
    442     if (has_type_id_ || has_result_id_) return 1;
    443     return 0;
    444   }
    445 
    446   // Returns true if the instruction declares a variable that is read-only.  The
    447   // first version assumes the module is a shader module.  The second assumes a
    448   // kernel.
    449   bool IsReadOnlyVariableShaders() const;
    450   bool IsReadOnlyVariableKernel() const;
    451 
    452   // Returns true if the result of |inst| can be used as the base image for an
    453   // instruction that samples a image, reads an image, or writes to an image.
    454   bool IsValidBaseImage() const;
    455 
    456   IRContext* context_;  // IR Context
    457   SpvOp opcode_;        // Opcode
    458   bool has_type_id_;    // True if the instruction has a type id
    459   bool has_result_id_;  // True if the instruction has a result id
    460   uint32_t unique_id_;  // Unique instruction id
    461   // All logical operands, including result type id and result id.
    462   OperandList operands_;
    463   // Opline and OpNoLine instructions preceding this instruction. Note that for
    464   // Instructions representing OpLine or OpNonLine itself, this field should be
    465   // empty.
    466   std::vector<Instruction> dbg_line_insts_;
    467 
    468   friend InstructionList;
    469 };
    470 
    471 // Pretty-prints |inst| to |str| and returns |str|.
    472 //
    473 // Provides the disassembly of a specific instruction. Utilizes |inst|'s context
    474 // to provide the correct interpretation of types, constants, etc.
    475 //
    476 // Disassembly uses raw ids (not pretty printed names).
    477 std::ostream& operator<<(std::ostream& str, const Instruction& inst);
    478 
    479 inline bool Instruction::operator==(const Instruction& other) const {
    480   return unique_id() == other.unique_id();
    481 }
    482 
    483 inline bool Instruction::operator!=(const Instruction& other) const {
    484   return !(*this == other);
    485 }
    486 
    487 inline bool Instruction::operator<(const Instruction& other) const {
    488   return unique_id() < other.unique_id();
    489 }
    490 
    491 inline Operand& Instruction::GetOperand(uint32_t index) {
    492   assert(index < operands_.size() && "operand index out of bound");
    493   return operands_[index];
    494 }
    495 
    496 inline const Operand& Instruction::GetOperand(uint32_t index) const {
    497   assert(index < operands_.size() && "operand index out of bound");
    498   return operands_[index];
    499 }
    500 
    501 inline void Instruction::AddOperand(Operand&& operand) {
    502   operands_.push_back(std::move(operand));
    503 }
    504 
    505 inline void Instruction::SetInOperand(uint32_t index,
    506                                       Operand::OperandData&& data) {
    507   SetOperand(index + TypeResultIdCount(), std::move(data));
    508 }
    509 
    510 inline void Instruction::SetOperand(uint32_t index,
    511                                     Operand::OperandData&& data) {
    512   assert(index < operands_.size() && "operand index out of bound");
    513   assert(index >= TypeResultIdCount() && "operand is not a in-operand");
    514   operands_[index].words = std::move(data);
    515 }
    516 
    517 inline void Instruction::SetInOperands(OperandList&& new_operands) {
    518   // Remove the old in operands.
    519   operands_.erase(operands_.begin() + TypeResultIdCount(), operands_.end());
    520   // Add the new in operands.
    521   operands_.insert(operands_.end(), new_operands.begin(), new_operands.end());
    522 }
    523 
    524 inline void Instruction::SetResultId(uint32_t res_id) {
    525   // TODO(dsinclair): Allow setting a result id if there wasn't one
    526   // previously. Need to make room in the operands_ array to place the result,
    527   // and update the has_result_id_ flag.
    528   assert(has_result_id_);
    529 
    530   // TODO(dsinclair): Allow removing the result id. This needs to make sure,
    531   // if there was a result id previously to remove it from the operands_ array
    532   // and reset the has_result_id_ flag.
    533   assert(res_id != 0);
    534 
    535   auto ridx = has_type_id_ ? 1 : 0;
    536   operands_[ridx].words = {res_id};
    537 }
    538 
    539 inline void Instruction::SetResultType(uint32_t ty_id) {
    540   // TODO(dsinclair): Allow setting a type id if there wasn't one
    541   // previously. Need to make room in the operands_ array to place the result,
    542   // and update the has_type_id_ flag.
    543   assert(has_type_id_);
    544 
    545   // TODO(dsinclair): Allow removing the type id. This needs to make sure,
    546   // if there was a type id previously to remove it from the operands_ array
    547   // and reset the has_type_id_ flag.
    548   assert(ty_id != 0);
    549 
    550   operands_.front().words = {ty_id};
    551 }
    552 
    553 inline bool Instruction::IsNop() const {
    554   return opcode_ == SpvOpNop && !has_type_id_ && !has_result_id_ &&
    555          operands_.empty();
    556 }
    557 
    558 inline void Instruction::ToNop() {
    559   opcode_ = SpvOpNop;
    560   has_type_id_ = false;
    561   has_result_id_ = false;
    562   operands_.clear();
    563 }
    564 
    565 inline bool Instruction::WhileEachInst(
    566     const std::function<bool(Instruction*)>& f, bool run_on_debug_line_insts) {
    567   if (run_on_debug_line_insts) {
    568     for (auto& dbg_line : dbg_line_insts_) {
    569       if (!f(&dbg_line)) return false;
    570     }
    571   }
    572   return f(this);
    573 }
    574 
    575 inline bool Instruction::WhileEachInst(
    576     const std::function<bool(const Instruction*)>& f,
    577     bool run_on_debug_line_insts) const {
    578   if (run_on_debug_line_insts) {
    579     for (auto& dbg_line : dbg_line_insts_) {
    580       if (!f(&dbg_line)) return false;
    581     }
    582   }
    583   return f(this);
    584 }
    585 
    586 inline void Instruction::ForEachInst(const std::function<void(Instruction*)>& f,
    587                                      bool run_on_debug_line_insts) {
    588   WhileEachInst(
    589       [&f](Instruction* inst) {
    590         f(inst);
    591         return true;
    592       },
    593       run_on_debug_line_insts);
    594 }
    595 
    596 inline void Instruction::ForEachInst(
    597     const std::function<void(const Instruction*)>& f,
    598     bool run_on_debug_line_insts) const {
    599   WhileEachInst(
    600       [&f](const Instruction* inst) {
    601         f(inst);
    602         return true;
    603       },
    604       run_on_debug_line_insts);
    605 }
    606 
    607 inline void Instruction::ForEachId(const std::function<void(uint32_t*)>& f) {
    608   for (auto& opnd : operands_)
    609     if (spvIsIdType(opnd.type)) f(&opnd.words[0]);
    610 }
    611 
    612 inline void Instruction::ForEachId(
    613     const std::function<void(const uint32_t*)>& f) const {
    614   for (const auto& opnd : operands_)
    615     if (spvIsIdType(opnd.type)) f(&opnd.words[0]);
    616 }
    617 
    618 inline bool Instruction::WhileEachInId(
    619     const std::function<bool(uint32_t*)>& f) {
    620   for (auto& opnd : operands_) {
    621     if (spvIsInIdType(opnd.type)) {
    622       if (!f(&opnd.words[0])) return false;
    623     }
    624   }
    625   return true;
    626 }
    627 
    628 inline bool Instruction::WhileEachInId(
    629     const std::function<bool(const uint32_t*)>& f) const {
    630   for (const auto& opnd : operands_) {
    631     if (spvIsInIdType(opnd.type)) {
    632       if (!f(&opnd.words[0])) return false;
    633     }
    634   }
    635   return true;
    636 }
    637 
    638 inline void Instruction::ForEachInId(const std::function<void(uint32_t*)>& f) {
    639   WhileEachInId([&f](uint32_t* id) {
    640     f(id);
    641     return true;
    642   });
    643 }
    644 
    645 inline void Instruction::ForEachInId(
    646     const std::function<void(const uint32_t*)>& f) const {
    647   WhileEachInId([&f](const uint32_t* id) {
    648     f(id);
    649     return true;
    650   });
    651 }
    652 
    653 inline bool Instruction::WhileEachInOperand(
    654     const std::function<bool(uint32_t*)>& f) {
    655   for (auto& opnd : operands_) {
    656     switch (opnd.type) {
    657       case SPV_OPERAND_TYPE_RESULT_ID:
    658       case SPV_OPERAND_TYPE_TYPE_ID:
    659         break;
    660       default:
    661         if (!f(&opnd.words[0])) return false;
    662         break;
    663     }
    664   }
    665   return true;
    666 }
    667 
    668 inline bool Instruction::WhileEachInOperand(
    669     const std::function<bool(const uint32_t*)>& f) const {
    670   for (const auto& opnd : operands_) {
    671     switch (opnd.type) {
    672       case SPV_OPERAND_TYPE_RESULT_ID:
    673       case SPV_OPERAND_TYPE_TYPE_ID:
    674         break;
    675       default:
    676         if (!f(&opnd.words[0])) return false;
    677         break;
    678     }
    679   }
    680   return true;
    681 }
    682 
    683 inline void Instruction::ForEachInOperand(
    684     const std::function<void(uint32_t*)>& f) {
    685   WhileEachInOperand([&f](uint32_t* op) {
    686     f(op);
    687     return true;
    688   });
    689 }
    690 
    691 inline void Instruction::ForEachInOperand(
    692     const std::function<void(const uint32_t*)>& f) const {
    693   WhileEachInOperand([&f](const uint32_t* op) {
    694     f(op);
    695     return true;
    696   });
    697 }
    698 
    699 inline bool Instruction::HasLabels() const {
    700   switch (opcode_) {
    701     case SpvOpSelectionMerge:
    702     case SpvOpBranch:
    703     case SpvOpLoopMerge:
    704     case SpvOpBranchConditional:
    705     case SpvOpSwitch:
    706     case SpvOpPhi:
    707       return true;
    708       break;
    709     default:
    710       break;
    711   }
    712   return false;
    713 }
    714 
    715 bool Instruction::IsDecoration() const {
    716   return spvOpcodeIsDecoration(opcode());
    717 }
    718 
    719 bool Instruction::IsLoad() const { return spvOpcodeIsLoad(opcode()); }
    720 
    721 bool Instruction::IsAtomicWithLoad() const {
    722   return spvOpcodeIsAtomicWithLoad(opcode());
    723 }
    724 
    725 bool Instruction::IsAtomicOp() const { return spvOpcodeIsAtomicOp(opcode()); }
    726 
    727 bool Instruction::IsConstant() const {
    728   return IsCompileTimeConstantInst(opcode());
    729 }
    730 }  // namespace opt
    731 }  // namespace spvtools
    732 
    733 #endif  // SOURCE_OPT_INSTRUCTION_H_
    734