• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "source/opt/instruction.h"
16 
17 #include <initializer_list>
18 
19 #include "OpenCLDebugInfo100.h"
20 #include "source/disassemble.h"
21 #include "source/opt/fold.h"
22 #include "source/opt/ir_context.h"
23 #include "source/opt/reflect.h"
24 
25 namespace spvtools {
26 namespace opt {
27 
28 namespace {
29 // Indices used to get particular operands out of instructions using InOperand.
30 const uint32_t kTypeImageDimIndex = 1;
31 const uint32_t kLoadBaseIndex = 0;
32 const uint32_t kPointerTypeStorageClassIndex = 0;
33 const uint32_t kVariableStorageClassIndex = 0;
34 const uint32_t kTypeImageSampledIndex = 5;
35 
36 // Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100
37 // extension instructions.
38 const uint32_t kExtInstSetIdInIdx = 0;
39 const uint32_t kExtInstInstructionInIdx = 1;
40 const uint32_t kDebugScopeNumWords = 7;
41 const uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
42 const uint32_t kDebugNoScopeNumWords = 5;
43 
44 // Number of operands of an OpBranchConditional instruction
45 // with weights.
46 const uint32_t kOpBranchConditionalWithWeightsNumOperands = 5;
47 }  // namespace
48 
Instruction(IRContext * c)49 Instruction::Instruction(IRContext* c)
50     : utils::IntrusiveNodeBase<Instruction>(),
51       context_(c),
52       opcode_(SpvOpNop),
53       has_type_id_(false),
54       has_result_id_(false),
55       unique_id_(c->TakeNextUniqueId()),
56       dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
57 
Instruction(IRContext * c,SpvOp op)58 Instruction::Instruction(IRContext* c, SpvOp op)
59     : utils::IntrusiveNodeBase<Instruction>(),
60       context_(c),
61       opcode_(op),
62       has_type_id_(false),
63       has_result_id_(false),
64       unique_id_(c->TakeNextUniqueId()),
65       dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
66 
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,std::vector<Instruction> && dbg_line)67 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
68                          std::vector<Instruction>&& dbg_line)
69     : utils::IntrusiveNodeBase<Instruction>(),
70       context_(c),
71       opcode_(static_cast<SpvOp>(inst.opcode)),
72       has_type_id_(inst.type_id != 0),
73       has_result_id_(inst.result_id != 0),
74       unique_id_(c->TakeNextUniqueId()),
75       dbg_line_insts_(std::move(dbg_line)),
76       dbg_scope_(kNoDebugScope, kNoInlinedAt) {
77   for (uint32_t i = 0; i < inst.num_operands; ++i) {
78     const auto& current_payload = inst.operands[i];
79     operands_.emplace_back(
80         current_payload.type, inst.words + current_payload.offset,
81         inst.words + current_payload.offset + current_payload.num_words);
82   }
83   assert((!IsLineInst() || dbg_line.empty()) &&
84          "Op(No)Line attaching to Op(No)Line found");
85 }
86 
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,const DebugScope & dbg_scope)87 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
88                          const DebugScope& dbg_scope)
89     : utils::IntrusiveNodeBase<Instruction>(),
90       context_(c),
91       opcode_(static_cast<SpvOp>(inst.opcode)),
92       has_type_id_(inst.type_id != 0),
93       has_result_id_(inst.result_id != 0),
94       unique_id_(c->TakeNextUniqueId()),
95       dbg_scope_(dbg_scope) {
96   for (uint32_t i = 0; i < inst.num_operands; ++i) {
97     const auto& current_payload = inst.operands[i];
98     operands_.emplace_back(
99         current_payload.type, inst.words + current_payload.offset,
100         inst.words + current_payload.offset + current_payload.num_words);
101   }
102 }
103 
Instruction(IRContext * c,SpvOp op,uint32_t ty_id,uint32_t res_id,const OperandList & in_operands)104 Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id,
105                          uint32_t res_id, const OperandList& in_operands)
106     : utils::IntrusiveNodeBase<Instruction>(),
107       context_(c),
108       opcode_(op),
109       has_type_id_(ty_id != 0),
110       has_result_id_(res_id != 0),
111       unique_id_(c->TakeNextUniqueId()),
112       operands_(),
113       dbg_scope_(kNoDebugScope, kNoInlinedAt) {
114   if (has_type_id_) {
115     operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
116                            std::initializer_list<uint32_t>{ty_id});
117   }
118   if (has_result_id_) {
119     operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
120                            std::initializer_list<uint32_t>{res_id});
121   }
122   operands_.insert(operands_.end(), in_operands.begin(), in_operands.end());
123 }
124 
Instruction(Instruction && that)125 Instruction::Instruction(Instruction&& that)
126     : utils::IntrusiveNodeBase<Instruction>(),
127       context_(that.context_),
128       opcode_(that.opcode_),
129       has_type_id_(that.has_type_id_),
130       has_result_id_(that.has_result_id_),
131       unique_id_(that.unique_id_),
132       operands_(std::move(that.operands_)),
133       dbg_line_insts_(std::move(that.dbg_line_insts_)),
134       dbg_scope_(that.dbg_scope_) {
135   for (auto& i : dbg_line_insts_) {
136     i.dbg_scope_ = that.dbg_scope_;
137   }
138 }
139 
operator =(Instruction && that)140 Instruction& Instruction::operator=(Instruction&& that) {
141   context_ = that.context_;
142   opcode_ = that.opcode_;
143   has_type_id_ = that.has_type_id_;
144   has_result_id_ = that.has_result_id_;
145   unique_id_ = that.unique_id_;
146   operands_ = std::move(that.operands_);
147   dbg_line_insts_ = std::move(that.dbg_line_insts_);
148   dbg_scope_ = that.dbg_scope_;
149   return *this;
150 }
151 
Clone(IRContext * c) const152 Instruction* Instruction::Clone(IRContext* c) const {
153   Instruction* clone = new Instruction(c);
154   clone->opcode_ = opcode_;
155   clone->has_type_id_ = has_type_id_;
156   clone->has_result_id_ = has_result_id_;
157   clone->unique_id_ = c->TakeNextUniqueId();
158   clone->operands_ = operands_;
159   clone->dbg_line_insts_ = dbg_line_insts_;
160   for (auto& i : clone->dbg_line_insts_) {
161     i.unique_id_ = c->TakeNextUniqueId();
162     if (i.IsDebugLineInst()) i.SetResultId(c->TakeNextId());
163   }
164   clone->dbg_scope_ = dbg_scope_;
165   return clone;
166 }
167 
GetSingleWordOperand(uint32_t index) const168 uint32_t Instruction::GetSingleWordOperand(uint32_t index) const {
169   const auto& words = GetOperand(index).words;
170   assert(words.size() == 1 && "expected the operand only taking one word");
171   return words.front();
172 }
173 
NumInOperandWords() const174 uint32_t Instruction::NumInOperandWords() const {
175   uint32_t size = 0;
176   for (uint32_t i = TypeResultIdCount(); i < operands_.size(); ++i)
177     size += static_cast<uint32_t>(operands_[i].words.size());
178   return size;
179 }
180 
HasBranchWeights() const181 bool Instruction::HasBranchWeights() const {
182   if (opcode_ == SpvOpBranchConditional &&
183       NumOperands() == kOpBranchConditionalWithWeightsNumOperands) {
184     return true;
185   }
186 
187   return false;
188 }
189 
ToBinaryWithoutAttachedDebugInsts(std::vector<uint32_t> * binary) const190 void Instruction::ToBinaryWithoutAttachedDebugInsts(
191     std::vector<uint32_t>* binary) const {
192   const uint32_t num_words = 1 + NumOperandWords();
193   binary->push_back((num_words << 16) | static_cast<uint16_t>(opcode_));
194   for (const auto& operand : operands_) {
195     binary->insert(binary->end(), operand.words.begin(), operand.words.end());
196   }
197 }
198 
ReplaceOperands(const OperandList & new_operands)199 void Instruction::ReplaceOperands(const OperandList& new_operands) {
200   operands_.clear();
201   operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
202 }
203 
IsReadOnlyLoad() const204 bool Instruction::IsReadOnlyLoad() const {
205   if (IsLoad()) {
206     Instruction* address_def = GetBaseAddress();
207     if (!address_def) {
208       return false;
209     }
210 
211     if (address_def->opcode() == SpvOpVariable) {
212       if (address_def->IsReadOnlyPointer()) {
213         return true;
214       }
215     }
216 
217     if (address_def->opcode() == SpvOpLoad) {
218       const analysis::Type* address_type =
219           context()->get_type_mgr()->GetType(address_def->type_id());
220       if (address_type->AsSampledImage() != nullptr) {
221         const auto* image_type =
222             address_type->AsSampledImage()->image_type()->AsImage();
223         if (image_type->sampled() == 1) {
224           return true;
225         }
226       }
227     }
228   }
229   return false;
230 }
231 
GetBaseAddress() const232 Instruction* Instruction::GetBaseAddress() const {
233   uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
234   Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
235   bool done = false;
236   while (!done) {
237     switch (base_inst->opcode()) {
238       case SpvOpAccessChain:
239       case SpvOpInBoundsAccessChain:
240       case SpvOpPtrAccessChain:
241       case SpvOpInBoundsPtrAccessChain:
242       case SpvOpImageTexelPointer:
243       case SpvOpCopyObject:
244         // All of these instructions have the base pointer use a base pointer
245         // in in-operand 0.
246         base = base_inst->GetSingleWordInOperand(0);
247         base_inst = context()->get_def_use_mgr()->GetDef(base);
248         break;
249       default:
250         done = true;
251         break;
252     }
253   }
254   return base_inst;
255 }
256 
IsReadOnlyPointer() const257 bool Instruction::IsReadOnlyPointer() const {
258   if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
259     return IsReadOnlyPointerShaders();
260   else
261     return IsReadOnlyPointerKernel();
262 }
263 
IsVulkanStorageImage() const264 bool Instruction::IsVulkanStorageImage() const {
265   if (opcode() != SpvOpTypePointer) {
266     return false;
267   }
268 
269   uint32_t storage_class =
270       GetSingleWordInOperand(kPointerTypeStorageClassIndex);
271   if (storage_class != SpvStorageClassUniformConstant) {
272     return false;
273   }
274 
275   Instruction* base_type =
276       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
277 
278   // Unpack the optional layer of arraying.
279   if (base_type->opcode() == SpvOpTypeArray ||
280       base_type->opcode() == SpvOpTypeRuntimeArray) {
281     base_type = context()->get_def_use_mgr()->GetDef(
282         base_type->GetSingleWordInOperand(0));
283   }
284 
285   if (base_type->opcode() != SpvOpTypeImage) {
286     return false;
287   }
288 
289   if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
290     return false;
291   }
292 
293   // Check if the image is sampled.  If we do not know for sure that it is,
294   // then assume it is a storage image.
295   return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
296 }
297 
IsVulkanSampledImage() const298 bool Instruction::IsVulkanSampledImage() const {
299   if (opcode() != SpvOpTypePointer) {
300     return false;
301   }
302 
303   uint32_t storage_class =
304       GetSingleWordInOperand(kPointerTypeStorageClassIndex);
305   if (storage_class != SpvStorageClassUniformConstant) {
306     return false;
307   }
308 
309   Instruction* base_type =
310       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
311 
312   // Unpack the optional layer of arraying.
313   if (base_type->opcode() == SpvOpTypeArray ||
314       base_type->opcode() == SpvOpTypeRuntimeArray) {
315     base_type = context()->get_def_use_mgr()->GetDef(
316         base_type->GetSingleWordInOperand(0));
317   }
318 
319   if (base_type->opcode() != SpvOpTypeImage) {
320     return false;
321   }
322 
323   if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
324     return false;
325   }
326 
327   // Check if the image is sampled.  If we know for sure that it is,
328   // then return true.
329   return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) == 1;
330 }
331 
IsVulkanStorageTexelBuffer() const332 bool Instruction::IsVulkanStorageTexelBuffer() const {
333   if (opcode() != SpvOpTypePointer) {
334     return false;
335   }
336 
337   uint32_t storage_class =
338       GetSingleWordInOperand(kPointerTypeStorageClassIndex);
339   if (storage_class != SpvStorageClassUniformConstant) {
340     return false;
341   }
342 
343   Instruction* base_type =
344       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
345 
346   // Unpack the optional layer of arraying.
347   if (base_type->opcode() == SpvOpTypeArray ||
348       base_type->opcode() == SpvOpTypeRuntimeArray) {
349     base_type = context()->get_def_use_mgr()->GetDef(
350         base_type->GetSingleWordInOperand(0));
351   }
352 
353   if (base_type->opcode() != SpvOpTypeImage) {
354     return false;
355   }
356 
357   if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
358     return false;
359   }
360 
361   // Check if the image is sampled.  If we do not know for sure that it is,
362   // then assume it is a storage texel buffer.
363   return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
364 }
365 
IsVulkanStorageBuffer() const366 bool Instruction::IsVulkanStorageBuffer() const {
367   // Is there a difference between a "Storage buffer" and a "dynamic storage
368   // buffer" in SPIR-V and do we care about the difference?
369   if (opcode() != SpvOpTypePointer) {
370     return false;
371   }
372 
373   Instruction* base_type =
374       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
375 
376   // Unpack the optional layer of arraying.
377   if (base_type->opcode() == SpvOpTypeArray ||
378       base_type->opcode() == SpvOpTypeRuntimeArray) {
379     base_type = context()->get_def_use_mgr()->GetDef(
380         base_type->GetSingleWordInOperand(0));
381   }
382 
383   if (base_type->opcode() != SpvOpTypeStruct) {
384     return false;
385   }
386 
387   uint32_t storage_class =
388       GetSingleWordInOperand(kPointerTypeStorageClassIndex);
389   if (storage_class == SpvStorageClassUniform) {
390     bool is_buffer_block = false;
391     context()->get_decoration_mgr()->ForEachDecoration(
392         base_type->result_id(), SpvDecorationBufferBlock,
393         [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
394     return is_buffer_block;
395   } else if (storage_class == SpvStorageClassStorageBuffer) {
396     bool is_block = false;
397     context()->get_decoration_mgr()->ForEachDecoration(
398         base_type->result_id(), SpvDecorationBlock,
399         [&is_block](const Instruction&) { is_block = true; });
400     return is_block;
401   }
402   return false;
403 }
404 
IsVulkanStorageBufferVariable() const405 bool Instruction::IsVulkanStorageBufferVariable() const {
406   if (opcode() != SpvOpVariable) {
407     return false;
408   }
409 
410   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
411   if (storage_class == SpvStorageClassStorageBuffer ||
412       storage_class == SpvStorageClassUniform) {
413     Instruction* var_type = context()->get_def_use_mgr()->GetDef(type_id());
414     return var_type != nullptr && var_type->IsVulkanStorageBuffer();
415   }
416 
417   return false;
418 }
419 
IsVulkanUniformBuffer() const420 bool Instruction::IsVulkanUniformBuffer() const {
421   if (opcode() != SpvOpTypePointer) {
422     return false;
423   }
424 
425   uint32_t storage_class =
426       GetSingleWordInOperand(kPointerTypeStorageClassIndex);
427   if (storage_class != SpvStorageClassUniform) {
428     return false;
429   }
430 
431   Instruction* base_type =
432       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
433 
434   // Unpack the optional layer of arraying.
435   if (base_type->opcode() == SpvOpTypeArray ||
436       base_type->opcode() == SpvOpTypeRuntimeArray) {
437     base_type = context()->get_def_use_mgr()->GetDef(
438         base_type->GetSingleWordInOperand(0));
439   }
440 
441   if (base_type->opcode() != SpvOpTypeStruct) {
442     return false;
443   }
444 
445   bool is_block = false;
446   context()->get_decoration_mgr()->ForEachDecoration(
447       base_type->result_id(), SpvDecorationBlock,
448       [&is_block](const Instruction&) { is_block = true; });
449   return is_block;
450 }
451 
IsReadOnlyPointerShaders() const452 bool Instruction::IsReadOnlyPointerShaders() const {
453   if (type_id() == 0) {
454     return false;
455   }
456 
457   Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
458   if (type_def->opcode() != SpvOpTypePointer) {
459     return false;
460   }
461 
462   uint32_t storage_class =
463       type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
464 
465   switch (storage_class) {
466     case SpvStorageClassUniformConstant:
467       if (!type_def->IsVulkanStorageImage() &&
468           !type_def->IsVulkanStorageTexelBuffer()) {
469         return true;
470       }
471       break;
472     case SpvStorageClassUniform:
473       if (!type_def->IsVulkanStorageBuffer()) {
474         return true;
475       }
476       break;
477     case SpvStorageClassPushConstant:
478     case SpvStorageClassInput:
479       return true;
480     default:
481       break;
482   }
483 
484   bool is_nonwritable = false;
485   context()->get_decoration_mgr()->ForEachDecoration(
486       result_id(), SpvDecorationNonWritable,
487       [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
488   return is_nonwritable;
489 }
490 
IsReadOnlyPointerKernel() const491 bool Instruction::IsReadOnlyPointerKernel() const {
492   if (type_id() == 0) {
493     return false;
494   }
495 
496   Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
497   if (type_def->opcode() != SpvOpTypePointer) {
498     return false;
499   }
500 
501   uint32_t storage_class =
502       type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
503 
504   return storage_class == SpvStorageClassUniformConstant;
505 }
506 
GetTypeComponent(uint32_t element) const507 uint32_t Instruction::GetTypeComponent(uint32_t element) const {
508   uint32_t subtype = 0;
509   switch (opcode()) {
510     case SpvOpTypeStruct:
511       subtype = GetSingleWordInOperand(element);
512       break;
513     case SpvOpTypeArray:
514     case SpvOpTypeRuntimeArray:
515     case SpvOpTypeVector:
516     case SpvOpTypeMatrix:
517       // These types all have uniform subtypes.
518       subtype = GetSingleWordInOperand(0u);
519       break;
520     default:
521       break;
522   }
523 
524   return subtype;
525 }
526 
UpdateLexicalScope(uint32_t scope)527 void Instruction::UpdateLexicalScope(uint32_t scope) {
528   dbg_scope_.SetLexicalScope(scope);
529   for (auto& i : dbg_line_insts_) {
530     i.dbg_scope_.SetLexicalScope(scope);
531   }
532   if (!IsLineInst() &&
533       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
534     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
535   }
536 }
537 
UpdateDebugInlinedAt(uint32_t new_inlined_at)538 void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) {
539   dbg_scope_.SetInlinedAt(new_inlined_at);
540   for (auto& i : dbg_line_insts_) {
541     i.dbg_scope_.SetInlinedAt(new_inlined_at);
542   }
543   if (!IsLineInst() &&
544       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
545     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
546   }
547 }
548 
ClearDbgLineInsts()549 void Instruction::ClearDbgLineInsts() {
550   if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) {
551     auto def_use_mgr = context()->get_def_use_mgr();
552     for (auto& l_inst : dbg_line_insts_) def_use_mgr->ClearInst(&l_inst);
553   }
554   clear_dbg_line_insts();
555 }
556 
UpdateDebugInfoFrom(const Instruction * from)557 void Instruction::UpdateDebugInfoFrom(const Instruction* from) {
558   if (from == nullptr) return;
559   ClearDbgLineInsts();
560   if (!from->dbg_line_insts().empty())
561     AddDebugLine(&from->dbg_line_insts().back());
562   SetDebugScope(from->GetDebugScope());
563   if (!IsLineInst() &&
564       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
565     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
566   }
567 }
568 
AddDebugLine(const Instruction * inst)569 void Instruction::AddDebugLine(const Instruction* inst) {
570   dbg_line_insts_.push_back(*inst);
571   dbg_line_insts_.back().unique_id_ = context()->TakeNextUniqueId();
572   if (inst->IsDebugLineInst())
573     dbg_line_insts_.back().SetResultId(context_->TakeNextId());
574   if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse))
575     context()->get_def_use_mgr()->AnalyzeInstDefUse(&dbg_line_insts_.back());
576 }
577 
IsDebugLineInst() const578 bool Instruction::IsDebugLineInst() const {
579   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
580   return ((ext_opt == NonSemanticShaderDebugInfo100DebugLine) ||
581           (ext_opt == NonSemanticShaderDebugInfo100DebugNoLine));
582 }
583 
IsLineInst() const584 bool Instruction::IsLineInst() const { return IsLine() || IsNoLine(); }
585 
IsLine() const586 bool Instruction::IsLine() const {
587   if (opcode() == SpvOpLine) return true;
588   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
589   return ext_opt == NonSemanticShaderDebugInfo100DebugLine;
590 }
591 
IsNoLine() const592 bool Instruction::IsNoLine() const {
593   if (opcode() == SpvOpNoLine) return true;
594   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
595   return ext_opt == NonSemanticShaderDebugInfo100DebugNoLine;
596 }
597 
InsertBefore(std::unique_ptr<Instruction> && inst)598 Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& inst) {
599   inst.get()->InsertBefore(this);
600   return inst.release();
601 }
602 
InsertBefore(std::vector<std::unique_ptr<Instruction>> && list)603 Instruction* Instruction::InsertBefore(
604     std::vector<std::unique_ptr<Instruction>>&& list) {
605   Instruction* first_node = list.front().get();
606   for (auto& inst : list) {
607     inst.release()->InsertBefore(this);
608   }
609   list.clear();
610   return first_node;
611 }
612 
IsValidBasePointer() const613 bool Instruction::IsValidBasePointer() const {
614   uint32_t tid = type_id();
615   if (tid == 0) {
616     return false;
617   }
618 
619   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
620   if (type->opcode() != SpvOpTypePointer) {
621     return false;
622   }
623 
624   auto feature_mgr = context()->get_feature_mgr();
625   if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
626     // TODO: The rules here could be more restrictive.
627     return true;
628   }
629 
630   if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
631     return true;
632   }
633 
634   // With variable pointers, there are more valid base pointer objects.
635   // Variable pointers implicitly declares Variable pointers storage buffer.
636   SpvStorageClass storage_class =
637       static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
638   if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
639        storage_class == SpvStorageClassStorageBuffer) ||
640       (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
641        storage_class == SpvStorageClassWorkgroup)) {
642     switch (opcode()) {
643       case SpvOpPhi:
644       case SpvOpSelect:
645       case SpvOpFunctionCall:
646       case SpvOpConstantNull:
647         return true;
648       default:
649         break;
650     }
651   }
652 
653   uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
654   Instruction* pointee_type_inst =
655       context()->get_def_use_mgr()->GetDef(pointee_type_id);
656 
657   if (pointee_type_inst->IsOpaqueType()) {
658     return true;
659   }
660   return false;
661 }
662 
GetOpenCL100DebugOpcode() const663 OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
664   if (opcode() != SpvOpExtInst) {
665     return OpenCLDebugInfo100InstructionsMax;
666   }
667 
668   if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
669     return OpenCLDebugInfo100InstructionsMax;
670   }
671 
672   if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
673       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
674     return OpenCLDebugInfo100InstructionsMax;
675   }
676 
677   return OpenCLDebugInfo100Instructions(
678       GetSingleWordInOperand(kExtInstInstructionInIdx));
679 }
680 
GetShader100DebugOpcode() const681 NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode()
682     const {
683   if (opcode() != SpvOpExtInst) {
684     return NonSemanticShaderDebugInfo100InstructionsMax;
685   }
686 
687   if (!context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
688     return NonSemanticShaderDebugInfo100InstructionsMax;
689   }
690 
691   if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
692       context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
693     return NonSemanticShaderDebugInfo100InstructionsMax;
694   }
695 
696   return NonSemanticShaderDebugInfo100Instructions(
697       GetSingleWordInOperand(kExtInstInstructionInIdx));
698 }
699 
GetCommonDebugOpcode() const700 CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const {
701   if (opcode() != SpvOpExtInst) {
702     return CommonDebugInfoInstructionsMax;
703   }
704 
705   const uint32_t opencl_set_id =
706       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
707   const uint32_t shader_set_id =
708       context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo();
709 
710   if (!opencl_set_id && !shader_set_id) {
711     return CommonDebugInfoInstructionsMax;
712   }
713 
714   const uint32_t used_set_id = GetSingleWordInOperand(kExtInstSetIdInIdx);
715 
716   if (used_set_id != opencl_set_id && used_set_id != shader_set_id) {
717     return CommonDebugInfoInstructionsMax;
718   }
719 
720   return CommonDebugInfoInstructions(
721       GetSingleWordInOperand(kExtInstInstructionInIdx));
722 }
723 
IsValidBaseImage() const724 bool Instruction::IsValidBaseImage() const {
725   uint32_t tid = type_id();
726   if (tid == 0) {
727     return false;
728   }
729 
730   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
731   return (type->opcode() == SpvOpTypeImage ||
732           type->opcode() == SpvOpTypeSampledImage);
733 }
734 
IsOpaqueType() const735 bool Instruction::IsOpaqueType() const {
736   if (opcode() == SpvOpTypeStruct) {
737     bool is_opaque = false;
738     ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
739       Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
740       is_opaque |= type_inst->IsOpaqueType();
741     });
742     return is_opaque;
743   } else if (opcode() == SpvOpTypeArray) {
744     uint32_t sub_type_id = GetSingleWordInOperand(0);
745     Instruction* sub_type_inst =
746         context()->get_def_use_mgr()->GetDef(sub_type_id);
747     return sub_type_inst->IsOpaqueType();
748   } else {
749     return opcode() == SpvOpTypeRuntimeArray ||
750            spvOpcodeIsBaseOpaqueType(opcode());
751   }
752 }
753 
IsFoldable() const754 bool Instruction::IsFoldable() const {
755   return IsFoldableByFoldScalar() ||
756          context()->get_instruction_folder().HasConstFoldingRule(this);
757 }
758 
IsFoldableByFoldScalar() const759 bool Instruction::IsFoldableByFoldScalar() const {
760   const InstructionFolder& folder = context()->get_instruction_folder();
761   if (!folder.IsFoldableOpcode(opcode())) {
762     return false;
763   }
764 
765   Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
766   if (!folder.IsFoldableType(type)) {
767     return false;
768   }
769 
770   // Even if the type of the instruction is foldable, its operands may not be
771   // foldable (e.g., comparisons of 64bit types).  Check that all operand types
772   // are foldable before accepting the instruction.
773   return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
774     Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
775     Instruction* def_inst_type =
776         context()->get_def_use_mgr()->GetDef(def_inst->type_id());
777     return folder.IsFoldableType(def_inst_type);
778   });
779 }
780 
IsFloatingPointFoldingAllowed() const781 bool Instruction::IsFloatingPointFoldingAllowed() const {
782   // TODO: Add the rules for kernels.  For now it will be pessimistic.
783   // For now, do not support capabilities introduced by SPV_KHR_float_controls.
784   if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
785       context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
786       context_->get_feature_mgr()->HasCapability(
787           SpvCapabilityDenormFlushToZero) ||
788       context_->get_feature_mgr()->HasCapability(
789           SpvCapabilitySignedZeroInfNanPreserve) ||
790       context_->get_feature_mgr()->HasCapability(
791           SpvCapabilityRoundingModeRTZ) ||
792       context_->get_feature_mgr()->HasCapability(
793           SpvCapabilityRoundingModeRTE)) {
794     return false;
795   }
796 
797   bool is_nocontract = false;
798   context_->get_decoration_mgr()->WhileEachDecoration(
799       result_id(), SpvDecorationNoContraction,
800       [&is_nocontract](const Instruction&) {
801         is_nocontract = true;
802         return false;
803       });
804   return !is_nocontract;
805 }
806 
PrettyPrint(uint32_t options) const807 std::string Instruction::PrettyPrint(uint32_t options) const {
808   // Convert the module to binary.
809   std::vector<uint32_t> module_binary;
810   context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
811 
812   // Convert the instruction to binary. This is used to identify the correct
813   // stream of words to output from the module.
814   std::vector<uint32_t> inst_binary;
815   ToBinaryWithoutAttachedDebugInsts(&inst_binary);
816 
817   // Do not generate a header.
818   return spvInstructionBinaryToText(
819       context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
820       module_binary.data(), module_binary.size(),
821       options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
822 }
823 
operator <<(std::ostream & str,const Instruction & inst)824 std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
825   str << inst.PrettyPrint();
826   return str;
827 }
828 
Dump() const829 void Instruction::Dump() const {
830   std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
831 }
832 
IsOpcodeCodeMotionSafe() const833 bool Instruction::IsOpcodeCodeMotionSafe() const {
834   switch (opcode_) {
835     case SpvOpNop:
836     case SpvOpUndef:
837     case SpvOpLoad:
838     case SpvOpAccessChain:
839     case SpvOpInBoundsAccessChain:
840     case SpvOpArrayLength:
841     case SpvOpVectorExtractDynamic:
842     case SpvOpVectorInsertDynamic:
843     case SpvOpVectorShuffle:
844     case SpvOpCompositeConstruct:
845     case SpvOpCompositeExtract:
846     case SpvOpCompositeInsert:
847     case SpvOpCopyObject:
848     case SpvOpTranspose:
849     case SpvOpConvertFToU:
850     case SpvOpConvertFToS:
851     case SpvOpConvertSToF:
852     case SpvOpConvertUToF:
853     case SpvOpUConvert:
854     case SpvOpSConvert:
855     case SpvOpFConvert:
856     case SpvOpQuantizeToF16:
857     case SpvOpBitcast:
858     case SpvOpSNegate:
859     case SpvOpFNegate:
860     case SpvOpIAdd:
861     case SpvOpFAdd:
862     case SpvOpISub:
863     case SpvOpFSub:
864     case SpvOpIMul:
865     case SpvOpFMul:
866     case SpvOpUDiv:
867     case SpvOpSDiv:
868     case SpvOpFDiv:
869     case SpvOpUMod:
870     case SpvOpSRem:
871     case SpvOpSMod:
872     case SpvOpFRem:
873     case SpvOpFMod:
874     case SpvOpVectorTimesScalar:
875     case SpvOpMatrixTimesScalar:
876     case SpvOpVectorTimesMatrix:
877     case SpvOpMatrixTimesVector:
878     case SpvOpMatrixTimesMatrix:
879     case SpvOpOuterProduct:
880     case SpvOpDot:
881     case SpvOpIAddCarry:
882     case SpvOpISubBorrow:
883     case SpvOpUMulExtended:
884     case SpvOpSMulExtended:
885     case SpvOpAny:
886     case SpvOpAll:
887     case SpvOpIsNan:
888     case SpvOpIsInf:
889     case SpvOpLogicalEqual:
890     case SpvOpLogicalNotEqual:
891     case SpvOpLogicalOr:
892     case SpvOpLogicalAnd:
893     case SpvOpLogicalNot:
894     case SpvOpSelect:
895     case SpvOpIEqual:
896     case SpvOpINotEqual:
897     case SpvOpUGreaterThan:
898     case SpvOpSGreaterThan:
899     case SpvOpUGreaterThanEqual:
900     case SpvOpSGreaterThanEqual:
901     case SpvOpULessThan:
902     case SpvOpSLessThan:
903     case SpvOpULessThanEqual:
904     case SpvOpSLessThanEqual:
905     case SpvOpFOrdEqual:
906     case SpvOpFUnordEqual:
907     case SpvOpFOrdNotEqual:
908     case SpvOpFUnordNotEqual:
909     case SpvOpFOrdLessThan:
910     case SpvOpFUnordLessThan:
911     case SpvOpFOrdGreaterThan:
912     case SpvOpFUnordGreaterThan:
913     case SpvOpFOrdLessThanEqual:
914     case SpvOpFUnordLessThanEqual:
915     case SpvOpFOrdGreaterThanEqual:
916     case SpvOpFUnordGreaterThanEqual:
917     case SpvOpShiftRightLogical:
918     case SpvOpShiftRightArithmetic:
919     case SpvOpShiftLeftLogical:
920     case SpvOpBitwiseOr:
921     case SpvOpBitwiseXor:
922     case SpvOpBitwiseAnd:
923     case SpvOpNot:
924     case SpvOpBitFieldInsert:
925     case SpvOpBitFieldSExtract:
926     case SpvOpBitFieldUExtract:
927     case SpvOpBitReverse:
928     case SpvOpBitCount:
929     case SpvOpSizeOf:
930       return true;
931     default:
932       return false;
933   }
934 }
935 
IsScalarizable() const936 bool Instruction::IsScalarizable() const {
937   if (spvOpcodeIsScalarizable(opcode())) {
938     return true;
939   }
940 
941   if (opcode() == SpvOpExtInst) {
942     uint32_t instSetId =
943         context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
944 
945     if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
946       switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
947         case GLSLstd450Round:
948         case GLSLstd450RoundEven:
949         case GLSLstd450Trunc:
950         case GLSLstd450FAbs:
951         case GLSLstd450SAbs:
952         case GLSLstd450FSign:
953         case GLSLstd450SSign:
954         case GLSLstd450Floor:
955         case GLSLstd450Ceil:
956         case GLSLstd450Fract:
957         case GLSLstd450Radians:
958         case GLSLstd450Degrees:
959         case GLSLstd450Sin:
960         case GLSLstd450Cos:
961         case GLSLstd450Tan:
962         case GLSLstd450Asin:
963         case GLSLstd450Acos:
964         case GLSLstd450Atan:
965         case GLSLstd450Sinh:
966         case GLSLstd450Cosh:
967         case GLSLstd450Tanh:
968         case GLSLstd450Asinh:
969         case GLSLstd450Acosh:
970         case GLSLstd450Atanh:
971         case GLSLstd450Atan2:
972         case GLSLstd450Pow:
973         case GLSLstd450Exp:
974         case GLSLstd450Log:
975         case GLSLstd450Exp2:
976         case GLSLstd450Log2:
977         case GLSLstd450Sqrt:
978         case GLSLstd450InverseSqrt:
979         case GLSLstd450Modf:
980         case GLSLstd450FMin:
981         case GLSLstd450UMin:
982         case GLSLstd450SMin:
983         case GLSLstd450FMax:
984         case GLSLstd450UMax:
985         case GLSLstd450SMax:
986         case GLSLstd450FClamp:
987         case GLSLstd450UClamp:
988         case GLSLstd450SClamp:
989         case GLSLstd450FMix:
990         case GLSLstd450Step:
991         case GLSLstd450SmoothStep:
992         case GLSLstd450Fma:
993         case GLSLstd450Frexp:
994         case GLSLstd450Ldexp:
995         case GLSLstd450FindILsb:
996         case GLSLstd450FindSMsb:
997         case GLSLstd450FindUMsb:
998         case GLSLstd450NMin:
999         case GLSLstd450NMax:
1000         case GLSLstd450NClamp:
1001           return true;
1002         default:
1003           return false;
1004       }
1005     }
1006   }
1007   return false;
1008 }
1009 
IsOpcodeSafeToDelete() const1010 bool Instruction::IsOpcodeSafeToDelete() const {
1011   if (context()->IsCombinatorInstruction(this)) {
1012     return true;
1013   }
1014 
1015   switch (opcode()) {
1016     case SpvOpDPdx:
1017     case SpvOpDPdy:
1018     case SpvOpFwidth:
1019     case SpvOpDPdxFine:
1020     case SpvOpDPdyFine:
1021     case SpvOpFwidthFine:
1022     case SpvOpDPdxCoarse:
1023     case SpvOpDPdyCoarse:
1024     case SpvOpFwidthCoarse:
1025     case SpvOpImageQueryLod:
1026       return true;
1027     default:
1028       return false;
1029   }
1030 }
1031 
IsNonSemanticInstruction() const1032 bool Instruction::IsNonSemanticInstruction() const {
1033   if (!HasResultId()) return false;
1034   if (opcode() != SpvOpExtInst) return false;
1035 
1036   auto import_inst =
1037       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(0));
1038   std::string import_name = import_inst->GetInOperand(0).AsString();
1039   return import_name.find("NonSemantic.") == 0;
1040 }
1041 
ToBinary(uint32_t type_id,uint32_t result_id,uint32_t ext_set,std::vector<uint32_t> * binary) const1042 void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
1043                           uint32_t ext_set,
1044                           std::vector<uint32_t>* binary) const {
1045   uint32_t num_words = kDebugScopeNumWords;
1046   CommonDebugInfoInstructions dbg_opcode = CommonDebugInfoDebugScope;
1047   if (GetLexicalScope() == kNoDebugScope) {
1048     num_words = kDebugNoScopeNumWords;
1049     dbg_opcode = CommonDebugInfoDebugNoScope;
1050   } else if (GetInlinedAt() == kNoInlinedAt) {
1051     num_words = kDebugScopeNumWordsWithoutInlinedAt;
1052   }
1053   std::vector<uint32_t> operands = {
1054       (num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
1055       type_id,
1056       result_id,
1057       ext_set,
1058       static_cast<uint32_t>(dbg_opcode),
1059   };
1060   binary->insert(binary->end(), operands.begin(), operands.end());
1061   if (GetLexicalScope() != kNoDebugScope) {
1062     binary->push_back(GetLexicalScope());
1063     if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
1064   }
1065 }
1066 
1067 }  // namespace opt
1068 }  // namespace spvtools
1069