/src/shaderc/third_party/spirv-tools/source/opt/instruction.h
Line  | Count  | Source  | 
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 "NonSemanticShaderDebugInfo100.h"  | 
26  |  | #include "OpenCLDebugInfo100.h"  | 
27  |  | #include "source/binary.h"  | 
28  |  | #include "source/common_debug_info.h"  | 
29  |  | #include "source/latest_version_glsl_std_450_header.h"  | 
30  |  | #include "source/latest_version_spirv_header.h"  | 
31  |  | #include "source/opcode.h"  | 
32  |  | #include "source/operand.h"  | 
33  |  | #include "source/opt/reflect.h"  | 
34  |  | #include "source/util/ilist_node.h"  | 
35  |  | #include "source/util/small_vector.h"  | 
36  |  | #include "source/util/string_utils.h"  | 
37  |  | #include "spirv-tools/libspirv.h"  | 
38  |  |  | 
39  |  | constexpr uint32_t kNoDebugScope = 0;  | 
40  |  | constexpr uint32_t kNoInlinedAt = 0;  | 
41  |  |  | 
42  |  | namespace spvtools { | 
43  |  | namespace opt { | 
44  |  |  | 
45  |  | class Function;  | 
46  |  | class IRContext;  | 
47  |  | class Module;  | 
48  |  | class InstructionList;  | 
49  |  |  | 
50  |  | // Relaxed logical addressing:  | 
51  |  | //  | 
52  |  | // In the logical addressing model, pointers cannot be stored or loaded.  This  | 
53  |  | // is a useful assumption because it simplifies the aliasing significantly.  | 
54  |  | // However, for the purpose of legalizing code generated from HLSL, we will have  | 
55  |  | // to allow storing and loading of pointers to opaque objects and runtime  | 
56  |  | // arrays.  This relaxation of the rule still implies that function and private  | 
57  |  | // scope variables do not have any aliasing, so we can treat them as before.  | 
58  |  | // This will be call the relaxed logical addressing model.  | 
59  |  | //  | 
60  |  | // This relaxation of the rule will be allowed by |GetBaseAddress|, but it will  | 
61  |  | // enforce that no other pointers are stored or loaded.  | 
62  |  |  | 
63  |  | // About operand:  | 
64  |  | //  | 
65  |  | // In the SPIR-V specification, the term "operand" is used to mean any single  | 
66  |  | // SPIR-V word following the leading wordcount-opcode word. Here, the term  | 
67  |  | // "operand" is used to mean a *logical* operand. A logical operand may consist  | 
68  |  | // of multiple SPIR-V words, which together make up the same component. For  | 
69  |  | // example, a logical operand of a 64-bit integer needs two words to express.  | 
70  |  | //  | 
71  |  | // Further, we categorize logical operands into *in* and *out* operands.  | 
72  |  | // In operands are operands actually serve as input to operations, while out  | 
73  |  | // operands are operands that represent ids generated from operations (result  | 
74  |  | // type id or result id). For example, for "OpIAdd %rtype %rid %inop1 %inop2",  | 
75  |  | // "%inop1" and "%inop2" are in operands, while "%rtype" and "%rid" are out  | 
76  |  | // operands.  | 
77  |  |  | 
78  |  | // A *logical* operand to a SPIR-V instruction. It can be the type id, result  | 
79  |  | // id, or other additional operands carried in an instruction.  | 
80  |  | struct Operand { | 
81  |  |   using OperandData = utils::SmallVector<uint32_t, 2>;  | 
82  |  |   Operand(spv_operand_type_t t, OperandData&& w)  | 
83  | 826k  |       : type(t), words(std::move(w)) {} | 
84  |  |  | 
85  | 111k  |   Operand(spv_operand_type_t t, const OperandData& w) : type(t), words(w) {} | 
86  |  |  | 
87  |  |   template <class InputIt>  | 
88  |  |   Operand(spv_operand_type_t t, InputIt firstOperandData,  | 
89  |  |           InputIt lastOperandData)  | 
90  | 687k  |       : type(t), words(firstOperandData, lastOperandData) {} | 
91  |  |  | 
92  |  |   spv_operand_type_t type;  // Type of this logical operand.  | 
93  |  |   OperandData words;        // Binary segments of this logical operand.  | 
94  |  |  | 
95  | 474  |   uint32_t AsId() const { | 
96  | 474  |     assert(spvIsIdType(type));  | 
97  | 474  |     assert(words.size() == 1);  | 
98  | 474  |     return words[0];  | 
99  | 474  |   }  | 
100  |  |  | 
101  |  |   // Returns a string operand as a std::string.  | 
102  | 62.9k  |   std::string AsString() const { | 
103  | 62.9k  |     assert(type == SPV_OPERAND_TYPE_LITERAL_STRING);  | 
104  | 62.9k  |     return spvtools::utils::MakeString(words);  | 
105  | 62.9k  |   }  | 
106  |  |  | 
107  |  |   // Returns a literal integer operand as a uint64_t  | 
108  | 0  |   uint64_t AsLiteralUint64() const { | 
109  | 0  |     assert(type == SPV_OPERAND_TYPE_LITERAL_INTEGER ||  | 
110  | 0  |            type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER ||  | 
111  | 0  |            type == SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER ||  | 
112  | 0  |            type == SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER);  | 
113  | 0  |     assert(1 <= words.size());  | 
114  | 0  |     assert(words.size() <= 2);  | 
115  | 0  |     uint64_t result = 0;  | 
116  | 0  |     if (words.size() > 0) {  // Needed to avoid maybe-uninitialized GCC warning | 
117  | 0  |       uint32_t low = words[0];  | 
118  | 0  |       result = uint64_t(low);  | 
119  | 0  |     }  | 
120  | 0  |     if (words.size() > 1) { | 
121  | 0  |       uint32_t high = words[1];  | 
122  | 0  |       result = result | (uint64_t(high) << 32);  | 
123  | 0  |     }  | 
124  | 0  |     return result;  | 
125  | 0  |   }  | 
126  |  |  | 
127  | 51.0k  |   friend bool operator==(const Operand& o1, const Operand& o2) { | 
128  | 51.0k  |     return o1.type == o2.type && o1.words == o2.words;  | 
129  | 51.0k  |   }  | 
130  |  |  | 
131  |  |   // TODO(antiagainst): create fields for literal number kind, width, etc.  | 
132  |  | };  | 
133  |  |  | 
134  | 51.0k  | inline bool operator!=(const Operand& o1, const Operand& o2) { | 
135  | 51.0k  |   return !(o1 == o2);  | 
136  | 51.0k  | }  | 
137  |  |  | 
138  |  | // This structure is used to represent a DebugScope instruction from  | 
139  |  | // the OpenCL.100.DebugInfo extended instruction set. Note that we can  | 
140  |  | // ignore the result id of DebugScope instruction because it is not  | 
141  |  | // used for anything. We do not keep it to reduce the size of  | 
142  |  | // structure.  | 
143  |  | // TODO: Let validator check that the result id is not used anywhere.  | 
144  |  | class DebugScope { | 
145  |  |  public:  | 
146  |  |   DebugScope(uint32_t lexical_scope, uint32_t inlined_at)  | 
147  | 629k  |       : lexical_scope_(lexical_scope), inlined_at_(inlined_at) {} | 
148  |  |  | 
149  | 125k  |   inline bool operator!=(const DebugScope& d) const { | 
150  | 125k  |     return lexical_scope_ != d.lexical_scope_ || inlined_at_ != d.inlined_at_;  | 
151  | 125k  |   }  | 
152  |  |  | 
153  |  |   // Accessor functions for |lexical_scope_|.  | 
154  | 2.36M  |   uint32_t GetLexicalScope() const { return lexical_scope_; } | 
155  | 0  |   void SetLexicalScope(uint32_t scope) { lexical_scope_ = scope; } | 
156  |  |  | 
157  |  |   // Accessor functions for |inlined_at_|.  | 
158  | 2.21M  |   uint32_t GetInlinedAt() const { return inlined_at_; } | 
159  | 75.6k  |   void SetInlinedAt(uint32_t at) { inlined_at_ = at; } | 
160  |  |  | 
161  |  |   // Pushes the binary segments for this DebugScope instruction into  | 
162  |  |   // the back of *|binary|.  | 
163  |  |   void ToBinary(uint32_t type_id, uint32_t result_id, uint32_t ext_set,  | 
164  |  |                 std::vector<uint32_t>* binary) const;  | 
165  |  |  | 
166  |  |  private:  | 
167  |  |   // The result id of the lexical scope in which this debug scope is  | 
168  |  |   // contained. The value is kNoDebugScope if there is no scope.  | 
169  |  |   uint32_t lexical_scope_;  | 
170  |  |  | 
171  |  |   // The result id of DebugInlinedAt if instruction in this debug scope  | 
172  |  |   // is inlined. The value is kNoInlinedAt if it is not inlined.  | 
173  |  |   uint32_t inlined_at_;  | 
174  |  | };  | 
175  |  |  | 
176  |  | // A SPIR-V instruction. It contains the opcode and any additional logical  | 
177  |  | // operand, including the result id (if any) and result type id (if any). It  | 
178  |  | // may also contain line-related debug instruction (OpLine, OpNoLine) directly  | 
179  |  | // appearing before this instruction. Note that the result id of an instruction  | 
180  |  | // should never change after the instruction being built. If the result id  | 
181  |  | // needs to change, the user should create a new instruction instead.  | 
182  |  | class Instruction : public utils::IntrusiveNodeBase<Instruction> { | 
183  |  |  public:  | 
184  |  |   using OperandList = std::vector<Operand>;  | 
185  |  |   using iterator = OperandList::iterator;  | 
186  |  |   using const_iterator = OperandList::const_iterator;  | 
187  |  |  | 
188  |  |   // Creates a default OpNop instruction.  | 
189  |  |   // This exists solely for containers that can't do without. Should be removed.  | 
190  |  |   Instruction()  | 
191  | 48.0k  |       : utils::IntrusiveNodeBase<Instruction>(),  | 
192  | 48.0k  |         context_(nullptr),  | 
193  | 48.0k  |         opcode_(spv::Op::OpNop),  | 
194  | 48.0k  |         has_type_id_(false),  | 
195  | 48.0k  |         has_result_id_(false),  | 
196  | 48.0k  |         unique_id_(0),  | 
197  | 48.0k  |         dbg_scope_(kNoDebugScope, kNoInlinedAt) {} | 
198  |  |  | 
199  |  |   // Creates a default OpNop instruction.  | 
200  |  |   Instruction(IRContext*);  | 
201  |  |   // Creates an instruction with the given opcode |op| and no additional logical  | 
202  |  |   // operands.  | 
203  |  |   Instruction(IRContext*, spv::Op);  | 
204  |  |   // Creates an instruction using the given spv_parsed_instruction_t |inst|. All  | 
205  |  |   // the data inside |inst| will be copied and owned in this instance. And keep  | 
206  |  |   // record of line-related debug instructions |dbg_line| ahead of this  | 
207  |  |   // instruction, if any.  | 
208  |  |   Instruction(IRContext* c, const spv_parsed_instruction_t& inst,  | 
209  |  |               std::vector<Instruction>&& dbg_line = {}); | 
210  |  |  | 
211  |  |   Instruction(IRContext* c, const spv_parsed_instruction_t& inst,  | 
212  |  |               const DebugScope& dbg_scope);  | 
213  |  |  | 
214  |  |   // Creates an instruction with the given opcode |op|, type id: |ty_id|,  | 
215  |  |   // result id: |res_id| and input operands: |in_operands|.  | 
216  |  |   Instruction(IRContext* c, spv::Op op, uint32_t ty_id, uint32_t res_id,  | 
217  |  |               const OperandList& in_operands);  | 
218  |  |  | 
219  |  |   // TODO: I will want to remove these, but will first have to remove the use of  | 
220  |  |   // std::vector<Instruction>.  | 
221  | 181k  |   Instruction(const Instruction&) = default;  | 
222  | 0  |   Instruction& operator=(const Instruction&) = default;  | 
223  |  |  | 
224  |  |   Instruction(Instruction&&);  | 
225  |  |   Instruction& operator=(Instruction&&);  | 
226  |  |  | 
227  | 789k  |   ~Instruction() override = default;  | 
228  |  |  | 
229  |  |   // Returns a newly allocated instruction that has the same operands, result,  | 
230  |  |   // and type as |this|.  The new instruction is not linked into any list.  | 
231  |  |   // It is the responsibility of the caller to make sure that the storage is  | 
232  |  |   // removed. It is the caller's responsibility to make sure that there is only  | 
233  |  |   // one instruction for each result id.  | 
234  |  |   Instruction* Clone(IRContext* c) const;  | 
235  |  |  | 
236  | 2.50M  |   IRContext* context() const { return context_; } | 
237  |  |  | 
238  | 50.7M  |   spv::Op opcode() const { return opcode_; } | 
239  |  |   // Sets the opcode of this instruction to a specific opcode. Note this may  | 
240  |  |   // invalidate the instruction.  | 
241  |  |   // TODO(qining): Remove this function when instruction building and insertion  | 
242  |  |   // is well implemented.  | 
243  | 5.06k  |   void SetOpcode(spv::Op op) { opcode_ = op; } | 
244  | 4.15M  |   uint32_t type_id() const { | 
245  | 4.15M  |     return has_type_id_ ? GetSingleWordOperand(0) : 0;  | 
246  | 4.15M  |   }  | 
247  | 13.1M  |   uint32_t result_id() const { | 
248  | 13.1M  |     return has_result_id_ ? GetSingleWordOperand(has_type_id_ ? 1 : 0) : 0;  | 
249  | 13.1M  |   }  | 
250  | 141M  |   uint32_t unique_id() const { | 
251  | 141M  |     assert(unique_id_ != 0);  | 
252  | 141M  |     return unique_id_;  | 
253  | 141M  |   }  | 
254  |  |   // Returns the vector of line-related debug instructions attached to this  | 
255  |  |   // instruction and the caller can directly modify them.  | 
256  | 852k  |   std::vector<Instruction>& dbg_line_insts() { return dbg_line_insts_; } | 
257  | 1.03M  |   const std::vector<Instruction>& dbg_line_insts() const { | 
258  | 1.03M  |     return dbg_line_insts_;  | 
259  | 1.03M  |   }  | 
260  |  |  | 
261  | 5.22k  |   const Instruction* dbg_line_inst() const { | 
262  | 5.22k  |     return dbg_line_insts_.empty() ? nullptr : &dbg_line_insts_[0];  | 
263  | 5.22k  |   }  | 
264  |  |  | 
265  |  |   // Clear line-related debug instructions attached to this instruction.  | 
266  | 8.58k  |   void clear_dbg_line_insts() { dbg_line_insts_.clear(); } | 
267  |  |  | 
268  |  |   // Same semantics as in the base class except the list the InstructionList  | 
269  |  |   // containing |pos| will now assume ownership of |this|.  | 
270  |  |   // inline void MoveBefore(Instruction* pos);  | 
271  |  |   // inline void InsertAfter(Instruction* pos);  | 
272  |  |  | 
273  |  |   // Begin and end iterators for operands.  | 
274  | 1.72k  |   iterator begin() { return operands_.begin(); } | 
275  | 1.72k  |   iterator end() { return operands_.end(); } | 
276  | 124k  |   const_iterator begin() const { return operands_.cbegin(); } | 
277  | 124k  |   const_iterator end() const { return operands_.cend(); } | 
278  |  |   // Const begin and end iterators for operands.  | 
279  | 0  |   const_iterator cbegin() const { return operands_.cbegin(); } | 
280  | 0  |   const_iterator cend() const { return operands_.cend(); } | 
281  |  |  | 
282  |  |   // Gets the number of logical operands.  | 
283  | 3.55M  |   uint32_t NumOperands() const { | 
284  | 3.55M  |     return static_cast<uint32_t>(operands_.size());  | 
285  | 3.55M  |   }  | 
286  |  |   // Gets the number of SPIR-V words occupied by all logical operands.  | 
287  | 125k  |   uint32_t NumOperandWords() const { | 
288  | 125k  |     return NumInOperandWords() + TypeResultIdCount();  | 
289  | 125k  |   }  | 
290  |  |   // Gets the |index|-th logical operand.  | 
291  |  |   inline Operand& GetOperand(uint32_t index);  | 
292  |  |   inline const Operand& GetOperand(uint32_t index) const;  | 
293  |  |   // Adds |operand| to the list of operands of this instruction.  | 
294  |  |   // It is the responsibility of the caller to make sure  | 
295  |  |   // that the instruction remains valid.  | 
296  |  |   inline void AddOperand(Operand&& operand);  | 
297  |  |   // Adds a copy of |operand| to the list of operands of this instruction.  | 
298  |  |   inline void AddOperand(const Operand& operand);  | 
299  |  |   // Gets the |index|-th logical operand as a single SPIR-V word. This method is  | 
300  |  |   // not expected to be used with logical operands consisting of multiple SPIR-V  | 
301  |  |   // words.  | 
302  |  |   uint32_t GetSingleWordOperand(uint32_t index) const;  | 
303  |  |   // Sets the |index|-th in-operand's data to the given |data|.  | 
304  |  |   inline void SetInOperand(uint32_t index, Operand::OperandData&& data);  | 
305  |  |   // Sets the |index|-th operand's data to the given |data|.  | 
306  |  |   // This is for in-operands modification only, but with |index| expressed in  | 
307  |  |   // terms of operand index rather than in-operand index.  | 
308  |  |   inline void SetOperand(uint32_t index, Operand::OperandData&& data);  | 
309  |  |   // Replace all of the in operands with those in |new_operands|.  | 
310  |  |   inline void SetInOperands(OperandList&& new_operands);  | 
311  |  |   // Sets the result type id.  | 
312  |  |   inline void SetResultType(uint32_t ty_id);  | 
313  | 0  |   inline bool HasResultType() const { return has_type_id_; } | 
314  |  |   // Sets the result id  | 
315  |  |   inline void SetResultId(uint32_t res_id);  | 
316  | 2.34M  |   inline bool HasResultId() const { return has_result_id_; } | 
317  |  |   // Sets DebugScope.  | 
318  |  |   inline void SetDebugScope(const DebugScope& scope);  | 
319  | 2.35M  |   inline const DebugScope& GetDebugScope() const { return dbg_scope_; } | 
320  |  |   // Add debug line inst. Renew result id if Debug[No]Line  | 
321  |  |   bool AddDebugLine(const Instruction* inst);  | 
322  |  |   // Updates DebugInlinedAt of DebugScope and OpLine.  | 
323  |  |   void UpdateDebugInlinedAt(uint32_t new_inlined_at);  | 
324  |  |   // Clear line-related debug instructions attached to this instruction  | 
325  |  |   // along with def-use entries.  | 
326  |  |   void ClearDbgLineInsts();  | 
327  |  |   // Return true if Shader100:Debug[No]Line  | 
328  |  |   bool IsDebugLineInst() const;  | 
329  |  |   // Return true if Op[No]Line or Shader100:Debug[No]Line  | 
330  |  |   bool IsLineInst() const;  | 
331  |  |   // Return true if OpLine or Shader100:DebugLine  | 
332  |  |   bool IsLine() const;  | 
333  |  |   // Return true if OpNoLine or Shader100:DebugNoLine  | 
334  |  |   bool IsNoLine() const;  | 
335  | 1.12M  |   inline uint32_t GetDebugInlinedAt() const { | 
336  | 1.12M  |     return dbg_scope_.GetInlinedAt();  | 
337  | 1.12M  |   }  | 
338  |  |   // Updates lexical scope of DebugScope and OpLine.  | 
339  |  |   void UpdateLexicalScope(uint32_t scope);  | 
340  |  |   // Updates OpLine and DebugScope based on the information of |from|.  | 
341  |  |   bool UpdateDebugInfoFrom(const Instruction* from,  | 
342  |  |                            const Instruction* line = nullptr);  | 
343  |  |   // Remove the |index|-th operand  | 
344  | 0  |   void RemoveOperand(uint32_t index) { | 
345  | 0  |     operands_.erase(operands_.begin() + index);  | 
346  | 0  |   }  | 
347  |  |   // Insert an operand before the |index|-th operand  | 
348  | 0  |   void InsertOperand(uint32_t index, Operand&& operand) { | 
349  | 0  |     operands_.insert(operands_.begin() + index, operand);  | 
350  | 0  |   }  | 
351  |  |  | 
352  |  |   // The following methods are similar to the above, but are for in operands.  | 
353  | 3.64M  |   uint32_t NumInOperands() const { | 
354  | 3.64M  |     return static_cast<uint32_t>(operands_.size() - TypeResultIdCount());  | 
355  | 3.64M  |   }  | 
356  |  |   uint32_t NumInOperandWords() const;  | 
357  | 674k  |   Operand& GetInOperand(uint32_t index) { | 
358  | 674k  |     return GetOperand(index + TypeResultIdCount());  | 
359  | 674k  |   }  | 
360  | 1.63M  |   const Operand& GetInOperand(uint32_t index) const { | 
361  | 1.63M  |     return GetOperand(index + TypeResultIdCount());  | 
362  | 1.63M  |   }  | 
363  | 3.15M  |   uint32_t GetSingleWordInOperand(uint32_t index) const { | 
364  | 3.15M  |     return GetSingleWordOperand(index + TypeResultIdCount());  | 
365  | 3.15M  |   }  | 
366  | 0  |   void RemoveInOperand(uint32_t index) { | 
367  | 0  |     operands_.erase(operands_.begin() + index + TypeResultIdCount());  | 
368  | 0  |   }  | 
369  |  |  | 
370  |  |   // Returns true if this instruction is OpNop.  | 
371  |  |   inline bool IsNop() const;  | 
372  |  |   // Turns this instruction to OpNop. This does not clear out all preceding  | 
373  |  |   // line-related debug instructions.  | 
374  |  |   inline void ToNop();  | 
375  |  |  | 
376  |  |   // Runs the given function |f| on this instruction and optionally on the  | 
377  |  |   // preceding debug line instructions.  The function will always be run  | 
378  |  |   // if this is itself a debug line instruction.  | 
379  |  |   inline void ForEachInst(const std::function<void(Instruction*)>& f,  | 
380  |  |                           bool run_on_debug_line_insts = false);  | 
381  |  |   inline void ForEachInst(const std::function<void(const Instruction*)>& f,  | 
382  |  |                           bool run_on_debug_line_insts = false) const;  | 
383  |  |  | 
384  |  |   // Runs the given function |f| on this instruction and optionally on the  | 
385  |  |   // preceding debug line instructions.  The function will always be run  | 
386  |  |   // if this is itself a debug line instruction. If |f| returns false,  | 
387  |  |   // iteration is terminated and this function returns false.  | 
388  |  |   inline bool WhileEachInst(const std::function<bool(Instruction*)>& f,  | 
389  |  |                             bool run_on_debug_line_insts = false);  | 
390  |  |   inline bool WhileEachInst(const std::function<bool(const Instruction*)>& f,  | 
391  |  |                             bool run_on_debug_line_insts = false) const;  | 
392  |  |  | 
393  |  |   // Runs the given function |f| on all operand ids.  | 
394  |  |   //  | 
395  |  |   // |f| should not transform an ID into 0, as 0 is an invalid ID.  | 
396  |  |   inline void ForEachId(const std::function<void(uint32_t*)>& f);  | 
397  |  |   inline void ForEachId(const std::function<void(const uint32_t*)>& f) const;  | 
398  |  |  | 
399  |  |   // Runs the given function |f| on all "in" operand ids.  | 
400  |  |   inline void ForEachInId(const std::function<void(uint32_t*)>& f);  | 
401  |  |   inline void ForEachInId(const std::function<void(const uint32_t*)>& f) const;  | 
402  |  |  | 
403  |  |   // Runs the given function |f| on all "in" operand ids. If |f| returns false,  | 
404  |  |   // iteration is terminated and this function returns false.  | 
405  |  |   inline bool WhileEachInId(const std::function<bool(uint32_t*)>& f);  | 
406  |  |   inline bool WhileEachInId(  | 
407  |  |       const std::function<bool(const uint32_t*)>& f) const;  | 
408  |  |  | 
409  |  |   // Runs the given function |f| on all "in" operands.  | 
410  |  |   inline void ForEachInOperand(const std::function<void(uint32_t*)>& f);  | 
411  |  |   inline void ForEachInOperand(  | 
412  |  |       const std::function<void(const uint32_t*)>& f) const;  | 
413  |  |  | 
414  |  |   // Runs the given function |f| on all "in" operands. If |f| returns false,  | 
415  |  |   // iteration is terminated and this function return false.  | 
416  |  |   inline bool WhileEachInOperand(const std::function<bool(uint32_t*)>& f);  | 
417  |  |   inline bool WhileEachInOperand(  | 
418  |  |       const std::function<bool(const uint32_t*)>& f) const;  | 
419  |  |  | 
420  |  |   // Returns true if it's an OpBranchConditional instruction  | 
421  |  |   // with branch weights.  | 
422  |  |   bool HasBranchWeights() const;  | 
423  |  |  | 
424  |  |   // Returns true if any operands can be labels  | 
425  |  |   inline bool HasLabels() const;  | 
426  |  |  | 
427  |  |   // Pushes the binary segments for this instruction into the back of *|binary|.  | 
428  |  |   void ToBinaryWithoutAttachedDebugInsts(std::vector<uint32_t>* binary) const;  | 
429  |  |  | 
430  |  |   // Replaces the operands to the instruction with |new_operands|. The caller  | 
431  |  |   // is responsible for building a complete and valid list of operands for  | 
432  |  |   // this instruction.  | 
433  |  |   void ReplaceOperands(const OperandList& new_operands);  | 
434  |  |  | 
435  |  |   // Returns true if the instruction annotates an id with a decoration.  | 
436  |  |   inline bool IsDecoration() const;  | 
437  |  |  | 
438  |  |   // Returns true if the instruction is known to be a load from read-only  | 
439  |  |   // memory.  | 
440  |  |   bool IsReadOnlyLoad() const;  | 
441  |  |  | 
442  |  |   // Returns the instruction that gives the base address of an address  | 
443  |  |   // calculation.  The instruction must be a load, as defined by |IsLoad|,  | 
444  |  |   // store, copy, or access chain instruction.  In logical addressing mode, will  | 
445  |  |   // return an OpVariable or OpFunctionParameter instruction. For relaxed  | 
446  |  |   // logical addressing, it would also return a load of a pointer to an opaque  | 
447  |  |   // object.  For physical addressing mode, could return other types of  | 
448  |  |   // instructions.  | 
449  |  |   Instruction* GetBaseAddress() const;  | 
450  |  |  | 
451  |  |   // Returns true if the instruction loads from memory or samples an image, and  | 
452  |  |   // stores the result into an id. It considers only core instructions.  | 
453  |  |   // Memory-to-memory instructions are not considered loads.  | 
454  |  |   inline bool IsLoad() const;  | 
455  |  |  | 
456  |  |   // Returns true if the instruction generates a pointer that is definitely  | 
457  |  |   // read-only.  This is determined by analysing the pointer type's storage  | 
458  |  |   // class and decorations that target the pointer's id.  It does not analyse  | 
459  |  |   // other instructions that the pointer may be derived from.  Thus if 'true' is  | 
460  |  |   // returned, the pointer is definitely read-only, while if 'false' is returned  | 
461  |  |   // it is possible that the pointer may actually be read-only if it is derived  | 
462  |  |   // from another pointer that is decorated as read-only.  | 
463  |  |   bool IsReadOnlyPointer() const;  | 
464  |  |  | 
465  |  |   // The following functions check for the various descriptor types defined in  | 
466  |  |   // the Vulkan specification section 13.1.  | 
467  |  |  | 
468  |  |   // Returns true if the instruction defines a pointer type that points to a  | 
469  |  |   // storage image.  | 
470  |  |   bool IsVulkanStorageImage() const;  | 
471  |  |  | 
472  |  |   // Returns true if the instruction defines a pointer type that points to a  | 
473  |  |   // sampled image.  | 
474  |  |   bool IsVulkanSampledImage() const;  | 
475  |  |  | 
476  |  |   // Returns true if the instruction defines a pointer type that points to a  | 
477  |  |   // storage texel buffer.  | 
478  |  |   bool IsVulkanStorageTexelBuffer() const;  | 
479  |  |  | 
480  |  |   // Returns true if the instruction defines a pointer type that points to a  | 
481  |  |   // storage buffer.  | 
482  |  |   bool IsVulkanStorageBuffer() const;  | 
483  |  |  | 
484  |  |   // Returns true if the instruction defines a variable in StorageBuffer or  | 
485  |  |   // Uniform storage class with a pointer type that points to a storage buffer.  | 
486  |  |   bool IsVulkanStorageBufferVariable() const;  | 
487  |  |  | 
488  |  |   // Returns true if the instruction defines a pointer type that points to a  | 
489  |  |   // uniform buffer.  | 
490  |  |   bool IsVulkanUniformBuffer() const;  | 
491  |  |  | 
492  |  |   // Returns true if the instruction is an atom operation that uses original  | 
493  |  |   // value.  | 
494  |  |   inline bool IsAtomicWithLoad() const;  | 
495  |  |  | 
496  |  |   // Returns true if the instruction is an atom operation.  | 
497  |  |   inline bool IsAtomicOp() const;  | 
498  |  |  | 
499  |  |   // Returns true if this instruction is a branch or switch instruction (either  | 
500  |  |   // conditional or not).  | 
501  | 1.04M  |   bool IsBranch() const { return spvOpcodeIsBranch(opcode()); } | 
502  |  |  | 
503  |  |   // Returns true if this instruction causes the function to finish execution  | 
504  |  |   // and return to its caller  | 
505  | 0  |   bool IsReturn() const { return spvOpcodeIsReturn(opcode()); } | 
506  |  |  | 
507  |  |   // Returns true if this instruction exits this function or aborts execution.  | 
508  | 16.1k  |   bool IsReturnOrAbort() const { return spvOpcodeIsReturnOrAbort(opcode()); } | 
509  |  |  | 
510  |  |   // Returns true if this instruction is a basic block terminator.  | 
511  | 103k  |   bool IsBlockTerminator() const { | 
512  | 103k  |     return spvOpcodeIsBlockTerminator(opcode());  | 
513  | 103k  |   }  | 
514  |  |  | 
515  |  |   // Returns true if |this| is an instruction that define an opaque type.  Since  | 
516  |  |   // runtime array have similar characteristics they are included as opaque  | 
517  |  |   // types.  | 
518  |  |   bool IsOpaqueType() const;  | 
519  |  |  | 
520  |  |   // Returns true if |this| is an instruction which could be folded into a  | 
521  |  |   // constant value.  | 
522  |  |   bool IsFoldable() const;  | 
523  |  |  | 
524  |  |   // Returns true if |this| is an instruction which could be folded into a  | 
525  |  |   // constant value by |FoldScalar|.  | 
526  |  |   bool IsFoldableByFoldScalar() const;  | 
527  |  |  | 
528  |  |   // Returns true if |this| is an instruction which could be folded into a  | 
529  |  |   // constant value by |FoldVector|.  | 
530  |  |   bool IsFoldableByFoldVector() const;  | 
531  |  |  | 
532  |  |   // Returns true if we are allowed to fold or otherwise manipulate the  | 
533  |  |   // instruction that defines |id| in the given context. This includes not  | 
534  |  |   // handling NaN values.  | 
535  |  |   bool IsFloatingPointFoldingAllowed() const;  | 
536  |  |  | 
537  |  |   inline bool operator==(const Instruction&) const;  | 
538  |  |   inline bool operator!=(const Instruction&) const;  | 
539  |  |   inline bool operator<(const Instruction&) const;  | 
540  |  |  | 
541  |  |   // Takes ownership of the instruction owned by |i| and inserts it immediately  | 
542  |  |   // before |this|. Returns the inserted instruction.  | 
543  |  |   Instruction* InsertBefore(std::unique_ptr<Instruction>&& i);  | 
544  |  |   // Takes ownership of the instructions in |list| and inserts them in order  | 
545  |  |   // immediately before |this|.  Returns the first inserted instruction.  | 
546  |  |   // Assumes the list is non-empty.  | 
547  |  |   Instruction* InsertBefore(std::vector<std::unique_ptr<Instruction>>&& list);  | 
548  |  |   using utils::IntrusiveNodeBase<Instruction>::InsertBefore;  | 
549  |  |  | 
550  |  |   // Returns true if |this| is an instruction defining a constant, but not a  | 
551  |  |   // Spec constant.  | 
552  |  |   inline bool IsConstant() const;  | 
553  |  |  | 
554  |  |   // Returns true if |this| is an instruction with an opcode safe to move  | 
555  |  |   bool IsOpcodeCodeMotionSafe() const;  | 
556  |  |  | 
557  |  |   // Pretty-prints |inst|.  | 
558  |  |   //  | 
559  |  |   // Provides the disassembly of a specific instruction. Utilizes |inst|'s  | 
560  |  |   // context to provide the correct interpretation of types, constants, etc.  | 
561  |  |   //  | 
562  |  |   // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER  | 
563  |  |   // is always added to |options|.  | 
564  |  |   std::string PrettyPrint(uint32_t options = 0u) const;  | 
565  |  |  | 
566  |  |   // Returns true if the result can be a vector and the result of each component  | 
567  |  |   // depends on the corresponding component of any vector inputs.  | 
568  |  |   bool IsScalarizable() const;  | 
569  |  |  | 
570  |  |   // Return true if the only effect of this instructions is the result.  | 
571  |  |   bool IsOpcodeSafeToDelete() const;  | 
572  |  |  | 
573  |  |   // Returns true if it is valid to use the result of |inst| as the base  | 
574  |  |   // pointer for a load or store.  In this case, valid is defined by the relaxed  | 
575  |  |   // logical addressing rules when using logical addressing.  Normal validation  | 
576  |  |   // rules for physical addressing.  | 
577  |  |   bool IsValidBasePointer() const;  | 
578  |  |  | 
579  |  |   // Returns debug opcode of an OpenCL.100.DebugInfo instruction. If  | 
580  |  |   // it is not an OpenCL.100.DebugInfo instruction, just returns  | 
581  |  |   // OpenCLDebugInfo100InstructionsMax.  | 
582  |  |   OpenCLDebugInfo100Instructions GetOpenCL100DebugOpcode() const;  | 
583  |  |  | 
584  |  |   // Returns debug opcode of an NonSemantic.Shader.DebugInfo.100 instruction. If  | 
585  |  |   // it is not an NonSemantic.Shader.DebugInfo.100 instruction, just return  | 
586  |  |   // NonSemanticShaderDebugInfo100InstructionsMax.  | 
587  |  |   NonSemanticShaderDebugInfo100Instructions GetShader100DebugOpcode() const;  | 
588  |  |  | 
589  |  |   // Returns debug opcode of an OpenCL.100.DebugInfo or  | 
590  |  |   // NonSemantic.Shader.DebugInfo.100 instruction. Since these overlap, we  | 
591  |  |   // return the OpenCLDebugInfo code  | 
592  |  |   CommonDebugInfoInstructions GetCommonDebugOpcode() const;  | 
593  |  |  | 
594  |  |   // Returns true if it is an OpenCL.DebugInfo.100 instruction.  | 
595  | 0  |   bool IsOpenCL100DebugInstr() const { | 
596  | 0  |     return GetOpenCL100DebugOpcode() != OpenCLDebugInfo100InstructionsMax;  | 
597  | 0  |   }  | 
598  |  |  | 
599  |  |   // Returns true if it is an NonSemantic.Shader.DebugInfo.100 instruction.  | 
600  | 0  |   bool IsShader100DebugInstr() const { | 
601  | 0  |     return GetShader100DebugOpcode() !=  | 
602  | 0  |            NonSemanticShaderDebugInfo100InstructionsMax;  | 
603  | 0  |   }  | 
604  | 1.23M  |   bool IsCommonDebugInstr() const { | 
605  | 1.23M  |     return GetCommonDebugOpcode() != CommonDebugInfoInstructionsMax;  | 
606  | 1.23M  |   }  | 
607  |  |  | 
608  |  |   // Returns true if this instructions a non-semantic instruction.  | 
609  |  |   bool IsNonSemanticInstruction() const;  | 
610  |  |  | 
611  |  |   // Dump this instruction on stderr.  Useful when running interactive  | 
612  |  |   // debuggers.  | 
613  |  |   void Dump() const;  | 
614  |  |  | 
615  |  |  private:  | 
616  |  |   // Returns the total count of result type id and result id.  | 
617  | 9.42M  |   uint32_t TypeResultIdCount() const { | 
618  | 9.42M  |     if (has_type_id_ && has_result_id_) return 2;  | 
619  | 3.33M  |     if (has_type_id_ || has_result_id_) return 1;  | 
620  | 2.03M  |     return 0;  | 
621  | 3.33M  |   }  | 
622  |  |  | 
623  |  |   // Returns true if the instruction generates a read-only pointer, with the  | 
624  |  |   // same caveats documented in the comment for IsReadOnlyPointer.  The first  | 
625  |  |   // version assumes the module is a shader module.  The second assumes a  | 
626  |  |   // kernel.  | 
627  |  |   bool IsReadOnlyPointerShaders() const;  | 
628  |  |   bool IsReadOnlyPointerKernel() const;  | 
629  |  |  | 
630  |  |   // Returns true if the result of |inst| can be used as the base image for an  | 
631  |  |   // instruction that samples a image, reads an image, or writes to an image.  | 
632  |  |   bool IsValidBaseImage() const;  | 
633  |  |  | 
634  |  |   IRContext* context_;  // IR Context  | 
635  |  |   spv::Op opcode_;      // Opcode  | 
636  |  |   bool has_type_id_;    // True if the instruction has a type id  | 
637  |  |   bool has_result_id_;  // True if the instruction has a result id  | 
638  |  |   uint32_t unique_id_;  // Unique instruction id  | 
639  |  |   // All logical operands, including result type id and result id.  | 
640  |  |   OperandList operands_;  | 
641  |  |   // Op[No]Line or Debug[No]Line instructions preceding this instruction. Note  | 
642  |  |   // that for Instructions representing Op[No]Line or Debug[No]Line themselves,  | 
643  |  |   // this field should be empty.  | 
644  |  |   std::vector<Instruction> dbg_line_insts_;  | 
645  |  |  | 
646  |  |   // DebugScope that wraps this instruction.  | 
647  |  |   DebugScope dbg_scope_;  | 
648  |  |  | 
649  |  |   friend InstructionList;  | 
650  |  | };  | 
651  |  |  | 
652  |  | // Pretty-prints |inst| to |str| and returns |str|.  | 
653  |  | //  | 
654  |  | // Provides the disassembly of a specific instruction. Utilizes |inst|'s context  | 
655  |  | // to provide the correct interpretation of types, constants, etc.  | 
656  |  | //  | 
657  |  | // Disassembly uses raw ids (not pretty printed names).  | 
658  |  | std::ostream& operator<<(std::ostream& str, const Instruction& inst);  | 
659  |  |  | 
660  | 0  | inline bool Instruction::operator==(const Instruction& other) const { | 
661  | 0  |   return unique_id() == other.unique_id();  | 
662  | 0  | }  | 
663  |  |  | 
664  | 0  | inline bool Instruction::operator!=(const Instruction& other) const { | 
665  | 0  |   return !(*this == other);  | 
666  | 0  | }  | 
667  |  |  | 
668  | 203k  | inline bool Instruction::operator<(const Instruction& other) const { | 
669  | 203k  |   return unique_id() < other.unique_id();  | 
670  | 203k  | }  | 
671  |  |  | 
672  | 3.47M  | inline Operand& Instruction::GetOperand(uint32_t index) { | 
673  | 3.47M  |   assert(index < operands_.size() && "operand index out of bound");  | 
674  | 3.47M  |   return operands_[index];  | 
675  | 3.47M  | }  | 
676  |  |  | 
677  | 22.8M  | inline const Operand& Instruction::GetOperand(uint32_t index) const { | 
678  | 22.8M  |   assert(index < operands_.size() && "operand index out of bound");  | 
679  | 22.8M  |   return operands_[index];  | 
680  | 22.8M  | }  | 
681  |  |  | 
682  | 462k  | inline void Instruction::AddOperand(Operand&& operand) { | 
683  | 462k  |   operands_.push_back(std::move(operand));  | 
684  | 462k  | }  | 
685  |  |  | 
686  | 0  | inline void Instruction::AddOperand(const Operand& operand) { | 
687  | 0  |   operands_.push_back(operand);  | 
688  | 0  | }  | 
689  |  |  | 
690  |  | inline void Instruction::SetInOperand(uint32_t index,  | 
691  | 64.3k  |                                       Operand::OperandData&& data) { | 
692  | 64.3k  |   SetOperand(index + TypeResultIdCount(), std::move(data));  | 
693  | 64.3k  | }  | 
694  |  |  | 
695  |  | inline void Instruction::SetOperand(uint32_t index,  | 
696  | 64.3k  |                                     Operand::OperandData&& data) { | 
697  | 64.3k  |   assert(index < operands_.size() && "operand index out of bound");  | 
698  | 64.3k  |   assert(index >= TypeResultIdCount() && "operand is not a in-operand");  | 
699  | 64.3k  |   operands_[index].words = std::move(data);  | 
700  | 64.3k  | }  | 
701  |  |  | 
702  | 3.31k  | inline void Instruction::SetInOperands(OperandList&& new_operands) { | 
703  |  |   // Remove the old in operands.  | 
704  | 3.31k  |   operands_.erase(operands_.begin() + TypeResultIdCount(), operands_.end());  | 
705  |  |   // Add the new in operands.  | 
706  | 3.31k  |   operands_.insert(operands_.end(), new_operands.begin(), new_operands.end());  | 
707  | 3.31k  | }  | 
708  |  |  | 
709  | 51.5k  | inline void Instruction::SetResultId(uint32_t res_id) { | 
710  |  |   // TODO(dsinclair): Allow setting a result id if there wasn't one  | 
711  |  |   // previously. Need to make room in the operands_ array to place the result,  | 
712  |  |   // and update the has_result_id_ flag.  | 
713  | 51.5k  |   assert(has_result_id_);  | 
714  |  |  | 
715  |  |   // TODO(dsinclair): Allow removing the result id. This needs to make sure,  | 
716  |  |   // if there was a result id previously to remove it from the operands_ array  | 
717  |  |   // and reset the has_result_id_ flag.  | 
718  | 51.5k  |   assert(res_id != 0);  | 
719  |  |  | 
720  | 51.5k  |   auto ridx = has_type_id_ ? 1 : 0;  | 
721  | 51.5k  |   operands_[ridx].words = {res_id}; | 
722  | 51.5k  | }  | 
723  |  |  | 
724  | 16.8k  | inline void Instruction::SetDebugScope(const DebugScope& scope) { | 
725  | 16.8k  |   dbg_scope_ = scope;  | 
726  | 16.8k  |   for (auto& i : dbg_line_insts_) { | 
727  | 0  |     i.dbg_scope_ = scope;  | 
728  | 0  |   }  | 
729  | 16.8k  | }  | 
730  |  |  | 
731  | 570  | inline void Instruction::SetResultType(uint32_t ty_id) { | 
732  |  |   // TODO(dsinclair): Allow setting a type id if there wasn't one  | 
733  |  |   // previously. Need to make room in the operands_ array to place the result,  | 
734  |  |   // and update the has_type_id_ flag.  | 
735  | 570  |   assert(has_type_id_);  | 
736  |  |  | 
737  |  |   // TODO(dsinclair): Allow removing the type id. This needs to make sure,  | 
738  |  |   // if there was a type id previously to remove it from the operands_ array  | 
739  |  |   // and reset the has_type_id_ flag.  | 
740  | 570  |   assert(ty_id != 0);  | 
741  |  |  | 
742  | 570  |   operands_.front().words = {ty_id}; | 
743  | 570  | }  | 
744  |  |  | 
745  | 125k  | inline bool Instruction::IsNop() const { | 
746  | 125k  |   return opcode_ == spv::Op::OpNop && !has_type_id_ && !has_result_id_ &&  | 
747  | 0  |          operands_.empty();  | 
748  | 125k  | }  | 
749  |  |  | 
750  | 13.9k  | inline void Instruction::ToNop() { | 
751  | 13.9k  |   opcode_ = spv::Op::OpNop;  | 
752  | 13.9k  |   has_type_id_ = false;  | 
753  | 13.9k  |   has_result_id_ = false;  | 
754  | 13.9k  |   operands_.clear();  | 
755  | 13.9k  | }  | 
756  |  |  | 
757  |  | inline bool Instruction::WhileEachInst(  | 
758  | 5.88M  |     const std::function<bool(Instruction*)>& f, bool run_on_debug_line_insts) { | 
759  | 5.88M  |   if (run_on_debug_line_insts) { | 
760  | 1.22M  |     for (auto& dbg_line : dbg_line_insts_) { | 
761  | 0  |       if (!f(&dbg_line)) return false;  | 
762  | 0  |     }  | 
763  | 1.22M  |   }  | 
764  | 5.88M  |   return f(this);  | 
765  | 5.88M  | }  | 
766  |  |  | 
767  |  | inline bool Instruction::WhileEachInst(  | 
768  |  |     const std::function<bool(const Instruction*)>& f,  | 
769  | 255k  |     bool run_on_debug_line_insts) const { | 
770  | 255k  |   if (run_on_debug_line_insts) { | 
771  | 250k  |     for (auto& dbg_line : dbg_line_insts_) { | 
772  | 0  |       if (!f(&dbg_line)) return false;  | 
773  | 0  |     }  | 
774  | 250k  |   }  | 
775  | 255k  |   return f(this);  | 
776  | 255k  | }  | 
777  |  |  | 
778  |  | inline void Instruction::ForEachInst(const std::function<void(Instruction*)>& f,  | 
779  | 438k  |                                      bool run_on_debug_line_insts) { | 
780  | 438k  |   WhileEachInst(  | 
781  | 438k  |       [&f](Instruction* inst) { | 
782  | 438k  |         f(inst);  | 
783  | 438k  |         return true;  | 
784  | 438k  |       },  | 
785  | 438k  |       run_on_debug_line_insts);  | 
786  | 438k  | }  | 
787  |  |  | 
788  |  | inline void Instruction::ForEachInst(  | 
789  |  |     const std::function<void(const Instruction*)>& f,  | 
790  | 66.8k  |     bool run_on_debug_line_insts) const { | 
791  | 66.8k  |   WhileEachInst(  | 
792  | 66.8k  |       [&f](const Instruction* inst) { | 
793  | 66.8k  |         f(inst);  | 
794  | 66.8k  |         return true;  | 
795  | 66.8k  |       },  | 
796  | 66.8k  |       run_on_debug_line_insts);  | 
797  | 66.8k  | }  | 
798  |  |  | 
799  | 0  | inline void Instruction::ForEachId(const std::function<void(uint32_t*)>& f) { | 
800  | 0  |   for (auto& operand : operands_)  | 
801  | 0  |     if (spvIsIdType(operand.type)) f(&operand.words[0]);  | 
802  | 0  | }  | 
803  |  |  | 
804  |  | inline void Instruction::ForEachId(  | 
805  | 0  |     const std::function<void(const uint32_t*)>& f) const { | 
806  | 0  |   for (const auto& operand : operands_)  | 
807  | 0  |     if (spvIsIdType(operand.type)) f(&operand.words[0]);  | 
808  | 0  | }  | 
809  |  |  | 
810  |  | inline bool Instruction::WhileEachInId(  | 
811  | 436k  |     const std::function<bool(uint32_t*)>& f) { | 
812  | 1.45M  |   for (auto& operand : operands_) { | 
813  | 1.45M  |     if (spvIsInIdType(operand.type) && !f(&operand.words[0])) { | 
814  | 53.0k  |       return false;  | 
815  | 53.0k  |     }  | 
816  | 1.45M  |   }  | 
817  | 383k  |   return true;  | 
818  | 436k  | }  | 
819  |  |  | 
820  |  | inline bool Instruction::WhileEachInId(  | 
821  | 1.41M  |     const std::function<bool(const uint32_t*)>& f) const { | 
822  | 4.54M  |   for (const auto& operand : operands_) { | 
823  | 4.54M  |     if (spvIsInIdType(operand.type) && !f(&operand.words[0])) { | 
824  | 45.3k  |       return false;  | 
825  | 45.3k  |     }  | 
826  | 4.54M  |   }  | 
827  | 1.37M  |   return true;  | 
828  | 1.41M  | }  | 
829  |  |  | 
830  | 363k  | inline void Instruction::ForEachInId(const std::function<void(uint32_t*)>& f) { | 
831  | 594k  |   WhileEachInId([&f](uint32_t* id) { | 
832  | 594k  |     f(id);  | 
833  | 594k  |     return true;  | 
834  | 594k  |   });  | 
835  | 363k  | }  | 
836  |  |  | 
837  |  | inline void Instruction::ForEachInId(  | 
838  | 1.03M  |     const std::function<void(const uint32_t*)>& f) const { | 
839  | 1.44M  |   WhileEachInId([&f](const uint32_t* id) { | 
840  | 1.44M  |     f(id);  | 
841  | 1.44M  |     return true;  | 
842  | 1.44M  |   });  | 
843  | 1.03M  | }  | 
844  |  |  | 
845  |  | inline bool Instruction::WhileEachInOperand(  | 
846  | 2.11k  |     const std::function<bool(uint32_t*)>& f) { | 
847  | 7.52k  |   for (auto& operand : operands_) { | 
848  | 7.52k  |     switch (operand.type) { | 
849  | 1.56k  |       case SPV_OPERAND_TYPE_RESULT_ID:  | 
850  | 2.95k  |       case SPV_OPERAND_TYPE_TYPE_ID:  | 
851  | 2.95k  |         break;  | 
852  | 4.57k  |       default:  | 
853  | 4.57k  |         if (!f(&operand.words[0])) return false;  | 
854  | 4.57k  |         break;  | 
855  | 7.52k  |     }  | 
856  | 7.52k  |   }  | 
857  | 2.11k  |   return true;  | 
858  | 2.11k  | }  | 
859  |  |  | 
860  |  | inline bool Instruction::WhileEachInOperand(  | 
861  | 0  |     const std::function<bool(const uint32_t*)>& f) const { | 
862  | 0  |   for (const auto& operand : operands_) { | 
863  | 0  |     switch (operand.type) { | 
864  | 0  |       case SPV_OPERAND_TYPE_RESULT_ID:  | 
865  | 0  |       case SPV_OPERAND_TYPE_TYPE_ID:  | 
866  | 0  |         break;  | 
867  | 0  |       default:  | 
868  | 0  |         if (!f(&operand.words[0])) return false;  | 
869  | 0  |         break;  | 
870  | 0  |     }  | 
871  | 0  |   }  | 
872  | 0  |   return true;  | 
873  | 0  | }  | 
874  |  |  | 
875  |  | inline void Instruction::ForEachInOperand(  | 
876  | 1.56k  |     const std::function<void(uint32_t*)>& f) { | 
877  | 3.48k  |   WhileEachInOperand([&f](uint32_t* operand) { | 
878  | 3.48k  |     f(operand);  | 
879  | 3.48k  |     return true;  | 
880  | 3.48k  |   });  | 
881  | 1.56k  | }  | 
882  |  |  | 
883  |  | inline void Instruction::ForEachInOperand(  | 
884  | 0  |     const std::function<void(const uint32_t*)>& f) const { | 
885  | 0  |   WhileEachInOperand([&f](const uint32_t* operand) { | 
886  | 0  |     f(operand);  | 
887  | 0  |     return true;  | 
888  | 0  |   });  | 
889  | 0  | }  | 
890  |  |  | 
891  | 0  | inline bool Instruction::HasLabels() const { | 
892  | 0  |   switch (opcode_) { | 
893  | 0  |     case spv::Op::OpSelectionMerge:  | 
894  | 0  |     case spv::Op::OpBranch:  | 
895  | 0  |     case spv::Op::OpLoopMerge:  | 
896  | 0  |     case spv::Op::OpBranchConditional:  | 
897  | 0  |     case spv::Op::OpSwitch:  | 
898  | 0  |     case spv::Op::OpPhi:  | 
899  | 0  |       return true;  | 
900  | 0  |       break;  | 
901  | 0  |     default:  | 
902  | 0  |       break;  | 
903  | 0  |   }  | 
904  | 0  |   return false;  | 
905  | 0  | }  | 
906  |  |  | 
907  | 331k  | bool Instruction::IsDecoration() const { | 
908  | 331k  |   return spvOpcodeIsDecoration(opcode());  | 
909  | 331k  | }  | 
910  |  |  | 
911  | 429k  | bool Instruction::IsLoad() const { return spvOpcodeIsLoad(opcode()); } | 
912  |  |  | 
913  | 1.02M  | bool Instruction::IsAtomicWithLoad() const { | 
914  | 1.02M  |   return spvOpcodeIsAtomicWithLoad(opcode());  | 
915  | 1.02M  | }  | 
916  |  |  | 
917  | 0  | bool Instruction::IsAtomicOp() const { return spvOpcodeIsAtomicOp(opcode()); } | 
918  |  |  | 
919  | 25.2k  | bool Instruction::IsConstant() const { | 
920  | 25.2k  |   return IsConstantInst(opcode()) && !IsSpecConstantInst(opcode());  | 
921  | 25.2k  | }  | 
922  |  | }  // namespace opt  | 
923  |  | }  // namespace spvtools  | 
924  |  |  | 
925  |  | #endif  // SOURCE_OPT_INSTRUCTION_H_  |