• 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 namespace {
28 // Indices used to get particular operands out of instructions using InOperand.
29 constexpr uint32_t kTypeImageDimIndex = 1;
30 constexpr uint32_t kLoadBaseIndex = 0;
31 constexpr uint32_t kPointerTypeStorageClassIndex = 0;
32 constexpr uint32_t kVariableStorageClassIndex = 0;
33 constexpr uint32_t kTypeImageSampledIndex = 5;
34 
35 // Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100
36 // extension instructions.
37 constexpr uint32_t kExtInstSetIdInIdx = 0;
38 constexpr uint32_t kExtInstInstructionInIdx = 1;
39 constexpr uint32_t kDebugScopeNumWords = 7;
40 constexpr uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
41 constexpr uint32_t kDebugNoScopeNumWords = 5;
42 
43 // Number of operands of an OpBranchConditional instruction
44 // with weights.
45 constexpr uint32_t kOpBranchConditionalWithWeightsNumOperands = 5;
46 }  // namespace
47 
Instruction(IRContext * c)48 Instruction::Instruction(IRContext* c)
49     : utils::IntrusiveNodeBase<Instruction>(),
50       context_(c),
51       opcode_(spv::Op::OpNop),
52       has_type_id_(false),
53       has_result_id_(false),
54       unique_id_(c->TakeNextUniqueId()),
55       dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
56 
Instruction(IRContext * c,spv::Op op)57 Instruction::Instruction(IRContext* c, spv::Op op)
58     : utils::IntrusiveNodeBase<Instruction>(),
59       context_(c),
60       opcode_(op),
61       has_type_id_(false),
62       has_result_id_(false),
63       unique_id_(c->TakeNextUniqueId()),
64       dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
65 
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,std::vector<Instruction> && dbg_line)66 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
67                          std::vector<Instruction>&& dbg_line)
68     : utils::IntrusiveNodeBase<Instruction>(),
69       context_(c),
70       opcode_(static_cast<spv::Op>(inst.opcode)),
71       has_type_id_(inst.type_id != 0),
72       has_result_id_(inst.result_id != 0),
73       unique_id_(c->TakeNextUniqueId()),
74       dbg_line_insts_(std::move(dbg_line)),
75       dbg_scope_(kNoDebugScope, kNoInlinedAt) {
76   operands_.reserve(inst.num_operands);
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<spv::Op>(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   operands_.reserve(inst.num_operands);
97   for (uint32_t i = 0; i < inst.num_operands; ++i) {
98     const auto& current_payload = inst.operands[i];
99     operands_.emplace_back(
100         current_payload.type, inst.words + current_payload.offset,
101         inst.words + current_payload.offset + current_payload.num_words);
102   }
103 }
104 
Instruction(IRContext * c,spv::Op op,uint32_t ty_id,uint32_t res_id,const OperandList & in_operands)105 Instruction::Instruction(IRContext* c, spv::Op op, uint32_t ty_id,
106                          uint32_t res_id, const OperandList& in_operands)
107     : utils::IntrusiveNodeBase<Instruction>(),
108       context_(c),
109       opcode_(op),
110       has_type_id_(ty_id != 0),
111       has_result_id_(res_id != 0),
112       unique_id_(c->TakeNextUniqueId()),
113       operands_(),
114       dbg_scope_(kNoDebugScope, kNoInlinedAt) {
115   size_t operands_size = in_operands.size();
116   if (has_type_id_) {
117     operands_size++;
118   }
119   if (has_result_id_) {
120     operands_size++;
121   }
122   operands_.reserve(operands_size);
123   if (has_type_id_) {
124     operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
125                            std::initializer_list<uint32_t>{ty_id});
126   }
127   if (has_result_id_) {
128     operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
129                            std::initializer_list<uint32_t>{res_id});
130   }
131   operands_.insert(operands_.end(), in_operands.begin(), in_operands.end());
132 }
133 
Instruction(Instruction && that)134 Instruction::Instruction(Instruction&& that)
135     : utils::IntrusiveNodeBase<Instruction>(),
136       context_(that.context_),
137       opcode_(that.opcode_),
138       has_type_id_(that.has_type_id_),
139       has_result_id_(that.has_result_id_),
140       unique_id_(that.unique_id_),
141       operands_(std::move(that.operands_)),
142       dbg_line_insts_(std::move(that.dbg_line_insts_)),
143       dbg_scope_(that.dbg_scope_) {
144   for (auto& i : dbg_line_insts_) {
145     i.dbg_scope_ = that.dbg_scope_;
146   }
147 }
148 
operator =(Instruction && that)149 Instruction& Instruction::operator=(Instruction&& that) {
150   context_ = that.context_;
151   opcode_ = that.opcode_;
152   has_type_id_ = that.has_type_id_;
153   has_result_id_ = that.has_result_id_;
154   unique_id_ = that.unique_id_;
155   operands_ = std::move(that.operands_);
156   dbg_line_insts_ = std::move(that.dbg_line_insts_);
157   dbg_scope_ = that.dbg_scope_;
158   return *this;
159 }
160 
Clone(IRContext * c) const161 Instruction* Instruction::Clone(IRContext* c) const {
162   Instruction* clone = new Instruction(c);
163   clone->opcode_ = opcode_;
164   clone->has_type_id_ = has_type_id_;
165   clone->has_result_id_ = has_result_id_;
166   clone->unique_id_ = c->TakeNextUniqueId();
167   clone->operands_ = operands_;
168   clone->dbg_line_insts_ = dbg_line_insts_;
169   for (auto& i : clone->dbg_line_insts_) {
170     i.unique_id_ = c->TakeNextUniqueId();
171     if (i.IsDebugLineInst()) i.SetResultId(c->TakeNextId());
172   }
173   clone->dbg_scope_ = dbg_scope_;
174   return clone;
175 }
176 
GetSingleWordOperand(uint32_t index) const177 uint32_t Instruction::GetSingleWordOperand(uint32_t index) const {
178   const auto& words = GetOperand(index).words;
179   assert(words.size() == 1 && "expected the operand only taking one word");
180   return words.front();
181 }
182 
NumInOperandWords() const183 uint32_t Instruction::NumInOperandWords() const {
184   uint32_t size = 0;
185   for (uint32_t i = TypeResultIdCount(); i < operands_.size(); ++i)
186     size += static_cast<uint32_t>(operands_[i].words.size());
187   return size;
188 }
189 
HasBranchWeights() const190 bool Instruction::HasBranchWeights() const {
191   if (opcode_ == spv::Op::OpBranchConditional &&
192       NumOperands() == kOpBranchConditionalWithWeightsNumOperands) {
193     return true;
194   }
195 
196   return false;
197 }
198 
ToBinaryWithoutAttachedDebugInsts(std::vector<uint32_t> * binary) const199 void Instruction::ToBinaryWithoutAttachedDebugInsts(
200     std::vector<uint32_t>* binary) const {
201   const uint32_t num_words = 1 + NumOperandWords();
202   binary->push_back((num_words << 16) | static_cast<uint16_t>(opcode_));
203   for (const auto& operand : operands_) {
204     binary->insert(binary->end(), operand.words.begin(), operand.words.end());
205   }
206 }
207 
ReplaceOperands(const OperandList & new_operands)208 void Instruction::ReplaceOperands(const OperandList& new_operands) {
209   operands_.clear();
210   operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
211 }
212 
IsReadOnlyLoad() const213 bool Instruction::IsReadOnlyLoad() const {
214   if (IsLoad()) {
215     Instruction* address_def = GetBaseAddress();
216     if (!address_def) {
217       return false;
218     }
219 
220     if (address_def->opcode() == spv::Op::OpVariable) {
221       if (address_def->IsReadOnlyPointer()) {
222         return true;
223       }
224     }
225 
226     if (address_def->opcode() == spv::Op::OpLoad) {
227       const analysis::Type* address_type =
228           context()->get_type_mgr()->GetType(address_def->type_id());
229       if (address_type->AsSampledImage() != nullptr) {
230         const auto* image_type =
231             address_type->AsSampledImage()->image_type()->AsImage();
232         if (image_type->sampled() == 1) {
233           return true;
234         }
235       }
236     }
237   }
238   return false;
239 }
240 
GetBaseAddress() const241 Instruction* Instruction::GetBaseAddress() const {
242   uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
243   Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
244   bool done = false;
245   while (!done) {
246     switch (base_inst->opcode()) {
247       case spv::Op::OpAccessChain:
248       case spv::Op::OpInBoundsAccessChain:
249       case spv::Op::OpPtrAccessChain:
250       case spv::Op::OpInBoundsPtrAccessChain:
251       case spv::Op::OpImageTexelPointer:
252       case spv::Op::OpCopyObject:
253         // All of these instructions have the base pointer use a base pointer
254         // in in-operand 0.
255         base = base_inst->GetSingleWordInOperand(0);
256         base_inst = context()->get_def_use_mgr()->GetDef(base);
257         break;
258       default:
259         done = true;
260         break;
261     }
262   }
263   return base_inst;
264 }
265 
IsReadOnlyPointer() const266 bool Instruction::IsReadOnlyPointer() const {
267   if (context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
268     return IsReadOnlyPointerShaders();
269   else
270     return IsReadOnlyPointerKernel();
271 }
272 
IsVulkanStorageImage() const273 bool Instruction::IsVulkanStorageImage() const {
274   if (opcode() != spv::Op::OpTypePointer) {
275     return false;
276   }
277 
278   spv::StorageClass storage_class =
279       spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
280   if (storage_class != spv::StorageClass::UniformConstant) {
281     return false;
282   }
283 
284   Instruction* base_type =
285       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
286 
287   // Unpack the optional layer of arraying.
288   if (base_type->opcode() == spv::Op::OpTypeArray ||
289       base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
290     base_type = context()->get_def_use_mgr()->GetDef(
291         base_type->GetSingleWordInOperand(0));
292   }
293 
294   if (base_type->opcode() != spv::Op::OpTypeImage) {
295     return false;
296   }
297 
298   if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) ==
299       spv::Dim::Buffer) {
300     return false;
301   }
302 
303   // Check if the image is sampled.  If we do not know for sure that it is,
304   // then assume it is a storage image.
305   return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
306 }
307 
IsVulkanSampledImage() const308 bool Instruction::IsVulkanSampledImage() const {
309   if (opcode() != spv::Op::OpTypePointer) {
310     return false;
311   }
312 
313   spv::StorageClass storage_class =
314       spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
315   if (storage_class != spv::StorageClass::UniformConstant) {
316     return false;
317   }
318 
319   Instruction* base_type =
320       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
321 
322   // Unpack the optional layer of arraying.
323   if (base_type->opcode() == spv::Op::OpTypeArray ||
324       base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
325     base_type = context()->get_def_use_mgr()->GetDef(
326         base_type->GetSingleWordInOperand(0));
327   }
328 
329   if (base_type->opcode() != spv::Op::OpTypeImage) {
330     return false;
331   }
332 
333   if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) ==
334       spv::Dim::Buffer) {
335     return false;
336   }
337 
338   // Check if the image is sampled.  If we know for sure that it is,
339   // then return true.
340   return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) == 1;
341 }
342 
IsVulkanStorageTexelBuffer() const343 bool Instruction::IsVulkanStorageTexelBuffer() const {
344   if (opcode() != spv::Op::OpTypePointer) {
345     return false;
346   }
347 
348   spv::StorageClass storage_class =
349       spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
350   if (storage_class != spv::StorageClass::UniformConstant) {
351     return false;
352   }
353 
354   Instruction* base_type =
355       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
356 
357   // Unpack the optional layer of arraying.
358   if (base_type->opcode() == spv::Op::OpTypeArray ||
359       base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
360     base_type = context()->get_def_use_mgr()->GetDef(
361         base_type->GetSingleWordInOperand(0));
362   }
363 
364   if (base_type->opcode() != spv::Op::OpTypeImage) {
365     return false;
366   }
367 
368   if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) !=
369       spv::Dim::Buffer) {
370     return false;
371   }
372 
373   // Check if the image is sampled.  If we do not know for sure that it is,
374   // then assume it is a storage texel buffer.
375   return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
376 }
377 
IsVulkanStorageBuffer() const378 bool Instruction::IsVulkanStorageBuffer() const {
379   // Is there a difference between a "Storage buffer" and a "dynamic storage
380   // buffer" in SPIR-V and do we care about the difference?
381   if (opcode() != spv::Op::OpTypePointer) {
382     return false;
383   }
384 
385   Instruction* base_type =
386       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
387 
388   // Unpack the optional layer of arraying.
389   if (base_type->opcode() == spv::Op::OpTypeArray ||
390       base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
391     base_type = context()->get_def_use_mgr()->GetDef(
392         base_type->GetSingleWordInOperand(0));
393   }
394 
395   if (base_type->opcode() != spv::Op::OpTypeStruct) {
396     return false;
397   }
398 
399   spv::StorageClass storage_class =
400       spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
401   if (storage_class == spv::StorageClass::Uniform) {
402     bool is_buffer_block = false;
403     context()->get_decoration_mgr()->ForEachDecoration(
404         base_type->result_id(), uint32_t(spv::Decoration::BufferBlock),
405         [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
406     return is_buffer_block;
407   } else if (storage_class == spv::StorageClass::StorageBuffer) {
408     bool is_block = false;
409     context()->get_decoration_mgr()->ForEachDecoration(
410         base_type->result_id(), uint32_t(spv::Decoration::Block),
411         [&is_block](const Instruction&) { is_block = true; });
412     return is_block;
413   }
414   return false;
415 }
416 
IsVulkanStorageBufferVariable() const417 bool Instruction::IsVulkanStorageBufferVariable() const {
418   if (opcode() != spv::Op::OpVariable) {
419     return false;
420   }
421 
422   spv::StorageClass storage_class =
423       spv::StorageClass(GetSingleWordInOperand(kVariableStorageClassIndex));
424   if (storage_class == spv::StorageClass::StorageBuffer ||
425       storage_class == spv::StorageClass::Uniform) {
426     Instruction* var_type = context()->get_def_use_mgr()->GetDef(type_id());
427     return var_type != nullptr && var_type->IsVulkanStorageBuffer();
428   }
429 
430   return false;
431 }
432 
IsVulkanUniformBuffer() const433 bool Instruction::IsVulkanUniformBuffer() const {
434   if (opcode() != spv::Op::OpTypePointer) {
435     return false;
436   }
437 
438   spv::StorageClass storage_class =
439       spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
440   if (storage_class != spv::StorageClass::Uniform) {
441     return false;
442   }
443 
444   Instruction* base_type =
445       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
446 
447   // Unpack the optional layer of arraying.
448   if (base_type->opcode() == spv::Op::OpTypeArray ||
449       base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
450     base_type = context()->get_def_use_mgr()->GetDef(
451         base_type->GetSingleWordInOperand(0));
452   }
453 
454   if (base_type->opcode() != spv::Op::OpTypeStruct) {
455     return false;
456   }
457 
458   bool is_block = false;
459   context()->get_decoration_mgr()->ForEachDecoration(
460       base_type->result_id(), uint32_t(spv::Decoration::Block),
461       [&is_block](const Instruction&) { is_block = true; });
462   return is_block;
463 }
464 
IsReadOnlyPointerShaders() const465 bool Instruction::IsReadOnlyPointerShaders() const {
466   if (type_id() == 0) {
467     return false;
468   }
469 
470   Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
471   if (type_def->opcode() != spv::Op::OpTypePointer) {
472     return false;
473   }
474 
475   spv::StorageClass storage_class = spv::StorageClass(
476       type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex));
477 
478   switch (storage_class) {
479     case spv::StorageClass::UniformConstant:
480       if (!type_def->IsVulkanStorageImage() &&
481           !type_def->IsVulkanStorageTexelBuffer()) {
482         return true;
483       }
484       break;
485     case spv::StorageClass::Uniform:
486       if (!type_def->IsVulkanStorageBuffer()) {
487         return true;
488       }
489       break;
490     case spv::StorageClass::PushConstant:
491     case spv::StorageClass::Input:
492       return true;
493     default:
494       break;
495   }
496 
497   bool is_nonwritable = false;
498   context()->get_decoration_mgr()->ForEachDecoration(
499       result_id(), uint32_t(spv::Decoration::NonWritable),
500       [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
501   return is_nonwritable;
502 }
503 
IsReadOnlyPointerKernel() const504 bool Instruction::IsReadOnlyPointerKernel() const {
505   if (type_id() == 0) {
506     return false;
507   }
508 
509   Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
510   if (type_def->opcode() != spv::Op::OpTypePointer) {
511     return false;
512   }
513 
514   spv::StorageClass storage_class = spv::StorageClass(
515       type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex));
516 
517   return storage_class == spv::StorageClass::UniformConstant;
518 }
519 
UpdateLexicalScope(uint32_t scope)520 void Instruction::UpdateLexicalScope(uint32_t scope) {
521   dbg_scope_.SetLexicalScope(scope);
522   for (auto& i : dbg_line_insts_) {
523     i.dbg_scope_.SetLexicalScope(scope);
524   }
525   if (!IsLineInst() &&
526       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
527     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
528   }
529 }
530 
UpdateDebugInlinedAt(uint32_t new_inlined_at)531 void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) {
532   dbg_scope_.SetInlinedAt(new_inlined_at);
533   for (auto& i : dbg_line_insts_) {
534     i.dbg_scope_.SetInlinedAt(new_inlined_at);
535   }
536   if (!IsLineInst() &&
537       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
538     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
539   }
540 }
541 
ClearDbgLineInsts()542 void Instruction::ClearDbgLineInsts() {
543   if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) {
544     auto def_use_mgr = context()->get_def_use_mgr();
545     for (auto& l_inst : dbg_line_insts_) def_use_mgr->ClearInst(&l_inst);
546   }
547   clear_dbg_line_insts();
548 }
549 
UpdateDebugInfoFrom(const Instruction * from)550 void Instruction::UpdateDebugInfoFrom(const Instruction* from) {
551   if (from == nullptr) return;
552   ClearDbgLineInsts();
553   if (!from->dbg_line_insts().empty())
554     AddDebugLine(&from->dbg_line_insts().back());
555   SetDebugScope(from->GetDebugScope());
556   if (!IsLineInst() &&
557       context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
558     context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
559   }
560 }
561 
AddDebugLine(const Instruction * inst)562 void Instruction::AddDebugLine(const Instruction* inst) {
563   dbg_line_insts_.push_back(*inst);
564   dbg_line_insts_.back().unique_id_ = context()->TakeNextUniqueId();
565   if (inst->IsDebugLineInst())
566     dbg_line_insts_.back().SetResultId(context_->TakeNextId());
567   if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse))
568     context()->get_def_use_mgr()->AnalyzeInstDefUse(&dbg_line_insts_.back());
569 }
570 
IsDebugLineInst() const571 bool Instruction::IsDebugLineInst() const {
572   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
573   return ((ext_opt == NonSemanticShaderDebugInfo100DebugLine) ||
574           (ext_opt == NonSemanticShaderDebugInfo100DebugNoLine));
575 }
576 
IsLineInst() const577 bool Instruction::IsLineInst() const { return IsLine() || IsNoLine(); }
578 
IsLine() const579 bool Instruction::IsLine() const {
580   if (opcode() == spv::Op::OpLine) return true;
581   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
582   return ext_opt == NonSemanticShaderDebugInfo100DebugLine;
583 }
584 
IsNoLine() const585 bool Instruction::IsNoLine() const {
586   if (opcode() == spv::Op::OpNoLine) return true;
587   NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
588   return ext_opt == NonSemanticShaderDebugInfo100DebugNoLine;
589 }
590 
InsertBefore(std::unique_ptr<Instruction> && inst)591 Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& inst) {
592   inst.get()->InsertBefore(this);
593   return inst.release();
594 }
595 
InsertBefore(std::vector<std::unique_ptr<Instruction>> && list)596 Instruction* Instruction::InsertBefore(
597     std::vector<std::unique_ptr<Instruction>>&& list) {
598   Instruction* first_node = list.front().get();
599   for (auto& inst : list) {
600     inst.release()->InsertBefore(this);
601   }
602   list.clear();
603   return first_node;
604 }
605 
IsValidBasePointer() const606 bool Instruction::IsValidBasePointer() const {
607   uint32_t tid = type_id();
608   if (tid == 0) {
609     return false;
610   }
611 
612   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
613   if (type->opcode() != spv::Op::OpTypePointer) {
614     return false;
615   }
616 
617   auto feature_mgr = context()->get_feature_mgr();
618   if (feature_mgr->HasCapability(spv::Capability::Addresses)) {
619     // TODO: The rules here could be more restrictive.
620     return true;
621   }
622 
623   if (opcode() == spv::Op::OpVariable ||
624       opcode() == spv::Op::OpFunctionParameter) {
625     return true;
626   }
627 
628   // With variable pointers, there are more valid base pointer objects.
629   // Variable pointers implicitly declares Variable pointers storage buffer.
630   spv::StorageClass storage_class =
631       static_cast<spv::StorageClass>(type->GetSingleWordInOperand(0));
632   if ((feature_mgr->HasCapability(
633            spv::Capability::VariablePointersStorageBuffer) &&
634        storage_class == spv::StorageClass::StorageBuffer) ||
635       (feature_mgr->HasCapability(spv::Capability::VariablePointers) &&
636        storage_class == spv::StorageClass::Workgroup)) {
637     switch (opcode()) {
638       case spv::Op::OpPhi:
639       case spv::Op::OpSelect:
640       case spv::Op::OpFunctionCall:
641       case spv::Op::OpConstantNull:
642         return true;
643       default:
644         break;
645     }
646   }
647 
648   uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
649   Instruction* pointee_type_inst =
650       context()->get_def_use_mgr()->GetDef(pointee_type_id);
651 
652   if (pointee_type_inst->IsOpaqueType()) {
653     return true;
654   }
655   return false;
656 }
657 
GetOpenCL100DebugOpcode() const658 OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
659   if (opcode() != spv::Op::OpExtInst) {
660     return OpenCLDebugInfo100InstructionsMax;
661   }
662 
663   if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
664     return OpenCLDebugInfo100InstructionsMax;
665   }
666 
667   if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
668       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
669     return OpenCLDebugInfo100InstructionsMax;
670   }
671 
672   return OpenCLDebugInfo100Instructions(
673       GetSingleWordInOperand(kExtInstInstructionInIdx));
674 }
675 
GetShader100DebugOpcode() const676 NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode()
677     const {
678   if (opcode() != spv::Op::OpExtInst) {
679     return NonSemanticShaderDebugInfo100InstructionsMax;
680   }
681 
682   if (!context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
683     return NonSemanticShaderDebugInfo100InstructionsMax;
684   }
685 
686   if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
687       context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
688     return NonSemanticShaderDebugInfo100InstructionsMax;
689   }
690 
691   uint32_t opcode = GetSingleWordInOperand(kExtInstInstructionInIdx);
692   if (opcode >= NonSemanticShaderDebugInfo100InstructionsMax) {
693     return NonSemanticShaderDebugInfo100InstructionsMax;
694   }
695 
696   return NonSemanticShaderDebugInfo100Instructions(opcode);
697 }
698 
GetCommonDebugOpcode() const699 CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const {
700   if (opcode() != spv::Op::OpExtInst) {
701     return CommonDebugInfoInstructionsMax;
702   }
703 
704   const uint32_t opencl_set_id =
705       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
706   const uint32_t shader_set_id =
707       context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo();
708 
709   if (!opencl_set_id && !shader_set_id) {
710     return CommonDebugInfoInstructionsMax;
711   }
712 
713   const uint32_t used_set_id = GetSingleWordInOperand(kExtInstSetIdInIdx);
714 
715   if (used_set_id != opencl_set_id && used_set_id != shader_set_id) {
716     return CommonDebugInfoInstructionsMax;
717   }
718 
719   return CommonDebugInfoInstructions(
720       GetSingleWordInOperand(kExtInstInstructionInIdx));
721 }
722 
IsValidBaseImage() const723 bool Instruction::IsValidBaseImage() const {
724   uint32_t tid = type_id();
725   if (tid == 0) {
726     return false;
727   }
728 
729   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
730   return (type->opcode() == spv::Op::OpTypeImage ||
731           type->opcode() == spv::Op::OpTypeSampledImage);
732 }
733 
IsOpaqueType() const734 bool Instruction::IsOpaqueType() const {
735   if (opcode() == spv::Op::OpTypeStruct) {
736     bool is_opaque = false;
737     ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
738       Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
739       is_opaque |= type_inst->IsOpaqueType();
740     });
741     return is_opaque;
742   } else if (opcode() == spv::Op::OpTypeArray) {
743     uint32_t sub_type_id = GetSingleWordInOperand(0);
744     Instruction* sub_type_inst =
745         context()->get_def_use_mgr()->GetDef(sub_type_id);
746     return sub_type_inst->IsOpaqueType();
747   } else {
748     return opcode() == spv::Op::OpTypeRuntimeArray ||
749            spvOpcodeIsBaseOpaqueType(opcode());
750   }
751 }
752 
IsFoldable() const753 bool Instruction::IsFoldable() const {
754   return IsFoldableByFoldScalar() || IsFoldableByFoldVector() ||
755          context()->get_instruction_folder().HasConstFoldingRule(this);
756 }
757 
IsFoldableByFoldScalar() const758 bool Instruction::IsFoldableByFoldScalar() const {
759   const InstructionFolder& folder = context()->get_instruction_folder();
760   if (!folder.IsFoldableOpcode(opcode())) {
761     return false;
762   }
763 
764   Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
765   if (!folder.IsFoldableScalarType(type)) {
766     return false;
767   }
768 
769   // Even if the type of the instruction is foldable, its operands may not be
770   // foldable (e.g., comparisons of 64bit types).  Check that all operand types
771   // are foldable before accepting the instruction.
772   return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
773     Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
774     Instruction* def_inst_type =
775         context()->get_def_use_mgr()->GetDef(def_inst->type_id());
776     return folder.IsFoldableScalarType(def_inst_type);
777   });
778 }
779 
IsFoldableByFoldVector() const780 bool Instruction::IsFoldableByFoldVector() const {
781   const InstructionFolder& folder = context()->get_instruction_folder();
782   if (!folder.IsFoldableOpcode(opcode())) {
783     return false;
784   }
785 
786   Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
787   if (!folder.IsFoldableVectorType(type)) {
788     return false;
789   }
790 
791   // Even if the type of the instruction is foldable, its operands may not be
792   // foldable (e.g., comparisons of 64bit types).  Check that all operand types
793   // are foldable before accepting the instruction.
794   return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
795     Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
796     Instruction* def_inst_type =
797         context()->get_def_use_mgr()->GetDef(def_inst->type_id());
798     return folder.IsFoldableVectorType(def_inst_type);
799   });
800 }
801 
IsFloatingPointFoldingAllowed() const802 bool Instruction::IsFloatingPointFoldingAllowed() const {
803   // TODO: Add the rules for kernels.  For now it will be pessimistic.
804   // For now, do not support capabilities introduced by SPV_KHR_float_controls.
805   if (!context_->get_feature_mgr()->HasCapability(spv::Capability::Shader) ||
806       context_->get_feature_mgr()->HasCapability(
807           spv::Capability::DenormPreserve) ||
808       context_->get_feature_mgr()->HasCapability(
809           spv::Capability::DenormFlushToZero) ||
810       context_->get_feature_mgr()->HasCapability(
811           spv::Capability::SignedZeroInfNanPreserve) ||
812       context_->get_feature_mgr()->HasCapability(
813           spv::Capability::RoundingModeRTZ) ||
814       context_->get_feature_mgr()->HasCapability(
815           spv::Capability::RoundingModeRTE)) {
816     return false;
817   }
818 
819   bool is_nocontract = false;
820   context_->get_decoration_mgr()->WhileEachDecoration(
821       result_id(), uint32_t(spv::Decoration::NoContraction),
822       [&is_nocontract](const Instruction&) {
823         is_nocontract = true;
824         return false;
825       });
826   return !is_nocontract;
827 }
828 
PrettyPrint(uint32_t options) const829 std::string Instruction::PrettyPrint(uint32_t options) const {
830   // Convert the module to binary.
831   std::vector<uint32_t> module_binary;
832   context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
833 
834   // Convert the instruction to binary. This is used to identify the correct
835   // stream of words to output from the module.
836   std::vector<uint32_t> inst_binary;
837   ToBinaryWithoutAttachedDebugInsts(&inst_binary);
838 
839   // Do not generate a header.
840   return spvInstructionBinaryToText(
841       context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
842       module_binary.data(), module_binary.size(),
843       options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
844 }
845 
operator <<(std::ostream & str,const Instruction & inst)846 std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
847   str << inst.PrettyPrint();
848   return str;
849 }
850 
Dump() const851 void Instruction::Dump() const {
852   std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
853 }
854 
IsOpcodeCodeMotionSafe() const855 bool Instruction::IsOpcodeCodeMotionSafe() const {
856   switch (opcode_) {
857     case spv::Op::OpNop:
858     case spv::Op::OpUndef:
859     case spv::Op::OpLoad:
860     case spv::Op::OpAccessChain:
861     case spv::Op::OpInBoundsAccessChain:
862     case spv::Op::OpArrayLength:
863     case spv::Op::OpVectorExtractDynamic:
864     case spv::Op::OpVectorInsertDynamic:
865     case spv::Op::OpVectorShuffle:
866     case spv::Op::OpCompositeConstruct:
867     case spv::Op::OpCompositeExtract:
868     case spv::Op::OpCompositeInsert:
869     case spv::Op::OpCopyObject:
870     case spv::Op::OpTranspose:
871     case spv::Op::OpConvertFToU:
872     case spv::Op::OpConvertFToS:
873     case spv::Op::OpConvertSToF:
874     case spv::Op::OpConvertUToF:
875     case spv::Op::OpUConvert:
876     case spv::Op::OpSConvert:
877     case spv::Op::OpFConvert:
878     case spv::Op::OpQuantizeToF16:
879     case spv::Op::OpBitcast:
880     case spv::Op::OpSNegate:
881     case spv::Op::OpFNegate:
882     case spv::Op::OpIAdd:
883     case spv::Op::OpFAdd:
884     case spv::Op::OpISub:
885     case spv::Op::OpFSub:
886     case spv::Op::OpIMul:
887     case spv::Op::OpFMul:
888     case spv::Op::OpUDiv:
889     case spv::Op::OpSDiv:
890     case spv::Op::OpFDiv:
891     case spv::Op::OpUMod:
892     case spv::Op::OpSRem:
893     case spv::Op::OpSMod:
894     case spv::Op::OpFRem:
895     case spv::Op::OpFMod:
896     case spv::Op::OpVectorTimesScalar:
897     case spv::Op::OpMatrixTimesScalar:
898     case spv::Op::OpVectorTimesMatrix:
899     case spv::Op::OpMatrixTimesVector:
900     case spv::Op::OpMatrixTimesMatrix:
901     case spv::Op::OpOuterProduct:
902     case spv::Op::OpDot:
903     case spv::Op::OpIAddCarry:
904     case spv::Op::OpISubBorrow:
905     case spv::Op::OpUMulExtended:
906     case spv::Op::OpSMulExtended:
907     case spv::Op::OpAny:
908     case spv::Op::OpAll:
909     case spv::Op::OpIsNan:
910     case spv::Op::OpIsInf:
911     case spv::Op::OpLogicalEqual:
912     case spv::Op::OpLogicalNotEqual:
913     case spv::Op::OpLogicalOr:
914     case spv::Op::OpLogicalAnd:
915     case spv::Op::OpLogicalNot:
916     case spv::Op::OpSelect:
917     case spv::Op::OpIEqual:
918     case spv::Op::OpINotEqual:
919     case spv::Op::OpUGreaterThan:
920     case spv::Op::OpSGreaterThan:
921     case spv::Op::OpUGreaterThanEqual:
922     case spv::Op::OpSGreaterThanEqual:
923     case spv::Op::OpULessThan:
924     case spv::Op::OpSLessThan:
925     case spv::Op::OpULessThanEqual:
926     case spv::Op::OpSLessThanEqual:
927     case spv::Op::OpFOrdEqual:
928     case spv::Op::OpFUnordEqual:
929     case spv::Op::OpFOrdNotEqual:
930     case spv::Op::OpFUnordNotEqual:
931     case spv::Op::OpFOrdLessThan:
932     case spv::Op::OpFUnordLessThan:
933     case spv::Op::OpFOrdGreaterThan:
934     case spv::Op::OpFUnordGreaterThan:
935     case spv::Op::OpFOrdLessThanEqual:
936     case spv::Op::OpFUnordLessThanEqual:
937     case spv::Op::OpFOrdGreaterThanEqual:
938     case spv::Op::OpFUnordGreaterThanEqual:
939     case spv::Op::OpShiftRightLogical:
940     case spv::Op::OpShiftRightArithmetic:
941     case spv::Op::OpShiftLeftLogical:
942     case spv::Op::OpBitwiseOr:
943     case spv::Op::OpBitwiseXor:
944     case spv::Op::OpBitwiseAnd:
945     case spv::Op::OpNot:
946     case spv::Op::OpBitFieldInsert:
947     case spv::Op::OpBitFieldSExtract:
948     case spv::Op::OpBitFieldUExtract:
949     case spv::Op::OpBitReverse:
950     case spv::Op::OpBitCount:
951     case spv::Op::OpSizeOf:
952       return true;
953     default:
954       return false;
955   }
956 }
957 
IsScalarizable() const958 bool Instruction::IsScalarizable() const {
959   if (spvOpcodeIsScalarizable(opcode())) {
960     return true;
961   }
962 
963   if (opcode() == spv::Op::OpExtInst) {
964     uint32_t instSetId =
965         context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
966 
967     if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
968       switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
969         case GLSLstd450Round:
970         case GLSLstd450RoundEven:
971         case GLSLstd450Trunc:
972         case GLSLstd450FAbs:
973         case GLSLstd450SAbs:
974         case GLSLstd450FSign:
975         case GLSLstd450SSign:
976         case GLSLstd450Floor:
977         case GLSLstd450Ceil:
978         case GLSLstd450Fract:
979         case GLSLstd450Radians:
980         case GLSLstd450Degrees:
981         case GLSLstd450Sin:
982         case GLSLstd450Cos:
983         case GLSLstd450Tan:
984         case GLSLstd450Asin:
985         case GLSLstd450Acos:
986         case GLSLstd450Atan:
987         case GLSLstd450Sinh:
988         case GLSLstd450Cosh:
989         case GLSLstd450Tanh:
990         case GLSLstd450Asinh:
991         case GLSLstd450Acosh:
992         case GLSLstd450Atanh:
993         case GLSLstd450Atan2:
994         case GLSLstd450Pow:
995         case GLSLstd450Exp:
996         case GLSLstd450Log:
997         case GLSLstd450Exp2:
998         case GLSLstd450Log2:
999         case GLSLstd450Sqrt:
1000         case GLSLstd450InverseSqrt:
1001         case GLSLstd450Modf:
1002         case GLSLstd450FMin:
1003         case GLSLstd450UMin:
1004         case GLSLstd450SMin:
1005         case GLSLstd450FMax:
1006         case GLSLstd450UMax:
1007         case GLSLstd450SMax:
1008         case GLSLstd450FClamp:
1009         case GLSLstd450UClamp:
1010         case GLSLstd450SClamp:
1011         case GLSLstd450FMix:
1012         case GLSLstd450Step:
1013         case GLSLstd450SmoothStep:
1014         case GLSLstd450Fma:
1015         case GLSLstd450Frexp:
1016         case GLSLstd450Ldexp:
1017         case GLSLstd450FindILsb:
1018         case GLSLstd450FindSMsb:
1019         case GLSLstd450FindUMsb:
1020         case GLSLstd450NMin:
1021         case GLSLstd450NMax:
1022         case GLSLstd450NClamp:
1023           return true;
1024         default:
1025           return false;
1026       }
1027     }
1028   }
1029   return false;
1030 }
1031 
IsOpcodeSafeToDelete() const1032 bool Instruction::IsOpcodeSafeToDelete() const {
1033   if (context()->IsCombinatorInstruction(this)) {
1034     return true;
1035   }
1036 
1037   switch (opcode()) {
1038     case spv::Op::OpDPdx:
1039     case spv::Op::OpDPdy:
1040     case spv::Op::OpFwidth:
1041     case spv::Op::OpDPdxFine:
1042     case spv::Op::OpDPdyFine:
1043     case spv::Op::OpFwidthFine:
1044     case spv::Op::OpDPdxCoarse:
1045     case spv::Op::OpDPdyCoarse:
1046     case spv::Op::OpFwidthCoarse:
1047     case spv::Op::OpImageQueryLod:
1048       return true;
1049     default:
1050       return false;
1051   }
1052 }
1053 
IsNonSemanticInstruction() const1054 bool Instruction::IsNonSemanticInstruction() const {
1055   if (!HasResultId()) return false;
1056   if (opcode() != spv::Op::OpExtInst) return false;
1057 
1058   auto import_inst =
1059       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(0));
1060   std::string import_name = import_inst->GetInOperand(0).AsString();
1061   return import_name.find("NonSemantic.") == 0;
1062 }
1063 
ToBinary(uint32_t type_id,uint32_t result_id,uint32_t ext_set,std::vector<uint32_t> * binary) const1064 void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
1065                           uint32_t ext_set,
1066                           std::vector<uint32_t>* binary) const {
1067   uint32_t num_words = kDebugScopeNumWords;
1068   CommonDebugInfoInstructions dbg_opcode = CommonDebugInfoDebugScope;
1069   if (GetLexicalScope() == kNoDebugScope) {
1070     num_words = kDebugNoScopeNumWords;
1071     dbg_opcode = CommonDebugInfoDebugNoScope;
1072   } else if (GetInlinedAt() == kNoInlinedAt) {
1073     num_words = kDebugScopeNumWordsWithoutInlinedAt;
1074   }
1075   std::vector<uint32_t> operands = {
1076       (num_words << 16) | static_cast<uint16_t>(spv::Op::OpExtInst),
1077       type_id,
1078       result_id,
1079       ext_set,
1080       static_cast<uint32_t>(dbg_opcode),
1081   };
1082   binary->insert(binary->end(), operands.begin(), operands.end());
1083   if (GetLexicalScope() != kNoDebugScope) {
1084     binary->push_back(GetLexicalScope());
1085     if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
1086   }
1087 }
1088 
1089 }  // namespace opt
1090 }  // namespace spvtools
1091