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