• 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 
UpdateLexicalScope(uint32_t scope)507 void Instruction::UpdateLexicalScope(uint32_t scope) {
508   dbg_scope_.SetLexicalScope(scope);
509   for (auto& i : dbg_line_insts_) {
510     i.dbg_scope_.SetLexicalScope(scope);
511   }
512   if (!IsLineInst() &&
513       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
514     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
515   }
516 }
517 
UpdateDebugInlinedAt(uint32_t new_inlined_at)518 void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) {
519   dbg_scope_.SetInlinedAt(new_inlined_at);
520   for (auto& i : dbg_line_insts_) {
521     i.dbg_scope_.SetInlinedAt(new_inlined_at);
522   }
523   if (!IsLineInst() &&
524       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
525     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
526   }
527 }
528 
ClearDbgLineInsts()529 void Instruction::ClearDbgLineInsts() {
530   if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) {
531     auto def_use_mgr = context()->get_def_use_mgr();
532     for (auto& l_inst : dbg_line_insts_) def_use_mgr->ClearInst(&l_inst);
533   }
534   clear_dbg_line_insts();
535 }
536 
UpdateDebugInfoFrom(const Instruction * from)537 void Instruction::UpdateDebugInfoFrom(const Instruction* from) {
538   if (from == nullptr) return;
539   ClearDbgLineInsts();
540   if (!from->dbg_line_insts().empty())
541     AddDebugLine(&from->dbg_line_insts().back());
542   SetDebugScope(from->GetDebugScope());
543   if (!IsLineInst() &&
544       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
545     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
546   }
547 }
548 
AddDebugLine(const Instruction * inst)549 void Instruction::AddDebugLine(const Instruction* inst) {
550   dbg_line_insts_.push_back(*inst);
551   dbg_line_insts_.back().unique_id_ = context()->TakeNextUniqueId();
552   if (inst->IsDebugLineInst())
553     dbg_line_insts_.back().SetResultId(context_->TakeNextId());
554   if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse))
555     context()->get_def_use_mgr()->AnalyzeInstDefUse(&dbg_line_insts_.back());
556 }
557 
IsDebugLineInst() const558 bool Instruction::IsDebugLineInst() const {
559   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
560   return ((ext_opt == NonSemanticShaderDebugInfo100DebugLine) ||
561           (ext_opt == NonSemanticShaderDebugInfo100DebugNoLine));
562 }
563 
IsLineInst() const564 bool Instruction::IsLineInst() const { return IsLine() || IsNoLine(); }
565 
IsLine() const566 bool Instruction::IsLine() const {
567   if (opcode() == SpvOpLine) return true;
568   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
569   return ext_opt == NonSemanticShaderDebugInfo100DebugLine;
570 }
571 
IsNoLine() const572 bool Instruction::IsNoLine() const {
573   if (opcode() == SpvOpNoLine) return true;
574   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
575   return ext_opt == NonSemanticShaderDebugInfo100DebugNoLine;
576 }
577 
InsertBefore(std::unique_ptr<Instruction> && inst)578 Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& inst) {
579   inst.get()->InsertBefore(this);
580   return inst.release();
581 }
582 
InsertBefore(std::vector<std::unique_ptr<Instruction>> && list)583 Instruction* Instruction::InsertBefore(
584     std::vector<std::unique_ptr<Instruction>>&& list) {
585   Instruction* first_node = list.front().get();
586   for (auto& inst : list) {
587     inst.release()->InsertBefore(this);
588   }
589   list.clear();
590   return first_node;
591 }
592 
IsValidBasePointer() const593 bool Instruction::IsValidBasePointer() const {
594   uint32_t tid = type_id();
595   if (tid == 0) {
596     return false;
597   }
598 
599   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
600   if (type->opcode() != SpvOpTypePointer) {
601     return false;
602   }
603 
604   auto feature_mgr = context()->get_feature_mgr();
605   if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
606     // TODO: The rules here could be more restrictive.
607     return true;
608   }
609 
610   if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
611     return true;
612   }
613 
614   // With variable pointers, there are more valid base pointer objects.
615   // Variable pointers implicitly declares Variable pointers storage buffer.
616   SpvStorageClass storage_class =
617       static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
618   if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
619        storage_class == SpvStorageClassStorageBuffer) ||
620       (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
621        storage_class == SpvStorageClassWorkgroup)) {
622     switch (opcode()) {
623       case SpvOpPhi:
624       case SpvOpSelect:
625       case SpvOpFunctionCall:
626       case SpvOpConstantNull:
627         return true;
628       default:
629         break;
630     }
631   }
632 
633   uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
634   Instruction* pointee_type_inst =
635       context()->get_def_use_mgr()->GetDef(pointee_type_id);
636 
637   if (pointee_type_inst->IsOpaqueType()) {
638     return true;
639   }
640   return false;
641 }
642 
GetOpenCL100DebugOpcode() const643 OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
644   if (opcode() != SpvOpExtInst) {
645     return OpenCLDebugInfo100InstructionsMax;
646   }
647 
648   if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
649     return OpenCLDebugInfo100InstructionsMax;
650   }
651 
652   if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
653       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
654     return OpenCLDebugInfo100InstructionsMax;
655   }
656 
657   return OpenCLDebugInfo100Instructions(
658       GetSingleWordInOperand(kExtInstInstructionInIdx));
659 }
660 
GetShader100DebugOpcode() const661 NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode()
662     const {
663   if (opcode() != SpvOpExtInst) {
664     return NonSemanticShaderDebugInfo100InstructionsMax;
665   }
666 
667   if (!context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
668     return NonSemanticShaderDebugInfo100InstructionsMax;
669   }
670 
671   if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
672       context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
673     return NonSemanticShaderDebugInfo100InstructionsMax;
674   }
675 
676   uint32_t opcode = GetSingleWordInOperand(kExtInstInstructionInIdx);
677   if (opcode >= NonSemanticShaderDebugInfo100InstructionsMax) {
678     return NonSemanticShaderDebugInfo100InstructionsMax;
679   }
680 
681   return NonSemanticShaderDebugInfo100Instructions(opcode);
682 }
683 
GetCommonDebugOpcode() const684 CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const {
685   if (opcode() != SpvOpExtInst) {
686     return CommonDebugInfoInstructionsMax;
687   }
688 
689   const uint32_t opencl_set_id =
690       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
691   const uint32_t shader_set_id =
692       context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo();
693 
694   if (!opencl_set_id && !shader_set_id) {
695     return CommonDebugInfoInstructionsMax;
696   }
697 
698   const uint32_t used_set_id = GetSingleWordInOperand(kExtInstSetIdInIdx);
699 
700   if (used_set_id != opencl_set_id && used_set_id != shader_set_id) {
701     return CommonDebugInfoInstructionsMax;
702   }
703 
704   return CommonDebugInfoInstructions(
705       GetSingleWordInOperand(kExtInstInstructionInIdx));
706 }
707 
IsValidBaseImage() const708 bool Instruction::IsValidBaseImage() const {
709   uint32_t tid = type_id();
710   if (tid == 0) {
711     return false;
712   }
713 
714   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
715   return (type->opcode() == SpvOpTypeImage ||
716           type->opcode() == SpvOpTypeSampledImage);
717 }
718 
IsOpaqueType() const719 bool Instruction::IsOpaqueType() const {
720   if (opcode() == SpvOpTypeStruct) {
721     bool is_opaque = false;
722     ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
723       Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
724       is_opaque |= type_inst->IsOpaqueType();
725     });
726     return is_opaque;
727   } else if (opcode() == SpvOpTypeArray) {
728     uint32_t sub_type_id = GetSingleWordInOperand(0);
729     Instruction* sub_type_inst =
730         context()->get_def_use_mgr()->GetDef(sub_type_id);
731     return sub_type_inst->IsOpaqueType();
732   } else {
733     return opcode() == SpvOpTypeRuntimeArray ||
734            spvOpcodeIsBaseOpaqueType(opcode());
735   }
736 }
737 
IsFoldable() const738 bool Instruction::IsFoldable() const {
739   return IsFoldableByFoldScalar() ||
740          context()->get_instruction_folder().HasConstFoldingRule(this);
741 }
742 
IsFoldableByFoldScalar() const743 bool Instruction::IsFoldableByFoldScalar() const {
744   const InstructionFolder& folder = context()->get_instruction_folder();
745   if (!folder.IsFoldableOpcode(opcode())) {
746     return false;
747   }
748 
749   Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
750   if (!folder.IsFoldableType(type)) {
751     return false;
752   }
753 
754   // Even if the type of the instruction is foldable, its operands may not be
755   // foldable (e.g., comparisons of 64bit types).  Check that all operand types
756   // are foldable before accepting the instruction.
757   return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
758     Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
759     Instruction* def_inst_type =
760         context()->get_def_use_mgr()->GetDef(def_inst->type_id());
761     return folder.IsFoldableType(def_inst_type);
762   });
763 }
764 
IsFloatingPointFoldingAllowed() const765 bool Instruction::IsFloatingPointFoldingAllowed() const {
766   // TODO: Add the rules for kernels.  For now it will be pessimistic.
767   // For now, do not support capabilities introduced by SPV_KHR_float_controls.
768   if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
769       context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
770       context_->get_feature_mgr()->HasCapability(
771           SpvCapabilityDenormFlushToZero) ||
772       context_->get_feature_mgr()->HasCapability(
773           SpvCapabilitySignedZeroInfNanPreserve) ||
774       context_->get_feature_mgr()->HasCapability(
775           SpvCapabilityRoundingModeRTZ) ||
776       context_->get_feature_mgr()->HasCapability(
777           SpvCapabilityRoundingModeRTE)) {
778     return false;
779   }
780 
781   bool is_nocontract = false;
782   context_->get_decoration_mgr()->WhileEachDecoration(
783       result_id(), SpvDecorationNoContraction,
784       [&is_nocontract](const Instruction&) {
785         is_nocontract = true;
786         return false;
787       });
788   return !is_nocontract;
789 }
790 
PrettyPrint(uint32_t options) const791 std::string Instruction::PrettyPrint(uint32_t options) const {
792   // Convert the module to binary.
793   std::vector<uint32_t> module_binary;
794   context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
795 
796   // Convert the instruction to binary. This is used to identify the correct
797   // stream of words to output from the module.
798   std::vector<uint32_t> inst_binary;
799   ToBinaryWithoutAttachedDebugInsts(&inst_binary);
800 
801   // Do not generate a header.
802   return spvInstructionBinaryToText(
803       context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
804       module_binary.data(), module_binary.size(),
805       options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
806 }
807 
operator <<(std::ostream & str,const Instruction & inst)808 std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
809   str << inst.PrettyPrint();
810   return str;
811 }
812 
Dump() const813 void Instruction::Dump() const {
814   std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
815 }
816 
IsOpcodeCodeMotionSafe() const817 bool Instruction::IsOpcodeCodeMotionSafe() const {
818   switch (opcode_) {
819     case SpvOpNop:
820     case SpvOpUndef:
821     case SpvOpLoad:
822     case SpvOpAccessChain:
823     case SpvOpInBoundsAccessChain:
824     case SpvOpArrayLength:
825     case SpvOpVectorExtractDynamic:
826     case SpvOpVectorInsertDynamic:
827     case SpvOpVectorShuffle:
828     case SpvOpCompositeConstruct:
829     case SpvOpCompositeExtract:
830     case SpvOpCompositeInsert:
831     case SpvOpCopyObject:
832     case SpvOpTranspose:
833     case SpvOpConvertFToU:
834     case SpvOpConvertFToS:
835     case SpvOpConvertSToF:
836     case SpvOpConvertUToF:
837     case SpvOpUConvert:
838     case SpvOpSConvert:
839     case SpvOpFConvert:
840     case SpvOpQuantizeToF16:
841     case SpvOpBitcast:
842     case SpvOpSNegate:
843     case SpvOpFNegate:
844     case SpvOpIAdd:
845     case SpvOpFAdd:
846     case SpvOpISub:
847     case SpvOpFSub:
848     case SpvOpIMul:
849     case SpvOpFMul:
850     case SpvOpUDiv:
851     case SpvOpSDiv:
852     case SpvOpFDiv:
853     case SpvOpUMod:
854     case SpvOpSRem:
855     case SpvOpSMod:
856     case SpvOpFRem:
857     case SpvOpFMod:
858     case SpvOpVectorTimesScalar:
859     case SpvOpMatrixTimesScalar:
860     case SpvOpVectorTimesMatrix:
861     case SpvOpMatrixTimesVector:
862     case SpvOpMatrixTimesMatrix:
863     case SpvOpOuterProduct:
864     case SpvOpDot:
865     case SpvOpIAddCarry:
866     case SpvOpISubBorrow:
867     case SpvOpUMulExtended:
868     case SpvOpSMulExtended:
869     case SpvOpAny:
870     case SpvOpAll:
871     case SpvOpIsNan:
872     case SpvOpIsInf:
873     case SpvOpLogicalEqual:
874     case SpvOpLogicalNotEqual:
875     case SpvOpLogicalOr:
876     case SpvOpLogicalAnd:
877     case SpvOpLogicalNot:
878     case SpvOpSelect:
879     case SpvOpIEqual:
880     case SpvOpINotEqual:
881     case SpvOpUGreaterThan:
882     case SpvOpSGreaterThan:
883     case SpvOpUGreaterThanEqual:
884     case SpvOpSGreaterThanEqual:
885     case SpvOpULessThan:
886     case SpvOpSLessThan:
887     case SpvOpULessThanEqual:
888     case SpvOpSLessThanEqual:
889     case SpvOpFOrdEqual:
890     case SpvOpFUnordEqual:
891     case SpvOpFOrdNotEqual:
892     case SpvOpFUnordNotEqual:
893     case SpvOpFOrdLessThan:
894     case SpvOpFUnordLessThan:
895     case SpvOpFOrdGreaterThan:
896     case SpvOpFUnordGreaterThan:
897     case SpvOpFOrdLessThanEqual:
898     case SpvOpFUnordLessThanEqual:
899     case SpvOpFOrdGreaterThanEqual:
900     case SpvOpFUnordGreaterThanEqual:
901     case SpvOpShiftRightLogical:
902     case SpvOpShiftRightArithmetic:
903     case SpvOpShiftLeftLogical:
904     case SpvOpBitwiseOr:
905     case SpvOpBitwiseXor:
906     case SpvOpBitwiseAnd:
907     case SpvOpNot:
908     case SpvOpBitFieldInsert:
909     case SpvOpBitFieldSExtract:
910     case SpvOpBitFieldUExtract:
911     case SpvOpBitReverse:
912     case SpvOpBitCount:
913     case SpvOpSizeOf:
914       return true;
915     default:
916       return false;
917   }
918 }
919 
IsScalarizable() const920 bool Instruction::IsScalarizable() const {
921   if (spvOpcodeIsScalarizable(opcode())) {
922     return true;
923   }
924 
925   if (opcode() == SpvOpExtInst) {
926     uint32_t instSetId =
927         context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
928 
929     if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
930       switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
931         case GLSLstd450Round:
932         case GLSLstd450RoundEven:
933         case GLSLstd450Trunc:
934         case GLSLstd450FAbs:
935         case GLSLstd450SAbs:
936         case GLSLstd450FSign:
937         case GLSLstd450SSign:
938         case GLSLstd450Floor:
939         case GLSLstd450Ceil:
940         case GLSLstd450Fract:
941         case GLSLstd450Radians:
942         case GLSLstd450Degrees:
943         case GLSLstd450Sin:
944         case GLSLstd450Cos:
945         case GLSLstd450Tan:
946         case GLSLstd450Asin:
947         case GLSLstd450Acos:
948         case GLSLstd450Atan:
949         case GLSLstd450Sinh:
950         case GLSLstd450Cosh:
951         case GLSLstd450Tanh:
952         case GLSLstd450Asinh:
953         case GLSLstd450Acosh:
954         case GLSLstd450Atanh:
955         case GLSLstd450Atan2:
956         case GLSLstd450Pow:
957         case GLSLstd450Exp:
958         case GLSLstd450Log:
959         case GLSLstd450Exp2:
960         case GLSLstd450Log2:
961         case GLSLstd450Sqrt:
962         case GLSLstd450InverseSqrt:
963         case GLSLstd450Modf:
964         case GLSLstd450FMin:
965         case GLSLstd450UMin:
966         case GLSLstd450SMin:
967         case GLSLstd450FMax:
968         case GLSLstd450UMax:
969         case GLSLstd450SMax:
970         case GLSLstd450FClamp:
971         case GLSLstd450UClamp:
972         case GLSLstd450SClamp:
973         case GLSLstd450FMix:
974         case GLSLstd450Step:
975         case GLSLstd450SmoothStep:
976         case GLSLstd450Fma:
977         case GLSLstd450Frexp:
978         case GLSLstd450Ldexp:
979         case GLSLstd450FindILsb:
980         case GLSLstd450FindSMsb:
981         case GLSLstd450FindUMsb:
982         case GLSLstd450NMin:
983         case GLSLstd450NMax:
984         case GLSLstd450NClamp:
985           return true;
986         default:
987           return false;
988       }
989     }
990   }
991   return false;
992 }
993 
IsOpcodeSafeToDelete() const994 bool Instruction::IsOpcodeSafeToDelete() const {
995   if (context()->IsCombinatorInstruction(this)) {
996     return true;
997   }
998 
999   switch (opcode()) {
1000     case SpvOpDPdx:
1001     case SpvOpDPdy:
1002     case SpvOpFwidth:
1003     case SpvOpDPdxFine:
1004     case SpvOpDPdyFine:
1005     case SpvOpFwidthFine:
1006     case SpvOpDPdxCoarse:
1007     case SpvOpDPdyCoarse:
1008     case SpvOpFwidthCoarse:
1009     case SpvOpImageQueryLod:
1010       return true;
1011     default:
1012       return false;
1013   }
1014 }
1015 
IsNonSemanticInstruction() const1016 bool Instruction::IsNonSemanticInstruction() const {
1017   if (!HasResultId()) return false;
1018   if (opcode() != SpvOpExtInst) return false;
1019 
1020   auto import_inst =
1021       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(0));
1022   std::string import_name = import_inst->GetInOperand(0).AsString();
1023   return import_name.find("NonSemantic.") == 0;
1024 }
1025 
ToBinary(uint32_t type_id,uint32_t result_id,uint32_t ext_set,std::vector<uint32_t> * binary) const1026 void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
1027                           uint32_t ext_set,
1028                           std::vector<uint32_t>* binary) const {
1029   uint32_t num_words = kDebugScopeNumWords;
1030   CommonDebugInfoInstructions dbg_opcode = CommonDebugInfoDebugScope;
1031   if (GetLexicalScope() == kNoDebugScope) {
1032     num_words = kDebugNoScopeNumWords;
1033     dbg_opcode = CommonDebugInfoDebugNoScope;
1034   } else if (GetInlinedAt() == kNoInlinedAt) {
1035     num_words = kDebugScopeNumWordsWithoutInlinedAt;
1036   }
1037   std::vector<uint32_t> operands = {
1038       (num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
1039       type_id,
1040       result_id,
1041       ext_set,
1042       static_cast<uint32_t>(dbg_opcode),
1043   };
1044   binary->insert(binary->end(), operands.begin(), operands.end());
1045   if (GetLexicalScope() != kNoDebugScope) {
1046     binary->push_back(GetLexicalScope());
1047     if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
1048   }
1049 }
1050 
1051 }  // namespace opt
1052 }  // namespace spvtools
1053