• 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 kVariableStorageClassIndex = 0;
33 const uint32_t kTypeImageSampledIndex = 5;
34 
35 // Constants for OpenCL.DebugInfo.100 extension instructions.
36 const uint32_t kDebugScopeNumWords = 7;
37 const uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
38 const uint32_t kDebugNoScopeNumWords = 5;
39 }  // namespace
40 
Instruction(IRContext * c)41 Instruction::Instruction(IRContext* c)
42     : utils::IntrusiveNodeBase<Instruction>(),
43       context_(c),
44       opcode_(SpvOpNop),
45       has_type_id_(false),
46       has_result_id_(false),
47       unique_id_(c->TakeNextUniqueId()),
48       dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
49 
Instruction(IRContext * c,SpvOp op)50 Instruction::Instruction(IRContext* c, SpvOp op)
51     : utils::IntrusiveNodeBase<Instruction>(),
52       context_(c),
53       opcode_(op),
54       has_type_id_(false),
55       has_result_id_(false),
56       unique_id_(c->TakeNextUniqueId()),
57       dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
58 
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,std::vector<Instruction> && dbg_line)59 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
60                          std::vector<Instruction>&& dbg_line)
61     : context_(c),
62       opcode_(static_cast<SpvOp>(inst.opcode)),
63       has_type_id_(inst.type_id != 0),
64       has_result_id_(inst.result_id != 0),
65       unique_id_(c->TakeNextUniqueId()),
66       dbg_line_insts_(std::move(dbg_line)),
67       dbg_scope_(kNoDebugScope, kNoInlinedAt) {
68   assert((!IsDebugLineInst(opcode_) || dbg_line.empty()) &&
69          "Op(No)Line attaching to Op(No)Line found");
70   for (uint32_t i = 0; i < inst.num_operands; ++i) {
71     const auto& current_payload = inst.operands[i];
72     std::vector<uint32_t> words(
73         inst.words + current_payload.offset,
74         inst.words + current_payload.offset + current_payload.num_words);
75     operands_.emplace_back(current_payload.type, std::move(words));
76   }
77 }
78 
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,const DebugScope & dbg_scope)79 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
80                          const DebugScope& dbg_scope)
81     : context_(c),
82       opcode_(static_cast<SpvOp>(inst.opcode)),
83       has_type_id_(inst.type_id != 0),
84       has_result_id_(inst.result_id != 0),
85       unique_id_(c->TakeNextUniqueId()),
86       dbg_scope_(dbg_scope) {
87   for (uint32_t i = 0; i < inst.num_operands; ++i) {
88     const auto& current_payload = inst.operands[i];
89     std::vector<uint32_t> words(
90         inst.words + current_payload.offset,
91         inst.words + current_payload.offset + current_payload.num_words);
92     operands_.emplace_back(current_payload.type, std::move(words));
93   }
94 }
95 
Instruction(IRContext * c,SpvOp op,uint32_t ty_id,uint32_t res_id,const OperandList & in_operands)96 Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id,
97                          uint32_t res_id, const OperandList& in_operands)
98     : utils::IntrusiveNodeBase<Instruction>(),
99       context_(c),
100       opcode_(op),
101       has_type_id_(ty_id != 0),
102       has_result_id_(res_id != 0),
103       unique_id_(c->TakeNextUniqueId()),
104       operands_(),
105       dbg_scope_(kNoDebugScope, kNoInlinedAt) {
106   if (has_type_id_) {
107     operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
108                            std::initializer_list<uint32_t>{ty_id});
109   }
110   if (has_result_id_) {
111     operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
112                            std::initializer_list<uint32_t>{res_id});
113   }
114   operands_.insert(operands_.end(), in_operands.begin(), in_operands.end());
115 }
116 
Instruction(Instruction && that)117 Instruction::Instruction(Instruction&& that)
118     : utils::IntrusiveNodeBase<Instruction>(),
119       opcode_(that.opcode_),
120       has_type_id_(that.has_type_id_),
121       has_result_id_(that.has_result_id_),
122       unique_id_(that.unique_id_),
123       operands_(std::move(that.operands_)),
124       dbg_line_insts_(std::move(that.dbg_line_insts_)),
125       dbg_scope_(that.dbg_scope_) {
126   for (auto& i : dbg_line_insts_) {
127     i.dbg_scope_ = that.dbg_scope_;
128   }
129 }
130 
operator =(Instruction && that)131 Instruction& Instruction::operator=(Instruction&& that) {
132   opcode_ = that.opcode_;
133   has_type_id_ = that.has_type_id_;
134   has_result_id_ = that.has_result_id_;
135   unique_id_ = that.unique_id_;
136   operands_ = std::move(that.operands_);
137   dbg_line_insts_ = std::move(that.dbg_line_insts_);
138   dbg_scope_ = that.dbg_scope_;
139   return *this;
140 }
141 
Clone(IRContext * c) const142 Instruction* Instruction::Clone(IRContext* c) const {
143   Instruction* clone = new Instruction(c);
144   clone->opcode_ = opcode_;
145   clone->has_type_id_ = has_type_id_;
146   clone->has_result_id_ = has_result_id_;
147   clone->unique_id_ = c->TakeNextUniqueId();
148   clone->operands_ = operands_;
149   clone->dbg_line_insts_ = dbg_line_insts_;
150   clone->dbg_scope_ = dbg_scope_;
151   return clone;
152 }
153 
GetSingleWordOperand(uint32_t index) const154 uint32_t Instruction::GetSingleWordOperand(uint32_t index) const {
155   const auto& words = GetOperand(index).words;
156   assert(words.size() == 1 && "expected the operand only taking one word");
157   return words.front();
158 }
159 
NumInOperandWords() const160 uint32_t Instruction::NumInOperandWords() const {
161   uint32_t size = 0;
162   for (uint32_t i = TypeResultIdCount(); i < operands_.size(); ++i)
163     size += static_cast<uint32_t>(operands_[i].words.size());
164   return size;
165 }
166 
ToBinaryWithoutAttachedDebugInsts(std::vector<uint32_t> * binary) const167 void Instruction::ToBinaryWithoutAttachedDebugInsts(
168     std::vector<uint32_t>* binary) const {
169   const uint32_t num_words = 1 + NumOperandWords();
170   binary->push_back((num_words << 16) | static_cast<uint16_t>(opcode_));
171   for (const auto& operand : operands_)
172     binary->insert(binary->end(), operand.words.begin(), operand.words.end());
173 }
174 
ReplaceOperands(const OperandList & new_operands)175 void Instruction::ReplaceOperands(const OperandList& new_operands) {
176   operands_.clear();
177   operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
178 }
179 
IsReadOnlyLoad() const180 bool Instruction::IsReadOnlyLoad() const {
181   if (IsLoad()) {
182     Instruction* address_def = GetBaseAddress();
183     if (!address_def || address_def->opcode() != SpvOpVariable) {
184       return false;
185     }
186     return address_def->IsReadOnlyVariable();
187   }
188   return false;
189 }
190 
GetBaseAddress() const191 Instruction* Instruction::GetBaseAddress() const {
192   uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
193   Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
194   bool done = false;
195   while (!done) {
196     switch (base_inst->opcode()) {
197       case SpvOpAccessChain:
198       case SpvOpInBoundsAccessChain:
199       case SpvOpPtrAccessChain:
200       case SpvOpInBoundsPtrAccessChain:
201       case SpvOpImageTexelPointer:
202       case SpvOpCopyObject:
203         // All of these instructions have the base pointer use a base pointer
204         // in in-operand 0.
205         base = base_inst->GetSingleWordInOperand(0);
206         base_inst = context()->get_def_use_mgr()->GetDef(base);
207         break;
208       default:
209         done = true;
210         break;
211     }
212   }
213   return base_inst;
214 }
215 
IsReadOnlyVariable() const216 bool Instruction::IsReadOnlyVariable() const {
217   if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
218     return IsReadOnlyVariableShaders();
219   else
220     return IsReadOnlyVariableKernel();
221 }
222 
IsVulkanStorageImage() const223 bool Instruction::IsVulkanStorageImage() const {
224   if (opcode() != SpvOpTypePointer) {
225     return false;
226   }
227 
228   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
229   if (storage_class != SpvStorageClassUniformConstant) {
230     return false;
231   }
232 
233   Instruction* base_type =
234       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
235 
236   // Unpack the optional layer of arraying.
237   if (base_type->opcode() == SpvOpTypeArray ||
238       base_type->opcode() == SpvOpTypeRuntimeArray) {
239     base_type = context()->get_def_use_mgr()->GetDef(
240         base_type->GetSingleWordInOperand(0));
241   }
242 
243   if (base_type->opcode() != SpvOpTypeImage) {
244     return false;
245   }
246 
247   if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
248     return false;
249   }
250 
251   // Check if the image is sampled.  If we do not know for sure that it is,
252   // then assume it is a storage image.
253   auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
254   return s != 1;
255 }
256 
IsVulkanSampledImage() const257 bool Instruction::IsVulkanSampledImage() const {
258   if (opcode() != SpvOpTypePointer) {
259     return false;
260   }
261 
262   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
263   if (storage_class != SpvStorageClassUniformConstant) {
264     return false;
265   }
266 
267   Instruction* base_type =
268       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
269 
270   // Unpack the optional layer of arraying.
271   if (base_type->opcode() == SpvOpTypeArray ||
272       base_type->opcode() == SpvOpTypeRuntimeArray) {
273     base_type = context()->get_def_use_mgr()->GetDef(
274         base_type->GetSingleWordInOperand(0));
275   }
276 
277   if (base_type->opcode() != SpvOpTypeImage) {
278     return false;
279   }
280 
281   if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
282     return false;
283   }
284 
285   // Check if the image is sampled.  If we know for sure that it is,
286   // then return true.
287   auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
288   return s == 1;
289 }
290 
IsVulkanStorageTexelBuffer() const291 bool Instruction::IsVulkanStorageTexelBuffer() const {
292   if (opcode() != SpvOpTypePointer) {
293     return false;
294   }
295 
296   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
297   if (storage_class != SpvStorageClassUniformConstant) {
298     return false;
299   }
300 
301   Instruction* base_type =
302       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
303 
304   // Unpack the optional layer of arraying.
305   if (base_type->opcode() == SpvOpTypeArray ||
306       base_type->opcode() == SpvOpTypeRuntimeArray) {
307     base_type = context()->get_def_use_mgr()->GetDef(
308         base_type->GetSingleWordInOperand(0));
309   }
310 
311   if (base_type->opcode() != SpvOpTypeImage) {
312     return false;
313   }
314 
315   if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
316     return false;
317   }
318 
319   // Check if the image is sampled.  If we do not know for sure that it is,
320   // then assume it is a storage texel buffer.
321   return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
322 }
323 
IsVulkanStorageBuffer() const324 bool Instruction::IsVulkanStorageBuffer() const {
325   // Is there a difference between a "Storage buffer" and a "dynamic storage
326   // buffer" in SPIR-V and do we care about the difference?
327   if (opcode() != SpvOpTypePointer) {
328     return false;
329   }
330 
331   Instruction* base_type =
332       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
333 
334   // Unpack the optional layer of arraying.
335   if (base_type->opcode() == SpvOpTypeArray ||
336       base_type->opcode() == SpvOpTypeRuntimeArray) {
337     base_type = context()->get_def_use_mgr()->GetDef(
338         base_type->GetSingleWordInOperand(0));
339   }
340 
341   if (base_type->opcode() != SpvOpTypeStruct) {
342     return false;
343   }
344 
345   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
346   if (storage_class == SpvStorageClassUniform) {
347     bool is_buffer_block = false;
348     context()->get_decoration_mgr()->ForEachDecoration(
349         base_type->result_id(), SpvDecorationBufferBlock,
350         [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
351     return is_buffer_block;
352   } else if (storage_class == SpvStorageClassStorageBuffer) {
353     bool is_block = false;
354     context()->get_decoration_mgr()->ForEachDecoration(
355         base_type->result_id(), SpvDecorationBlock,
356         [&is_block](const Instruction&) { is_block = true; });
357     return is_block;
358   }
359   return false;
360 }
361 
IsVulkanUniformBuffer() const362 bool Instruction::IsVulkanUniformBuffer() const {
363   if (opcode() != SpvOpTypePointer) {
364     return false;
365   }
366 
367   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
368   if (storage_class != SpvStorageClassUniform) {
369     return false;
370   }
371 
372   Instruction* base_type =
373       context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
374 
375   // Unpack the optional layer of arraying.
376   if (base_type->opcode() == SpvOpTypeArray ||
377       base_type->opcode() == SpvOpTypeRuntimeArray) {
378     base_type = context()->get_def_use_mgr()->GetDef(
379         base_type->GetSingleWordInOperand(0));
380   }
381 
382   if (base_type->opcode() != SpvOpTypeStruct) {
383     return false;
384   }
385 
386   bool is_block = false;
387   context()->get_decoration_mgr()->ForEachDecoration(
388       base_type->result_id(), SpvDecorationBlock,
389       [&is_block](const Instruction&) { is_block = true; });
390   return is_block;
391 }
392 
IsReadOnlyVariableShaders() const393 bool Instruction::IsReadOnlyVariableShaders() const {
394   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
395   Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
396 
397   switch (storage_class) {
398     case SpvStorageClassUniformConstant:
399       if (!type_def->IsVulkanStorageImage() &&
400           !type_def->IsVulkanStorageTexelBuffer()) {
401         return true;
402       }
403       break;
404     case SpvStorageClassUniform:
405       if (!type_def->IsVulkanStorageBuffer()) {
406         return true;
407       }
408       break;
409     case SpvStorageClassPushConstant:
410     case SpvStorageClassInput:
411       return true;
412     default:
413       break;
414   }
415 
416   bool is_nonwritable = false;
417   context()->get_decoration_mgr()->ForEachDecoration(
418       result_id(), SpvDecorationNonWritable,
419       [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
420   return is_nonwritable;
421 }
422 
IsReadOnlyVariableKernel() const423 bool Instruction::IsReadOnlyVariableKernel() const {
424   uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
425   return storage_class == SpvStorageClassUniformConstant;
426 }
427 
GetTypeComponent(uint32_t element) const428 uint32_t Instruction::GetTypeComponent(uint32_t element) const {
429   uint32_t subtype = 0;
430   switch (opcode()) {
431     case SpvOpTypeStruct:
432       subtype = GetSingleWordInOperand(element);
433       break;
434     case SpvOpTypeArray:
435     case SpvOpTypeRuntimeArray:
436     case SpvOpTypeVector:
437     case SpvOpTypeMatrix:
438       // These types all have uniform subtypes.
439       subtype = GetSingleWordInOperand(0u);
440       break;
441     default:
442       break;
443   }
444 
445   return subtype;
446 }
447 
InsertBefore(std::unique_ptr<Instruction> && i)448 Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& i) {
449   i.get()->InsertBefore(this);
450   return i.release();
451 }
452 
InsertBefore(std::vector<std::unique_ptr<Instruction>> && list)453 Instruction* Instruction::InsertBefore(
454     std::vector<std::unique_ptr<Instruction>>&& list) {
455   Instruction* first_node = list.front().get();
456   for (auto& i : list) {
457     i.release()->InsertBefore(this);
458   }
459   list.clear();
460   return first_node;
461 }
462 
IsValidBasePointer() const463 bool Instruction::IsValidBasePointer() const {
464   uint32_t tid = type_id();
465   if (tid == 0) {
466     return false;
467   }
468 
469   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
470   if (type->opcode() != SpvOpTypePointer) {
471     return false;
472   }
473 
474   auto feature_mgr = context()->get_feature_mgr();
475   if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
476     // TODO: The rules here could be more restrictive.
477     return true;
478   }
479 
480   if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
481     return true;
482   }
483 
484   // With variable pointers, there are more valid base pointer objects.
485   // Variable pointers implicitly declares Variable pointers storage buffer.
486   SpvStorageClass storage_class =
487       static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
488   if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
489        storage_class == SpvStorageClassStorageBuffer) ||
490       (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
491        storage_class == SpvStorageClassWorkgroup)) {
492     switch (opcode()) {
493       case SpvOpPhi:
494       case SpvOpSelect:
495       case SpvOpFunctionCall:
496       case SpvOpConstantNull:
497         return true;
498       default:
499         break;
500     }
501   }
502 
503   uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
504   Instruction* pointee_type_inst =
505       context()->get_def_use_mgr()->GetDef(pointee_type_id);
506 
507   if (pointee_type_inst->IsOpaqueType()) {
508     return true;
509   }
510   return false;
511 }
512 
IsValidBaseImage() const513 bool Instruction::IsValidBaseImage() const {
514   uint32_t tid = type_id();
515   if (tid == 0) {
516     return false;
517   }
518 
519   Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
520   return (type->opcode() == SpvOpTypeImage ||
521           type->opcode() == SpvOpTypeSampledImage);
522 }
523 
IsOpaqueType() const524 bool Instruction::IsOpaqueType() const {
525   if (opcode() == SpvOpTypeStruct) {
526     bool is_opaque = false;
527     ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
528       Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
529       is_opaque |= type_inst->IsOpaqueType();
530     });
531     return is_opaque;
532   } else if (opcode() == SpvOpTypeArray) {
533     uint32_t sub_type_id = GetSingleWordInOperand(0);
534     Instruction* sub_type_inst =
535         context()->get_def_use_mgr()->GetDef(sub_type_id);
536     return sub_type_inst->IsOpaqueType();
537   } else {
538     return opcode() == SpvOpTypeRuntimeArray ||
539            spvOpcodeIsBaseOpaqueType(opcode());
540   }
541 }
542 
IsFoldable() const543 bool Instruction::IsFoldable() const {
544   return IsFoldableByFoldScalar() ||
545          context()->get_instruction_folder().HasConstFoldingRule(this);
546 }
547 
IsFoldableByFoldScalar() const548 bool Instruction::IsFoldableByFoldScalar() const {
549   const InstructionFolder& folder = context()->get_instruction_folder();
550   if (!folder.IsFoldableOpcode(opcode())) {
551     return false;
552   }
553   Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
554   return folder.IsFoldableType(type);
555 }
556 
IsFloatingPointFoldingAllowed() const557 bool Instruction::IsFloatingPointFoldingAllowed() const {
558   // TODO: Add the rules for kernels.  For now it will be pessimistic.
559   // For now, do not support capabilities introduced by SPV_KHR_float_controls.
560   if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
561       context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
562       context_->get_feature_mgr()->HasCapability(
563           SpvCapabilityDenormFlushToZero) ||
564       context_->get_feature_mgr()->HasCapability(
565           SpvCapabilitySignedZeroInfNanPreserve) ||
566       context_->get_feature_mgr()->HasCapability(
567           SpvCapabilityRoundingModeRTZ) ||
568       context_->get_feature_mgr()->HasCapability(
569           SpvCapabilityRoundingModeRTE)) {
570     return false;
571   }
572 
573   bool is_nocontract = false;
574   context_->get_decoration_mgr()->WhileEachDecoration(
575       result_id(), SpvDecorationNoContraction,
576       [&is_nocontract](const Instruction&) {
577         is_nocontract = true;
578         return false;
579       });
580   return !is_nocontract;
581 }
582 
PrettyPrint(uint32_t options) const583 std::string Instruction::PrettyPrint(uint32_t options) const {
584   // Convert the module to binary.
585   std::vector<uint32_t> module_binary;
586   context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
587 
588   // Convert the instruction to binary. This is used to identify the correct
589   // stream of words to output from the module.
590   std::vector<uint32_t> inst_binary;
591   ToBinaryWithoutAttachedDebugInsts(&inst_binary);
592 
593   // Do not generate a header.
594   return spvInstructionBinaryToText(
595       context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
596       module_binary.data(), module_binary.size(),
597       options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
598 }
599 
operator <<(std::ostream & str,const Instruction & inst)600 std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
601   str << inst.PrettyPrint();
602   return str;
603 }
604 
Dump() const605 void Instruction::Dump() const {
606   std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
607 }
608 
IsOpcodeCodeMotionSafe() const609 bool Instruction::IsOpcodeCodeMotionSafe() const {
610   switch (opcode_) {
611     case SpvOpNop:
612     case SpvOpUndef:
613     case SpvOpLoad:
614     case SpvOpAccessChain:
615     case SpvOpInBoundsAccessChain:
616     case SpvOpArrayLength:
617     case SpvOpVectorExtractDynamic:
618     case SpvOpVectorInsertDynamic:
619     case SpvOpVectorShuffle:
620     case SpvOpCompositeConstruct:
621     case SpvOpCompositeExtract:
622     case SpvOpCompositeInsert:
623     case SpvOpCopyObject:
624     case SpvOpTranspose:
625     case SpvOpConvertFToU:
626     case SpvOpConvertFToS:
627     case SpvOpConvertSToF:
628     case SpvOpConvertUToF:
629     case SpvOpUConvert:
630     case SpvOpSConvert:
631     case SpvOpFConvert:
632     case SpvOpQuantizeToF16:
633     case SpvOpBitcast:
634     case SpvOpSNegate:
635     case SpvOpFNegate:
636     case SpvOpIAdd:
637     case SpvOpFAdd:
638     case SpvOpISub:
639     case SpvOpFSub:
640     case SpvOpIMul:
641     case SpvOpFMul:
642     case SpvOpUDiv:
643     case SpvOpSDiv:
644     case SpvOpFDiv:
645     case SpvOpUMod:
646     case SpvOpSRem:
647     case SpvOpSMod:
648     case SpvOpFRem:
649     case SpvOpFMod:
650     case SpvOpVectorTimesScalar:
651     case SpvOpMatrixTimesScalar:
652     case SpvOpVectorTimesMatrix:
653     case SpvOpMatrixTimesVector:
654     case SpvOpMatrixTimesMatrix:
655     case SpvOpOuterProduct:
656     case SpvOpDot:
657     case SpvOpIAddCarry:
658     case SpvOpISubBorrow:
659     case SpvOpUMulExtended:
660     case SpvOpSMulExtended:
661     case SpvOpAny:
662     case SpvOpAll:
663     case SpvOpIsNan:
664     case SpvOpIsInf:
665     case SpvOpLogicalEqual:
666     case SpvOpLogicalNotEqual:
667     case SpvOpLogicalOr:
668     case SpvOpLogicalAnd:
669     case SpvOpLogicalNot:
670     case SpvOpSelect:
671     case SpvOpIEqual:
672     case SpvOpINotEqual:
673     case SpvOpUGreaterThan:
674     case SpvOpSGreaterThan:
675     case SpvOpUGreaterThanEqual:
676     case SpvOpSGreaterThanEqual:
677     case SpvOpULessThan:
678     case SpvOpSLessThan:
679     case SpvOpULessThanEqual:
680     case SpvOpSLessThanEqual:
681     case SpvOpFOrdEqual:
682     case SpvOpFUnordEqual:
683     case SpvOpFOrdNotEqual:
684     case SpvOpFUnordNotEqual:
685     case SpvOpFOrdLessThan:
686     case SpvOpFUnordLessThan:
687     case SpvOpFOrdGreaterThan:
688     case SpvOpFUnordGreaterThan:
689     case SpvOpFOrdLessThanEqual:
690     case SpvOpFUnordLessThanEqual:
691     case SpvOpFOrdGreaterThanEqual:
692     case SpvOpFUnordGreaterThanEqual:
693     case SpvOpShiftRightLogical:
694     case SpvOpShiftRightArithmetic:
695     case SpvOpShiftLeftLogical:
696     case SpvOpBitwiseOr:
697     case SpvOpBitwiseXor:
698     case SpvOpBitwiseAnd:
699     case SpvOpNot:
700     case SpvOpBitFieldInsert:
701     case SpvOpBitFieldSExtract:
702     case SpvOpBitFieldUExtract:
703     case SpvOpBitReverse:
704     case SpvOpBitCount:
705     case SpvOpSizeOf:
706       return true;
707     default:
708       return false;
709   }
710 }
711 
IsScalarizable() const712 bool Instruction::IsScalarizable() const {
713   if (spvOpcodeIsScalarizable(opcode())) {
714     return true;
715   }
716 
717   const uint32_t kExtInstSetIdInIdx = 0;
718   const uint32_t kExtInstInstructionInIdx = 1;
719 
720   if (opcode() == SpvOpExtInst) {
721     uint32_t instSetId =
722         context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
723 
724     if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
725       switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
726         case GLSLstd450Round:
727         case GLSLstd450RoundEven:
728         case GLSLstd450Trunc:
729         case GLSLstd450FAbs:
730         case GLSLstd450SAbs:
731         case GLSLstd450FSign:
732         case GLSLstd450SSign:
733         case GLSLstd450Floor:
734         case GLSLstd450Ceil:
735         case GLSLstd450Fract:
736         case GLSLstd450Radians:
737         case GLSLstd450Degrees:
738         case GLSLstd450Sin:
739         case GLSLstd450Cos:
740         case GLSLstd450Tan:
741         case GLSLstd450Asin:
742         case GLSLstd450Acos:
743         case GLSLstd450Atan:
744         case GLSLstd450Sinh:
745         case GLSLstd450Cosh:
746         case GLSLstd450Tanh:
747         case GLSLstd450Asinh:
748         case GLSLstd450Acosh:
749         case GLSLstd450Atanh:
750         case GLSLstd450Atan2:
751         case GLSLstd450Pow:
752         case GLSLstd450Exp:
753         case GLSLstd450Log:
754         case GLSLstd450Exp2:
755         case GLSLstd450Log2:
756         case GLSLstd450Sqrt:
757         case GLSLstd450InverseSqrt:
758         case GLSLstd450Modf:
759         case GLSLstd450FMin:
760         case GLSLstd450UMin:
761         case GLSLstd450SMin:
762         case GLSLstd450FMax:
763         case GLSLstd450UMax:
764         case GLSLstd450SMax:
765         case GLSLstd450FClamp:
766         case GLSLstd450UClamp:
767         case GLSLstd450SClamp:
768         case GLSLstd450FMix:
769         case GLSLstd450Step:
770         case GLSLstd450SmoothStep:
771         case GLSLstd450Fma:
772         case GLSLstd450Frexp:
773         case GLSLstd450Ldexp:
774         case GLSLstd450FindILsb:
775         case GLSLstd450FindSMsb:
776         case GLSLstd450FindUMsb:
777         case GLSLstd450NMin:
778         case GLSLstd450NMax:
779         case GLSLstd450NClamp:
780           return true;
781         default:
782           return false;
783       }
784     }
785   }
786   return false;
787 }
788 
IsOpcodeSafeToDelete() const789 bool Instruction::IsOpcodeSafeToDelete() const {
790   if (context()->IsCombinatorInstruction(this)) {
791     return true;
792   }
793 
794   switch (opcode()) {
795     case SpvOpDPdx:
796     case SpvOpDPdy:
797     case SpvOpFwidth:
798     case SpvOpDPdxFine:
799     case SpvOpDPdyFine:
800     case SpvOpFwidthFine:
801     case SpvOpDPdxCoarse:
802     case SpvOpDPdyCoarse:
803     case SpvOpFwidthCoarse:
804     case SpvOpImageQueryLod:
805       return true;
806     default:
807       return false;
808   }
809 }
810 
ToBinary(uint32_t type_id,uint32_t result_id,uint32_t ext_set,std::vector<uint32_t> * binary) const811 void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
812                           uint32_t ext_set,
813                           std::vector<uint32_t>* binary) const {
814   uint32_t num_words = kDebugScopeNumWords;
815   OpenCLDebugInfo100Instructions dbg_opcode = OpenCLDebugInfo100DebugScope;
816   if (GetLexicalScope() == kNoDebugScope) {
817     num_words = kDebugNoScopeNumWords;
818     dbg_opcode = OpenCLDebugInfo100DebugNoScope;
819   } else if (GetInlinedAt() == kNoInlinedAt) {
820     num_words = kDebugScopeNumWordsWithoutInlinedAt;
821   }
822   std::vector<uint32_t> operands = {
823       (num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
824       type_id,
825       result_id,
826       ext_set,
827       static_cast<uint32_t>(dbg_opcode),
828   };
829   binary->insert(binary->end(), operands.begin(), operands.end());
830   if (GetLexicalScope() != kNoDebugScope) binary->push_back(GetLexicalScope());
831   if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
832 }
833 
834 }  // namespace opt
835 }  // namespace spvtools
836